diff --git a/README.md b/README.md index 8b3459d..e5c16dd 100644 --- a/README.md +++ b/README.md @@ -58,12 +58,14 @@ require '/src/Delivery/NovaPoshtaApi2.php'; ## Создание экземпляра класса Класс по умолчанию находится в namespace `\LisDev\Delivery`. При создании экземпляра класса необходимо или использовать Full Qualified Class Name: + ```php -$np = new \LisDev\Delivery\NovaPoshtaApi2('Ваш_ключ_API_2.0'); +$np = new \LisDev\Controllers\NovaPoshtaApi2('Ваш_ключ_API_2.0'); ``` или указать используемый namespace в секции use: + ```php -use LisDev\Delivery\NovaPoshtaApi2; +use LisDev\Controllers\NovaPoshtaApi2; ... $np = new NovaPoshtaApi2('Ваш_ключ_API_2.0'); ``` diff --git a/README.ua.md b/README.ua.md index 61b3cde..d6290df 100644 --- a/README.ua.md +++ b/README.ua.md @@ -58,12 +58,14 @@ require '/src/Delivery/NovaPoshtaApi2.php'; ## Створення екземпляру класа Клас знаходиться в namespace `\LisDev\Delivery`. При створенні екземпляру класу необхідно або використовувати Full Qualified Class Name: + ```php -$np = new \LisDev\Delivery\NovaPoshtaApi2('Ваш_ключ_API_2.0'); +$np = new \LisDev\Controllers\NovaPoshtaApi2('Ваш_ключ_API_2.0'); ``` або вказати namespace що використовується у секції use: + ```php -use LisDev\Delivery\NovaPoshtaApi2; +use LisDev\Controllers\NovaPoshtaApi2; ... $np = new NovaPoshtaApi2('Ваш_ключ_API_2.0'); ``` diff --git a/composer.json b/composer.json index e6773ad..10ede50 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,9 @@ } ], "require": { - "php": ">=5.3.0" + "php": ">=8.1", + "ext-simplexml": "*", + "ext-curl": "*" }, "require-dev": { "phpunit/phpunit": "~4.4" diff --git a/src/Common/Format.php b/src/Common/Format.php new file mode 100644 index 0000000..78b311a --- /dev/null +++ b/src/Common/Format.php @@ -0,0 +1,32 @@ +format = $format; + return $this; + } + + /** + * Getter for format property. + * + * @return string + */ + public function getFormat(): string + { + return $this->format; + } +} \ No newline at end of file diff --git a/src/Common/Language.php b/src/Common/Language.php new file mode 100644 index 0000000..e3def7a --- /dev/null +++ b/src/Common/Language.php @@ -0,0 +1,34 @@ +language = $language; + return $this; + } + + /** + * Getter for language property. + * + * @return string + */ + public function getLanguage(): string + { + return $this->language; + } +} \ No newline at end of file diff --git a/src/Common/ListAreas.php b/src/Common/ListAreas.php new file mode 100644 index 0000000..198115e --- /dev/null +++ b/src/Common/ListAreas.php @@ -0,0 +1,153 @@ + [ + 'Description' => 'Вінниця', + 'DescriptionRu' => 'Винница', + 'Area' => 'Вінницька', + 'AreaRu' => 'Винницкая', + ], + '7150812b-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Дніпропетровськ', + 'DescriptionRu' => 'Днепропетровск', + 'Area' => 'Дніпропетровська', + 'AreaRu' => 'Днепропетровская', + ], + '7150812c-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Донецьк', + 'DescriptionRu' => 'Донецк', + 'Area' => 'Донецька', + 'AreaRu' => 'Донецкая', + ], + '7150812d-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Житомир', + 'DescriptionRu' => 'Житомир', + 'Area' => 'Житомирська', + 'AreaRu' => 'Житомирская', + ], + '7150812f-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Запоріжжя', + 'DescriptionRu' => 'Запорожье', + 'Area' => 'Запорізька', + 'AreaRu' => 'Запорожская', + ], + '71508130-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Івано-Франківськ', + 'DescriptionRu' => 'Ивано-Франковск', + 'Area' => 'Івано-Франківська', + 'AreaRu' => 'Ивано-Франковская', + ], + '71508131-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Київ', + 'DescriptionRu' => 'Киев', + 'Area' => 'Київська', + 'AreaRu' => 'Киевская', + ], + '71508132-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Кіровоград', + 'DescriptionRu' => 'Кировоград', + 'Area' => 'Кіровоградська', + 'AreaRu' => 'Кировоградская', + ], + '71508133-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Луганськ', + 'DescriptionRu' => 'Луганск', + 'Area' => 'Луганська', + 'AreaRu' => 'Луганская', + ], + '7150812a-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Луцьк', + 'DescriptionRu' => 'Луцк', + 'Area' => 'Волинська', + 'AreaRu' => 'Волынская', + ], + '71508134-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Львів', + 'DescriptionRu' => 'Львов', + 'Area' => 'Львівська', + 'AreaRu' => 'Львовская', + ], + '71508135-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Миколаїв', + 'DescriptionRu' => 'Николаев', + 'Area' => 'Миколаївська', + 'AreaRu' => 'Николаевская', + ], + '71508136-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Одеса', + 'DescriptionRu' => 'Одесса', + 'Area' => 'Одеська', + 'AreaRu' => 'Одесская', + ], + '71508137-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Полтава', + 'DescriptionRu' => 'Полтава', + 'Area' => 'Полтавська', + 'AreaRu' => 'Полтавская', + ], + '71508138-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Рівне', + 'DescriptionRu' => 'Ровно', + 'Area' => 'Рівненська', + 'AreaRu' => 'Ровненская', + ], + '71508139-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Суми', + 'DescriptionRu' => 'Сумы', + 'Area' => 'Сумська', + 'AreaRu' => 'Сумская', + ], + '7150813a-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Тернопіль', + 'DescriptionRu' => 'Тернополь', + 'Area' => 'Тернопільська', + 'AreaRu' => 'Тернопольская', + ], + '7150812e-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Ужгород', + 'DescriptionRu' => 'Ужгород', + 'Area' => 'Закарпатська', + 'AreaRu' => 'Закарпатская', + ], + '7150813b-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Харків', + 'DescriptionRu' => 'Харьков', + 'Area' => 'Харківська', + 'AreaRu' => 'Харьковская', + ], + '7150813c-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Херсон', + 'DescriptionRu' => 'Херсон', + 'Area' => 'Херсонська', + 'AreaRu' => 'Херсонская', + ], + '7150813d-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Хмельницький', + 'DescriptionRu' => 'Хмельницкий', + 'Area' => 'Хмельницька', + 'AreaRu' => 'Хмельницкая', + ], + '7150813e-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Черкаси', + 'DescriptionRu' => 'Черкассы', + 'Area' => 'Черкаська', + 'AreaRu' => 'Черкасская', + ], + '71508140-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Чернігів', + 'DescriptionRu' => 'Чернигов', + 'Area' => 'Чернігівська', + 'AreaRu' => 'Черниговская', + ], + '7150813f-9b87-11de-822f-000c2965ae0e' => [ + 'Description' => 'Чернівці', + 'DescriptionRu' => 'Черновцы', + 'Area' => 'Чернівецька', + 'AreaRu' => 'Черновицкая', + ], + ]; +} \ No newline at end of file diff --git a/src/Common/PrintMarkingType.php b/src/Common/PrintMarkingType.php new file mode 100644 index 0000000..664e565 --- /dev/null +++ b/src/Common/PrintMarkingType.php @@ -0,0 +1,13 @@ +throwErrors = $throwErrors; + $this + ->setKey($key) + ->setLanguage($language) + ->setConnectionType($connectionType) + ->model('Common'); + } + + /** + * Setter for key property. + * + * @param string $key NovaPoshta API key + * + * @return NovaPoshtaApi2 + */ + public function setKey($key) + { + $this->key = $key; + return $this; + } + + /** + * Getter for key property. + * + * @return string + */ + public function getKey() + { + return $this->key; + } + + + /** + * Set current model and empties method and params properties. + * + * @param string $model + * + * @return mixed + */ + public function model($model = '') + { + if (!$model) { + return $this->model; + } + + $this->model = $model; + $this->method = ''; + $this->params = array(); + return $this; + } + + /** + * Set method of current model property and empties params properties. + * + * @param string $method + * + * @return mixed + */ + public function method($method = '') + { + if (!$method) { + return $this->method; + } + + $this->method = $method; + $this->params = array(); + return $this; + } + + /** + * Set params of current method/property property. + * + * @param array $params + * + * @return mixed + */ + public function params($params) + { + $this->params = $params; + return $this; + } + + /** + * Execute request to NovaPoshta API. + * + * @return mixed + */ + public function execute() + { + return $this->request($this->model, $this->method, $this->params); + } + + + + /** + * Magic method of calling functions (uses for calling Common Model of NovaPoshta API). + * + * @param string $method Called method of Common Model + * @param array $arguments Array of params + */ + public function __call($method, $arguments) + { + $common_model_method = array( + 'getTypesOfCounterparties', + 'getBackwardDeliveryCargoTypes', + 'getCargoDescriptionList', + 'getCargoTypes', + 'getDocumentStatuses', + 'getOwnershipFormsList', + 'getPalletsList', + 'getPaymentForms', + 'getTimeIntervals', + 'getServiceTypes', + 'getTiresWheelsList', + 'getTraysList', + 'getTypesOfAlternativePayers', + 'getTypesOfPayers', + 'getTypesOfPayersForRedelivery', + ); + // Call method of Common model + if (in_array($method, $common_model_method)) { + return $this + ->model('Common') + ->method($method) + ->params(null) + ->execute(); + } + } + + /** + * getCounterparties() function of model Counterparty. + * + * @param string $counterpartyProperty Type of Counterparty (Sender|Recipient) + * @param int $page Page number + * @param string $findByString String to search + * @param string $cityRef City ID + * + * @return mixed + */ + public function getCounterparties($counterpartyProperty = 'Recipient', $page = null, $findByString = null, $cityRef = null) + { + // Any param can be skipped + $params = array(); + $params['CounterpartyProperty'] = $counterpartyProperty ? $counterpartyProperty : 'Recipient'; + $page and $params['Page'] = $page; + $findByString and $params['FindByString'] = $findByString; + $cityRef and $params['City'] = $cityRef; + return $this->request('Counterparty', 'getCounterparties', $params); + } + + /** + * cloneLoyaltyCounterpartySender() function of model Counterparty + * The counterparty will be not created immediately, you can wait a long time. + * + * @param string $cityRef City ID + * + * @return mixed + */ + public function cloneLoyaltyCounterpartySender($cityRef) + { + return $this->request('Counterparty', 'cloneLoyaltyCounterpartySender', array('CityRef' => $cityRef)); + } + + /** + * Check required fields for new InternetDocument and set defaults. + * + * @param array &$counterparty Recipient info array + */ + protected function checkInternetDocumentRecipient(array &$counterparty) + { + // Check required fields + if (!$counterparty['FirstName']) { + throw new \Exception('FirstName is required filed for recipient'); + } + // MiddleName realy is not required field, but manual says otherwise + // if ( ! $counterparty['MiddleName']) + // throw new \Exception('MiddleName is required filed for sender and recipient'); + if (!$counterparty['LastName']) { + throw new \Exception('LastName is required filed for recipient'); + } + if (!$counterparty['Phone']) { + throw new \Exception('Phone is required filed for recipient'); + } + if (!($counterparty['City'] or $counterparty['CityRef'])) { + throw new \Exception('City is required filed for recipient'); + } + if (!($counterparty['Region'] or $counterparty['CityRef'])) { + throw new \Exception('Region is required filed for recipient'); + } + + // Set defaults + if (empty($counterparty['CounterpartyType'])) { + $counterparty['CounterpartyType'] = 'PrivatePerson'; + } + } + + /** + * Check required params for new InternetDocument and set defaults. + * + * @param array &$params + */ + protected function checkInternetDocumentParams(array &$params) + { + if (!$params['Description']) { + throw new \Exception('Description is required filed for new Internet document'); + } + if (!$params['Weight']) { + throw new \Exception('Weight is required filed for new Internet document'); + } + if (!$params['Cost']) { + throw new \Exception('Cost is required filed for new Internet document'); + } + empty($params['DateTime']) and $params['DateTime'] = date('d.m.Y'); + empty($params['ServiceType']) and $params['ServiceType'] = 'WarehouseWarehouse'; + empty($params['PaymentMethod']) and $params['PaymentMethod'] = 'Cash'; + empty($params['PayerType']) and $params['PayerType'] = 'Recipient'; + empty($params['SeatsAmount']) and $params['SeatsAmount'] = '1'; + empty($params['CargoType']) and $params['CargoType'] = 'Cargo'; + if($params['CargoType'] != 'Documents') { + empty($params['VolumeGeneral']) and $params['VolumeGeneral'] = '0.0004'; + empty($params['VolumeWeight']) and $params['VolumeWeight'] = $params['Weight']; + } + } + + /** + * Create Internet Document by. + * + * @param array $sender Sender info. + * Required: + * For existing sender: + * 'Description' => String (Full name i.e.), 'City' => String (City name) + * For creating: + * 'FirstName' => String, 'MiddleName' => String, + * 'LastName' => String, 'Phone' => '000xxxxxxx', 'City' => String (City name), 'Region' => String (Region name), + * 'Warehouse' => String (Description from getWarehouses)) + * @param array $recipient Recipient info, same like $sender param + * @param array $params Additional params of Internet Document + * Required: + * 'Description' => String, 'Weight' => Float, 'Cost' => Float + * Recommended: + * 'VolumeGeneral' => Float (default = 0.004), 'SeatsAmount' => Int (default = 1), + * 'PayerType' => (Sender|Recipient - default), 'PaymentMethod' => (NonCash|Cash - default) + * 'ServiceType' => (DoorsDoors|DoorsWarehouse|WarehouseDoors|WarehouseWarehouse - default) + * 'CargoType' => String + * @return mixed + */ + public function newInternetDocument($sender, $recipient, $params) + { + // Check for required params and set defaults + $this->checkInternetDocumentRecipient($recipient); + $this->checkInternetDocumentParams($params); + if (empty($sender['CitySender'])) { + $senderCity = $this->getCity($sender['City'], $sender['Region'], $sender['Warehouse']); + $sender['CitySender'] = $senderCity['data'][0]['Ref']; + } + $sender['CityRef'] = $sender['CitySender']; + if (empty($sender['SenderAddress']) and $sender['CitySender'] and $sender['Warehouse']) { + $senderWarehouse = $this->getWarehouse($sender['CitySender'], $sender['Warehouse']); + $sender['SenderAddress'] = $senderWarehouse['data'][0]['Ref']; + } + if (empty($sender['Sender'])) { + $sender['CounterpartyProperty'] = 'Sender'; + $fullName = trim($sender['LastName'].' '.$sender['FirstName'].' '.$sender['MiddleName']); + // Set full name to Description if is not set + if (empty($sender['Description'])) { + $sender['Description'] = $fullName; + } + // Check for existing sender + $senderCounterpartyExisting = $this->getCounterparties('Sender', 1, $fullName, $sender['CityRef']); + // Copy user to the selected city if user doesn't exists there + if (isset($senderCounterpartyExisting['data'][0]['Ref'])) { + // Counterparty exists + $sender['Sender'] = $senderCounterpartyExisting['data'][0]['Ref']; + $contactSender = $this->getCounterpartyContactPersons($sender['Sender']); + $sender['ContactSender'] = $contactSender['data'][0]['Ref']; + $sender['SendersPhone'] = isset($sender['Phone']) ? $sender['Phone'] : $contactSender['data'][0]['Phones']; + } + } + + // Prepare recipient data + $recipient['CounterpartyProperty'] = 'Recipient'; + $recipient['RecipientsPhone'] = $recipient['Phone']; + if (empty($recipient['CityRecipient'])) { + $recipientCity = $this->getCity($recipient['City'], $recipient['Region'], $recipient['Warehouse']); + $recipient['CityRecipient'] = $recipientCity['data'][0]['Ref']; + } + $recipient['CityRef'] = $recipient['CityRecipient']; + if (empty($recipient['RecipientAddress'])) { + $recipientWarehouse = $this->getWarehouse($recipient['CityRecipient'], $recipient['Warehouse']); + $recipient['RecipientAddress'] = $recipientWarehouse['data'][0]['Ref']; + } + if (empty($recipient['Recipient'])) { + $recipientCounterparty = $this->model('Counterparty')->save($recipient); + $recipient['Recipient'] = $recipientCounterparty['data'][0]['Ref']; + $recipient['ContactRecipient'] = $recipientCounterparty['data'][0]['ContactPerson']['data'][0]['Ref']; + } + // Full params is merge of arrays $sender, $recipient, $params + $paramsInternetDocument = array_merge($sender, $recipient, $params); + // Creating new Internet Document + return $this->model('InternetDocument')->save($paramsInternetDocument); + } +} diff --git a/src/Delivery/NovaPoshtaApi2Areas.php b/src/Controllers/Api/v1/NovaPoshtaApi2Areas.php similarity index 100% rename from src/Delivery/NovaPoshtaApi2Areas.php rename to src/Controllers/Api/v1/NovaPoshtaApi2Areas.php diff --git a/src/Controllers/Api/v1/NovaPoshtaApiClient.php b/src/Controllers/Api/v1/NovaPoshtaApiClient.php new file mode 100644 index 0000000..b226b63 --- /dev/null +++ b/src/Controllers/Api/v1/NovaPoshtaApiClient.php @@ -0,0 +1,120 @@ +outputService = new OutputService(); + $this->connectionService = new ConnectionService(); + $this->preparationDataService = new PreparationDataService(); + $this->languageService = new Language(); + $this->formatService = new Format(); + } + + /** + * @throws \Exception + */ + public function request(string $model, string $method, array $params = null) + { + // Get required URL + $url = 'xml' == $this->formatService->getFormat() + ? self::API_URI.'/xml/' + : self::API_URI.'/json/'; + + $data = array( + 'apiKey' => $this->key, + 'modelName' => $model, + 'calledMethod' => $method, + 'language' => $this->languageService->getLanguage(), + 'methodProperties' => $params, + ); + $result = array(); + // Convert data to neccessary format + $post = 'xml' == $this->formatService->getFormat() + ? $this->outputService->array2xml($data) + : json_encode($data); + + if ('curl' == $this->connectionService->getConnectionType()) { + $ch = curl_init($url); + if (is_resource($ch)) { + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: '.('xml' == $this->format ? 'text/xml' : 'application/json'))); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($ch, CURLOPT_POSTFIELDS, $post); + + if ($this->timeout > 0) { + curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->timeout); + } + + $result = curl_exec($ch); + curl_close($ch); + } + } else { + $httpOptions = array( + 'method' => 'POST', + 'header' => "Content-type: application/x-www-form-urlencoded;\r\n", + 'content' => $post, + ); + + if ($this->timeout > 0) { + $httpOptions['timeout'] = $this->timeout; + } + + $result = file_get_contents($url, false, stream_context_create(array( + 'http' => $httpOptions, + ))); + } + + return $this->preparationDataService->prepare($result); + } + + /** + * @param int $timeout + * + * @return $this + */ + public function setTimeout(int $timeout): NovaPoshtaApiClient + { + $this->timeout = (int)$timeout; + + return $this; + } + + /** + * @return int + */ + public function getTimeout(): int + { + return $this->timeout; + } +} \ No newline at end of file diff --git a/src/Delivery/NovaPoshtaApi2.php b/src/Delivery/NovaPoshtaApi2.php deleted file mode 100644 index d56035d..0000000 --- a/src/Delivery/NovaPoshtaApi2.php +++ /dev/null @@ -1,1115 +0,0 @@ -throwErrors = $throwErrors; - $this - ->setKey($key) - ->setLanguage($language) - ->setConnectionType($connectionType) - ->model('Common'); - } - - /** - * Setter for key property. - * - * @param string $key NovaPoshta API key - * - * @return NovaPoshtaApi2 - */ - public function setKey($key) - { - $this->key = $key; - return $this; - } - - /** - * Getter for key property. - * - * @return string - */ - public function getKey() - { - return $this->key; - } - - /** - * Setter for $connectionType property. - * - * @param string $connectionType Connection type (curl | file_get_contents) - * - * @return $this - */ - public function setConnectionType($connectionType) - { - $this->connectionType = $connectionType; - return $this; - } - - /** - * Getter for $connectionType property. - * - * @return string - */ - public function getConnectionType() - { - return $this->connectionType; - } - - /** - * @param int $timeout - * - * @return $this - */ - public function setTimeout($timeout) - { - $this->timeout = (int)$timeout; - - return $this; - } - - /** - * @return int - */ - public function getTimeout() - { - return $this->timeout; - } - - /** - * Setter for language property. - * - * @param string $language - * - * @return NovaPoshtaApi2 - */ - public function setLanguage($language) - { - $this->language = $language; - return $this; - } - - /** - * Getter for language property. - * - * @return string - */ - public function getLanguage() - { - return $this->language; - } - - /** - * Setter for format property. - * - * @param string $format Format of returned data by methods (json, xml, array) - * - * @return NovaPoshtaApi2 - */ - public function setFormat($format) - { - $this->format = $format; - return $this; - } - - /** - * Getter for format property. - * - * @return string - */ - public function getFormat() - { - return $this->format; - } - - /** - * Prepare data before return it. - * - * @param string|array $data - * - * @return mixed - */ - private function prepare($data) - { - // Returns array - if ('array' == $this->format) { - $result = is_array($data) - ? $data - : json_decode($data, true); - // If error exists, throw Exception - if ($this->throwErrors and array_key_exists('errors', $result) and $result['errors']) { - throw new \Exception(is_array($result['errors']) ? implode("\n", $result['errors']) : $result['errors']); - } - return $result; - } - // Returns json or xml document - return $data; - } - - /** - * Converts array to xml. - * - * @param array $array - * @param \SimpleXMLElement|bool $xml - */ - private function array2xml(array $array, $xml = false) - { - (false === $xml) and $xml = new \SimpleXMLElement(''); - foreach ($array as $key => $value) { - if (is_numeric($key)) { - $key = 'item'; - } - if (is_array($value)) { - $this->array2xml($value, $xml->addChild($key)); - } else { - $xml->addChild($key, $value); - } - } - return $xml->asXML(); - } - - /** - * Make request to NovaPoshta API. - * - * @param string $model Model name - * @param string $method Method name - * @param array $params Required params - */ - private function request($model, $method, $params = null) - { - // Get required URL - $url = 'xml' == $this->format - ? self::API_URI.'/xml/' - : self::API_URI.'/json/'; - - $data = array( - 'apiKey' => $this->key, - 'modelName' => $model, - 'calledMethod' => $method, - 'language' => $this->language, - 'methodProperties' => $params, - ); - $result = array(); - // Convert data to neccessary format - $post = 'xml' == $this->format - ? $this->array2xml($data) - : json_encode($data); - - if ('curl' == $this->getConnectionType()) { - $ch = curl_init($url); - if (is_resource($ch)) { - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: '.('xml' == $this->format ? 'text/xml' : 'application/json'))); - curl_setopt($ch, CURLOPT_HEADER, 0); - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); - curl_setopt($ch, CURLOPT_POSTFIELDS, $post); - - if ($this->timeout > 0) { - curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); - curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->timeout); - } - - $result = curl_exec($ch); - curl_close($ch); - } - } else { - $httpOptions = array( - 'method' => 'POST', - 'header' => "Content-type: application/x-www-form-urlencoded;\r\n", - 'content' => $post, - ); - - if ($this->timeout > 0) { - $httpOptions['timeout'] = $this->timeout; - } - - $result = file_get_contents($url, false, stream_context_create(array( - 'http' => $httpOptions, - ))); - } - - return $this->prepare($result); - } - - /** - * Set current model and empties method and params properties. - * - * @param string $model - * - * @return mixed - */ - public function model($model = '') - { - if (!$model) { - return $this->model; - } - - $this->model = $model; - $this->method = ''; - $this->params = array(); - return $this; - } - - /** - * Set method of current model property and empties params properties. - * - * @param string $method - * - * @return mixed - */ - public function method($method = '') - { - if (!$method) { - return $this->method; - } - - $this->method = $method; - $this->params = array(); - return $this; - } - - /** - * Set params of current method/property property. - * - * @param array $params - * - * @return mixed - */ - public function params($params) - { - $this->params = $params; - return $this; - } - - /** - * Execute request to NovaPoshta API. - * - * @return mixed - */ - public function execute() - { - return $this->request($this->model, $this->method, $this->params); - } - - /** - * Get tracking information by track number. - * - * @param string $track Track number - * - * @return mixed - */ - public function documentsTracking($track) - { - $params = array('Documents' => array(array('DocumentNumber' => $track))); - - return $this->request('TrackingDocument', 'getStatusDocuments', $params); - } - - /** - * Get cities of company NovaPoshta. - * - * @param int $page Num of page - * @param string $findByString Find city by russian or ukrainian word - * @param string $ref ID of city - * - * @return mixed - */ - public function getCities($page = 0, $findByString = '', $ref = '') - { - return $this->request('Address', 'getCities', array( - 'Page' => $page, - 'FindByString' => $findByString, - 'Ref' => $ref, - )); - } - - /** - * Get warehouses by city. - * - * @param string $cityRef ID of city - * @param int $page - * - * @return mixed - */ - public function getWarehouses($cityRef, $page = 0) - { - return $this->request('Address', 'getWarehouses', array( - 'CityRef' => $cityRef, - 'Page' => $page, - )); - } - - /** - * Get warehouse types. - * - * @return mixed - */ - public function getWarehouseTypes() - { - return $this->request('Address', 'getWarehouseTypes'); - } - - /** - * Get 5 nearest warehouses by array of strings. - * - * @param array $searchStringArray - * - * @return mixed - */ - public function findNearestWarehouse($searchStringArray) - { - $searchStringArray = (array) $searchStringArray; - return $this->request('Address', 'findNearestWarehouse', array( - 'SearchStringArray' => $searchStringArray, - )); - } - - /** - * Get one warehouse by city name and warehouse's description. - * - * @param string $cityRef ID of city - * @param string $description Description like in getted by getWarehouses() - * - * @return mixed - */ - public function getWarehouse($cityRef, $description = '') - { - $warehouses = $this->getWarehouses($cityRef); - $error = array(); - $data = array(); - if (is_array($warehouses['data'])) { - $data = $warehouses['data'][0]; - if (count($warehouses['data']) > 1 && $description) { - foreach ($warehouses['data'] as $warehouse) { - if (false !== mb_stripos($warehouse['Description'], $description) - or false !== mb_stripos($warehouse['DescriptionRu'], $description)) { - $data = $warehouse; - break; - } - } - } - } - // Error - (!$data) and $error = 'Warehouse was not found'; - // Return data in same format like NovaPoshta API - return $this->prepare( - array( - 'success' => empty($error), - 'data' => array($data), - 'errors' => (array) $error, - 'warnings' => array(), - 'info' => array(), - ) - ); - } - - /** - * Get streets list by city and/or search string. - * - * @param string $cityRef ID of city - * @param string $findByString - * @param int $page - * - * @return mixed - */ - public function getStreet($cityRef, $findByString = '', $page = 0) - { - return $this->request('Address', 'getStreet', array( - 'FindByString' => $findByString, - 'CityRef' => $cityRef, - 'Page' => $page, - )); - } - - /** - * Find current area in list of areas. - * - * @param array $areas List of arias, getted from file - * @param string $findByString Area name - * @param string $ref Area Ref ID - * - * @return array - */ - protected function findArea(array $areas, $findByString = '', $ref = '') - { - $data = array(); - if (!$findByString and !$ref) { - return $data; - } - // Try to find current region - foreach ($areas as $key => $area) { - // Is current area found by string or by key - $found = $findByString - ? ((false !== mb_stripos($area['Description'], $findByString)) - or (false !== mb_stripos($area['DescriptionRu'], $findByString)) - or (false !== mb_stripos($area['Area'], $findByString)) - or (false !== mb_stripos($area['AreaRu'], $findByString))) - : ($key == $ref); - if ($found) { - $area['Ref'] = $key; - $data[] = $area; - break; - } - } - return $data; - } - - /** - * Get area by name or by ID. - * - * @param string $findByString Find area by russian or ukrainian word - * @param string $ref Get area by ID - * - * @return array - */ - public function getArea($findByString = '', $ref = '') - { - // Load areas list from file - empty($this->areas) and $this->areas = (include dirname(__FILE__).'/NovaPoshtaApi2Areas.php'); - $data = $this->findArea($this->areas, $findByString, $ref); - // Error - $error = array(); - empty($data) and $error = array('Area was not found'); - // Return data in same format like NovaPoshta API - return $this->prepare( - array( - 'success' => empty($error), - 'data' => $data, - 'errors' => $error, - 'warnings' => array(), - 'info' => array(), - ) - ); - } - - /** - * Get areas list by city and/or search string. - * - * @param string $ref ID of area - * @param int $page - * - * @return mixed - */ - public function getAreas($ref = '', $page = 0) - { - return $this->request('Address', 'getAreas', array( - 'Ref' => $ref, - 'Page' => $page, - )); - } - - /** - * Find city from list by name of region. - * - * @param array $cities Array from query getCities to NovaPoshta - * @param string $areaName - * - * @return array - */ - protected function findCityByRegion($cities, $areaName) - { - $data = array(); - $areaRef = ''; - // Get region id - $area = $this->getArea($areaName); - $area['success'] and $areaRef = $area['data'][0]['Ref']; - if ($areaRef and is_array($cities['data'])) { - foreach ($cities['data'] as $city) { - if ($city['Area'] == $areaRef) { - $data[] = $city; - } - } - } - return $data; - } - - /** - * Get city by name and region (if it needs). - * - * @param string $cityName City's name - * @param string $areaName Region's name - * @param string $warehouseDescription Warehouse description to identiry needed city (if it more than 1 in the area) - * - * @return array Cities's data Can be returned more than 1 city with the same name - */ - public function getCity($cityName, $areaName = '', $warehouseDescription = '') - { - // Get cities by name - $cities = $this->getCities(0, $cityName); - $data = array(); - if (is_array($cities) && is_array($cities['data'])) { - // If cities more then one, calculate current by area name - $data = (count($cities['data']) > 1) - ? $this->findCityByRegion($cities, $areaName) - : array($cities['data'][0]); - } - // Try to identify city by one of warehouses descriptions - if (count($data) > 1 && $warehouseDescription) { - foreach ($data as $cityData) { - $warehouseData = $this->getWarehouse($cityData['Ref'], $warehouseDescription); - $warehouseDescriptions = array( - $warehouseData['data'][0]['Description'], - $warehouseData['data'][0]['DescriptionRu'] - ); - if (in_array($warehouseDescription, $warehouseDescriptions)) { - $data = array($cityData); - break; - } - } - } - // Error - $error = array(); - (!$data) and $error = array('City was not found'); - // Return data in same format like NovaPoshta API - return $this->prepare( - array( - 'success' => empty($error), - 'data' => $data, - 'errors' => $error, - 'warnings' => array(), - 'info' => array(), - ) - ); - } - - /** - * Magic method of calling functions (uses for calling Common Model of NovaPoshta API). - * - * @param string $method Called method of Common Model - * @param array $arguments Array of params - */ - public function __call($method, $arguments) - { - $common_model_method = array( - 'getTypesOfCounterparties', - 'getBackwardDeliveryCargoTypes', - 'getCargoDescriptionList', - 'getCargoTypes', - 'getDocumentStatuses', - 'getOwnershipFormsList', - 'getPalletsList', - 'getPaymentForms', - 'getTimeIntervals', - 'getServiceTypes', - 'getTiresWheelsList', - 'getTraysList', - 'getTypesOfAlternativePayers', - 'getTypesOfPayers', - 'getTypesOfPayersForRedelivery', - ); - // Call method of Common model - if (in_array($method, $common_model_method)) { - return $this - ->model('Common') - ->method($method) - ->params(null) - ->execute(); - } - } - - /** - * Delete method of current model. - * - * @param array $params - * - * @return mixed - */ - public function delete($params) - { - return $this->request($this->model, 'delete', $params); - } - - /** - * Update method of current model - * Required params: - * For ContactPerson model: Ref, CounterpartyRef, FirstName (ukr), MiddleName, LastName, Phone (format 0xxxxxxxxx) - * For Counterparty model: Ref, CounterpartyProperty (Recipient|Sender), CityRef, CounterpartyType (Organization, PrivatePerson), - * FirstName (or name of organization), MiddleName, LastName, Phone (0xxxxxxxxx), OwnershipForm (if Organization). - * - * @param array $params - * - * @return mixed - */ - public function update($params) - { - return $this->request($this->model, 'update', $params); - } - - /** - * Save method of current model - * Required params: - * For ContactPerson model (only for Organization API key, for PrivatePerson error will be returned): - * CounterpartyRef, FirstName (ukr), MiddleName, LastName, Phone (format 0xxxxxxxxx) - * For Counterparty model: - * CounterpartyProperty (Recipient|Sender), CityRef, CounterpartyType (Organization, PrivatePerson), - * FirstName (or name of organization), MiddleName, LastName, Phone (0xxxxxxxxx), OwnershipForm (if Organization). - * - * @param array $params - * - * @return mixed - */ - public function save($params) - { - return $this->request($this->model, 'save', $params); - } - - /** - * getCounterparties() function of model Counterparty. - * - * @param string $counterpartyProperty Type of Counterparty (Sender|Recipient) - * @param int $page Page number - * @param string $findByString String to search - * @param string $cityRef City ID - * - * @return mixed - */ - public function getCounterparties($counterpartyProperty = 'Recipient', $page = null, $findByString = null, $cityRef = null) - { - // Any param can be skipped - $params = array(); - $params['CounterpartyProperty'] = $counterpartyProperty ? $counterpartyProperty : 'Recipient'; - $page and $params['Page'] = $page; - $findByString and $params['FindByString'] = $findByString; - $cityRef and $params['City'] = $cityRef; - return $this->request('Counterparty', 'getCounterparties', $params); - } - - /** - * cloneLoyaltyCounterpartySender() function of model Counterparty - * The counterparty will be not created immediately, you can wait a long time. - * - * @param string $cityRef City ID - * - * @return mixed - */ - public function cloneLoyaltyCounterpartySender($cityRef) - { - return $this->request('Counterparty', 'cloneLoyaltyCounterpartySender', array('CityRef' => $cityRef)); - } - - /** - * getCounterpartyContactPersons() function of model Counterparty. - * - * @param string $ref Counterparty ref - * - * @return mixed - */ - public function getCounterpartyContactPersons($ref) - { - return $this->request('Counterparty', 'getCounterpartyContactPersons', array('Ref' => $ref)); - } - - /** - * getCounterpartyAddresses() function of model Counterparty. - * - * @param string $ref Counterparty ref - * @param int $page - * - * @return mixed - */ - public function getCounterpartyAddresses($ref, $page = 0) - { - return $this->request('Counterparty', 'getCounterpartyAddresses', array('Ref' => $ref, 'Page' => $page)); - } - - /** - * getCounterpartyOptions() function of model Counterparty. - * - * @param string $ref Counterparty ref - * - * @return mixed - */ - public function getCounterpartyOptions($ref) - { - return $this->request('Counterparty', 'getCounterpartyOptions', array('Ref' => $ref)); - } - - /** - * getCounterpartyByEDRPOU() function of model Counterparty. - * - * @param string $edrpou EDRPOU code - * @param string $cityRef City ID - * - * @return mixed - */ - public function getCounterpartyByEDRPOU($edrpou, $cityRef) - { - return $this->request('Counterparty', 'getCounterpartyByEDRPOU', array('EDRPOU' => $edrpou, 'cityRef' => $cityRef)); - } - - /** - * Get price of delivery between two cities. - * - * @param string $citySender City ID - * @param string $cityRecipient City ID - * @param string $serviceType (DoorsDoors|DoorsWarehouse|WarehouseWarehouse|WarehouseDoors) - * @param float $weight - * @param float $cost - * - * @return mixed - */ - public function getDocumentPrice($citySender, $cityRecipient, $serviceType, $weight, $cost) - { - return $this->request('InternetDocument', 'getDocumentPrice', array( - 'CitySender' => $citySender, - 'CityRecipient' => $cityRecipient, - 'ServiceType' => $serviceType, - 'Weight' => $weight, - 'Cost' => $cost, - )); - } - - /** - * Get approximately date of delivery between two cities. - * - * @param string $citySender City ID - * @param string $cityRecipient City ID - * @param string $serviceType (DoorsDoors|DoorsWarehouse|WarehouseWarehouse|WarehouseDoors) - * @param string $dateTime Date of shipping - * - * @return mixed - */ - public function getDocumentDeliveryDate($citySender, $cityRecipient, $serviceType, $dateTime) - { - return $this->request('InternetDocument', 'getDocumentDeliveryDate', array( - 'CitySender' => $citySender, - 'CityRecipient' => $cityRecipient, - 'ServiceType' => $serviceType, - 'DateTime' => $dateTime, - )); - } - - /** - * Get documents list. - * - * @param array $params List of params - * Not required keys: - * 'Ref', 'IntDocNumber', 'InfoRegClientBarcodes', 'DeliveryDateTime', 'RecipientDateTime', - * 'CreateTime', 'SenderRef', 'RecipientRef', 'WeightFrom', 'WeightTo', - * 'CostFrom', 'CostTo', 'SeatsAmountFrom', 'SeatsAmountTo', 'CostOnSiteFrom', - * 'CostOnSiteTo', 'StateIds', 'ScanSheetRef', 'DateTime', 'DateTimeFrom', - * 'RecipientDateTime', 'isAfterpayment', 'Page', 'OrderField => - * [ - * IntDocNumber, DateTime, Weight, Cost, SeatsAmount, CostOnSite, - * CreateTime, EstimatedDeliveryDate, StateId, InfoRegClientBarcodes, RecipientDateTime - * ], - * 'OrderDirection' => [DESC, ASC], 'ScanSheetRef' - * - * @return mixed - */ - public function getDocumentList($params = null) - { - return $this->request('InternetDocument', 'getDocumentList', $params ? $params : null); - } - - /** - * Get document info by ID. - * - * @param string $ref Document ID - * - * @return mixed - */ - public function getDocument($ref) - { - return $this->request('InternetDocument', 'getDocument', array( - 'Ref' => $ref, - )); - } - - /** - * Generetes report by Document refs. - * - * @param array $params Params like getDocumentList with requiered keys - * 'Type' => [xls, csv], 'DocumentRefs' => [] - * - * @return mixed - */ - public function generateReport($params) - { - return $this->request('InternetDocument', 'generateReport', $params); - } - - /** - * Check required fields for new InternetDocument and set defaults. - * - * @param array &$counterparty Recipient info array - */ - protected function checkInternetDocumentRecipient(array &$counterparty) - { - // Check required fields - if (!$counterparty['FirstName']) { - throw new \Exception('FirstName is required filed for recipient'); - } - // MiddleName realy is not required field, but manual says otherwise - // if ( ! $counterparty['MiddleName']) - // throw new \Exception('MiddleName is required filed for sender and recipient'); - if (!$counterparty['LastName']) { - throw new \Exception('LastName is required filed for recipient'); - } - if (!$counterparty['Phone']) { - throw new \Exception('Phone is required filed for recipient'); - } - if (!($counterparty['City'] or $counterparty['CityRef'])) { - throw new \Exception('City is required filed for recipient'); - } - if (!($counterparty['Region'] or $counterparty['CityRef'])) { - throw new \Exception('Region is required filed for recipient'); - } - - // Set defaults - if (empty($counterparty['CounterpartyType'])) { - $counterparty['CounterpartyType'] = 'PrivatePerson'; - } - } - - /** - * Check required params for new InternetDocument and set defaults. - * - * @param array &$params - */ - protected function checkInternetDocumentParams(array &$params) - { - if (!$params['Description']) { - throw new \Exception('Description is required filed for new Internet document'); - } - if (!$params['Weight']) { - throw new \Exception('Weight is required filed for new Internet document'); - } - if (!$params['Cost']) { - throw new \Exception('Cost is required filed for new Internet document'); - } - empty($params['DateTime']) and $params['DateTime'] = date('d.m.Y'); - empty($params['ServiceType']) and $params['ServiceType'] = 'WarehouseWarehouse'; - empty($params['PaymentMethod']) and $params['PaymentMethod'] = 'Cash'; - empty($params['PayerType']) and $params['PayerType'] = 'Recipient'; - empty($params['SeatsAmount']) and $params['SeatsAmount'] = '1'; - empty($params['CargoType']) and $params['CargoType'] = 'Cargo'; - if($params['CargoType'] != 'Documents') { - empty($params['VolumeGeneral']) and $params['VolumeGeneral'] = '0.0004'; - empty($params['VolumeWeight']) and $params['VolumeWeight'] = $params['Weight']; - } - } - - /** - * Create Internet Document by. - * - * @param array $sender Sender info. - * Required: - * For existing sender: - * 'Description' => String (Full name i.e.), 'City' => String (City name) - * For creating: - * 'FirstName' => String, 'MiddleName' => String, - * 'LastName' => String, 'Phone' => '000xxxxxxx', 'City' => String (City name), 'Region' => String (Region name), - * 'Warehouse' => String (Description from getWarehouses)) - * @param array $recipient Recipient info, same like $sender param - * @param array $params Additional params of Internet Document - * Required: - * 'Description' => String, 'Weight' => Float, 'Cost' => Float - * Recommended: - * 'VolumeGeneral' => Float (default = 0.004), 'SeatsAmount' => Int (default = 1), - * 'PayerType' => (Sender|Recipient - default), 'PaymentMethod' => (NonCash|Cash - default) - * 'ServiceType' => (DoorsDoors|DoorsWarehouse|WarehouseDoors|WarehouseWarehouse - default) - * 'CargoType' => String - * @return mixed - */ - public function newInternetDocument($sender, $recipient, $params) - { - // Check for required params and set defaults - $this->checkInternetDocumentRecipient($recipient); - $this->checkInternetDocumentParams($params); - if (empty($sender['CitySender'])) { - $senderCity = $this->getCity($sender['City'], $sender['Region'], $sender['Warehouse']); - $sender['CitySender'] = $senderCity['data'][0]['Ref']; - } - $sender['CityRef'] = $sender['CitySender']; - if (empty($sender['SenderAddress']) and $sender['CitySender'] and $sender['Warehouse']) { - $senderWarehouse = $this->getWarehouse($sender['CitySender'], $sender['Warehouse']); - $sender['SenderAddress'] = $senderWarehouse['data'][0]['Ref']; - } - if (empty($sender['Sender'])) { - $sender['CounterpartyProperty'] = 'Sender'; - $fullName = trim($sender['LastName'].' '.$sender['FirstName'].' '.$sender['MiddleName']); - // Set full name to Description if is not set - if (empty($sender['Description'])) { - $sender['Description'] = $fullName; - } - // Check for existing sender - $senderCounterpartyExisting = $this->getCounterparties('Sender', 1, $fullName, $sender['CityRef']); - // Copy user to the selected city if user doesn't exists there - if (isset($senderCounterpartyExisting['data'][0]['Ref'])) { - // Counterparty exists - $sender['Sender'] = $senderCounterpartyExisting['data'][0]['Ref']; - $contactSender = $this->getCounterpartyContactPersons($sender['Sender']); - $sender['ContactSender'] = $contactSender['data'][0]['Ref']; - $sender['SendersPhone'] = isset($sender['Phone']) ? $sender['Phone'] : $contactSender['data'][0]['Phones']; - } - } - - // Prepare recipient data - $recipient['CounterpartyProperty'] = 'Recipient'; - $recipient['RecipientsPhone'] = $recipient['Phone']; - if (empty($recipient['CityRecipient'])) { - $recipientCity = $this->getCity($recipient['City'], $recipient['Region'], $recipient['Warehouse']); - $recipient['CityRecipient'] = $recipientCity['data'][0]['Ref']; - } - $recipient['CityRef'] = $recipient['CityRecipient']; - if (empty($recipient['RecipientAddress'])) { - $recipientWarehouse = $this->getWarehouse($recipient['CityRecipient'], $recipient['Warehouse']); - $recipient['RecipientAddress'] = $recipientWarehouse['data'][0]['Ref']; - } - if (empty($recipient['Recipient'])) { - $recipientCounterparty = $this->model('Counterparty')->save($recipient); - $recipient['Recipient'] = $recipientCounterparty['data'][0]['Ref']; - $recipient['ContactRecipient'] = $recipientCounterparty['data'][0]['ContactPerson']['data'][0]['Ref']; - } - // Full params is merge of arrays $sender, $recipient, $params - $paramsInternetDocument = array_merge($sender, $recipient, $params); - // Creating new Internet Document - return $this->model('InternetDocument')->save($paramsInternetDocument); - } - - /** - * Get only link on internet document for printing. - * - * @param string $method Called method of NovaPoshta API - * @param array $documentRefs Array of Documents IDs - * @param string $type (html_link|pdf_link) - * - * @return mixed - */ - protected function printGetLink($method, $documentRefs, $type) - { - $data = 'https://my.novaposhta.ua/orders/'.$method.'/orders[]/'.implode(',', $documentRefs) - .'/type/'.str_replace('_link', '', $type) - .'/apiKey/'.$this->key; - // Return data in same format like NovaPoshta API - return $this->prepare( - array( - 'success' => true, - 'data' => array($data), - 'errors' => array(), - 'warnings' => array(), - 'info' => array(), - ) - ); - } - - /** - * printDocument method of InternetDocument model. - * - * @param array|string $documentRefs Array of Documents IDs - * @param string $type (pdf|html|html_link|pdf_link) - * - * @return mixed - */ - public function printDocument($documentRefs, $type = 'html') - { - $documentRefs = (array) $documentRefs; - // If needs link - if ('html_link' == $type or 'pdf_link' == $type) { - return $this->printGetLink('printDocument', $documentRefs, $type); - } - // If needs data - return $this->request('InternetDocument', 'printDocument', array('DocumentRefs' => $documentRefs, 'Type' => $type)); - } - - /** - * printMarkings method of InternetDocument model. - * - * @param array|string $documentRefs Array of Documents IDs - * @param string $type (pdf|new_pdf|new_html|old_html|html_link|pdf_link) - * - * @return mixed - */ - public function printMarkings($documentRefs, $type = 'new_html', $size = '85x85') - { - $documentRefs = (array) $documentRefs; - $documentSize = $size === '85x85' ? '85x85' : '100x100'; - $method = 'printMarking'.$documentSize; - // If needs link - if ('html_link' == $type or 'pdf_link' == $type) { - return $this->printGetLink($method, $documentRefs, $type); - } - // If needs data - return $this->request('InternetDocument', $method, array('DocumentRefs' => $documentRefs, 'Type' => $type)); - } -} diff --git a/src/Exception/ArgumentException.php b/src/Exception/ArgumentException.php new file mode 100644 index 0000000..b4373a0 --- /dev/null +++ b/src/Exception/ArgumentException.php @@ -0,0 +1,8 @@ +request($this->model, 'save', $params); + } + + /** + * Update method of current model + * Required params: + * For ContactPerson model: Ref, CounterpartyRef, FirstName (ukr), MiddleName, LastName, Phone (format 0xxxxxxxxx) + * For Counterparty model: Ref, CounterpartyProperty (Recipient|Sender), CityRef, CounterpartyType (Organization, PrivatePerson), + * FirstName (or name of organization), MiddleName, LastName, Phone (0xxxxxxxxx), OwnershipForm (if Organization). + * + * @param array $params + * + * @return mixed + */ + public function update(array $params): Model + { + return $this->request($this->model, 'update', $params); + } + + /** + * Delete method of current model. + * + * @param array $params + * + * @return mixed + */ + public function delete(array $params): string + { + return $this->request($this->model, 'delete', $params); + } +} \ No newline at end of file diff --git a/src/Models/TrackingDocument.php b/src/Models/TrackingDocument.php new file mode 100644 index 0000000..196e725 --- /dev/null +++ b/src/Models/TrackingDocument.php @@ -0,0 +1,8 @@ +preparationDataService = new PreparationDataService(); + $this->novaPoshtaApiClient = new NovaPoshtaApiClient(); + } + + /** + * Get cities of company NovaPoshta. + * + * @param int $page Num of page + * @param string $findByString Find city by russian or ukrainian word + * @param string $ref ID of city + * + * @return mixed + */ + public function getCities($page = 0, $findByString = '', $ref = '') + { + return $this->novaPoshtaApiClient->request('Address', 'getCities', array( + 'Page' => $page, + 'FindByString' => $findByString, + 'Ref' => $ref, + )); + } + + /** + * Get warehouses by city. + * + * @param string $cityRef ID of city + * @param int $page + * + * @return mixed + */ + public function getWarehouses($cityRef, $page = 0) + { + return $this->novaPoshtaApiClient->request('Address', 'getWarehouses', array( + 'CityRef' => $cityRef, + 'Page' => $page, + )); + } + + /** + * Get warehouse types. + * + * @return mixed + */ + public function getWarehouseTypes() + { + return $this->novaPoshtaApiClient->request('Address', 'getWarehouseTypes'); + } + + /** + * Get 5 nearest warehouses by array of strings. + * + * @param array $searchStringArray + * + * @return mixed + */ + public function findNearestWarehouse(array $searchStringArray) + { + $searchStringArray = $searchStringArray; + return $this->novaPoshtaApiClient->request('Address', 'findNearestWarehouse', array( + 'SearchStringArray' => $searchStringArray, + )); + } + + /** + * Get streets list by city and/or search string. + * + * @param string $cityRef ID of city + * @param string $findByString + * @param int $page + * + * @return mixed + */ + public function getStreet($cityRef, $findByString = '', $page = 0) + { + return $this->novaPoshtaApiClient->request('Address', 'getStreet', array( + 'FindByString' => $findByString, + 'CityRef' => $cityRef, + 'Page' => $page, + )); + } + + /** + * Find current area in list of areas. + * + * @param array $areas List of arias, getted from file + * @param string $findByString Area name + * @param string $ref Area Ref ID + * + * @return array + */ + protected function findArea(array $areas, $findByString = '', $ref = '') + { + $data = array(); + if (!$findByString and !$ref) { + return $data; + } + // Try to find current region + foreach ($areas as $key => $area) { + $found = $findByString + ? ((false !== mb_stripos($area['Description'], $findByString)) + or (false !== mb_stripos($area['DescriptionRu'], $findByString)) + or (false !== mb_stripos($area['Area'], $findByString)) + or (false !== mb_stripos($area['AreaRu'], $findByString))) + : ($key == $ref); + if ($found) { + $area['Ref'] = $key; + $data[] = $area; + break; + } + } + return $data; + } + + /** + * Get area by name or by ID. + * + * @param string $findByString Find area by russian or ukrainian word + * @param string $ref Get area by ID + * + * @return array + */ + public function getArea($findByString = '', $ref = '') + { + // Load areas list from file + empty($this->areas) and $this->areas = (include dirname(__FILE__) . '/NovaPoshtaApi2Areas.php'); + $data = $this->findArea($this->areas, $findByString, $ref); + // Error + $error = array(); + empty($data) and $error = array('Area was not found'); + // Return data in same format like NovaPoshta API + return $this->preparationDataService->prepare( + array( + 'success' => empty($error), + 'data' => $data, + 'errors' => $error, + 'warnings' => array(), + 'info' => array(), + ) + ); + } + + /** + * Get areas list by city and/or search string. + * + * @param string $ref ID of area + * @param int $page + * + * @return mixed + */ + public function getAreas($ref = '', $page = 0) + { + return $this->novaPoshtaApiClient->request('Address', 'getAreas', array( + 'Ref' => $ref, + 'Page' => $page, + )); + } + + /** + * Find city from list by name of region. + * + * @param array $cities Array from query getCities to NovaPoshta + * @param string $areaName + * + * @return array + */ + protected function findCityByRegion($cities, $areaName) + { + $data = array(); + $areaRef = ''; + // Get region id + $area = $this->getArea($areaName); + $area['success'] and $areaRef = $area['data'][0]['Ref']; + if ($areaRef and is_array($cities['data'])) { + foreach ($cities['data'] as $city) { + if ($city['Area'] == $areaRef) { + $data[] = $city; + } + } + } + return $data; + } + + /** + * Get city by name and region (if it needs). + * + * @param string $cityName City's name + * @param string $areaName Region's name + * @param string $warehouseDescription Warehouse description to identiry needed city (if it more than 1 in the area) + * + * @return array Cities's data Can be returned more than 1 city with the same name + */ + public function getCity($cityName, $areaName = '', $warehouseDescription = '') + { + // Get cities by name + $cities = $this->getCities(0, $cityName); + $data = array(); + if (is_array($cities) && is_array($cities['data'])) { + // If cities more then one, calculate current by area name + $data = (count($cities['data']) > 1) + ? $this->findCityByRegion($cities, $areaName) + : array($cities['data'][0]); + } + // Try to identify city by one of warehouses descriptions + if (count($data) > 1 && $warehouseDescription) { + foreach ($data as $cityData) { + $warehouseData = $this->getWarehouse($cityData['Ref'], $warehouseDescription); + $warehouseDescriptions = array( + $warehouseData['data'][0]['Description'], + $warehouseData['data'][0]['DescriptionRu'] + ); + if (in_array($warehouseDescription, $warehouseDescriptions)) { + $data = array($cityData); + break; + } + } + } + // Error + $error = array(); + (!$data) and $error = array('City was not found'); + // Return data in same format like NovaPoshta API + return $this->preparationDataService->prepare( + array( + 'success' => empty($error), + 'data' => $data, + 'errors' => $error, + 'warnings' => array(), + 'info' => array(), + ) + ); + } +} \ No newline at end of file diff --git a/src/Services/ConnectionService.php b/src/Services/ConnectionService.php new file mode 100644 index 0000000..c40453b --- /dev/null +++ b/src/Services/ConnectionService.php @@ -0,0 +1,36 @@ +connectionType; + } + + /** + * Setter for $connectionType property. + * + * @param string $connectionType Connection type (curl | file_get_contents) + * + * @return $this + */ + public function setConnectionType(string $connectionType): ConnectionService + { + $this->connectionType = $connectionType; + return $this; + } +} \ No newline at end of file diff --git a/src/Services/CounterPartyService.php b/src/Services/CounterPartyService.php new file mode 100644 index 0000000..7a52972 --- /dev/null +++ b/src/Services/CounterPartyService.php @@ -0,0 +1,62 @@ +novaPoshtaApiClient = new NovaPoshtaApiClient(); + } + /** + * getCounterpartyContactPersons() function of model Counterparty. + * + * @param string $ref Counterparty ref + * + * @return mixed + */ + public function getCounterpartyContactPersons($ref) + { + return $this->novaPoshtaApiClient->request('Counterparty', 'getCounterpartyContactPersons', array('Ref' => $ref)); + } + + /** + * getCounterpartyAddresses() function of model Counterparty. + * + * @param string $ref Counterparty ref + * @param int $page + * + * @return mixed + */ + public function getCounterpartyAddresses($ref, $page = 0) + { + return $this->novaPoshtaApiClient->request('Counterparty', 'getCounterpartyAddresses', array('Ref' => $ref, 'Page' => $page)); + } + + /** + * getCounterpartyOptions() function of model Counterparty. + * + * @param string $ref Counterparty ref + * + * @return mixed + */ + public function getCounterpartyOptions($ref) + { + return $this->novaPoshtaApiClient->request('Counterparty', 'getCounterpartyOptions', array('Ref' => $ref)); + } + + /** + * getCounterpartyByEDRPOU() function of model Counterparty. + * + * @param string $edrpou EDRPOU code + * @param string $cityRef City ID + * + * @return mixed + */ + public function getCounterpartyByEDRPOU($edrpou, $cityRef) + { + return $this->novaPoshtaApiClient->request('Counterparty', 'getCounterpartyByEDRPOU', array('EDRPOU' => $edrpou, 'cityRef' => $cityRef)); + } +} \ No newline at end of file diff --git a/src/Services/GenerateReportService.php b/src/Services/GenerateReportService.php new file mode 100644 index 0000000..fee05b7 --- /dev/null +++ b/src/Services/GenerateReportService.php @@ -0,0 +1,27 @@ +novaPoshtaApiClient = new NovaPoshtaApiClient(); + } + + /** + * Generetes report by Document refs. + * + * @param array $params Params like getDocumentList with requiered keys + * 'Type' => [xls, csv], 'DocumentRefs' => [] + * + * @return mixed + * @throws \Exception + */ + public function generateReport($params) + { + return $this->novaPoshtaApiClient->request('InternetDocument', 'generateReport', $params); + } +} \ No newline at end of file diff --git a/src/Services/InternetDocumentService.php b/src/Services/InternetDocumentService.php new file mode 100644 index 0000000..c1e694e --- /dev/null +++ b/src/Services/InternetDocumentService.php @@ -0,0 +1,93 @@ +novaPoshtaApiClient = new NovaPoshtaApiClient(); + } + + /** + * Get price of delivery between two cities. + * + * @param string $citySender City ID + * @param string $cityRecipient City ID + * @param string $serviceType (DoorsDoors|DoorsWarehouse|WarehouseWarehouse|WarehouseDoors) + * @param float $weight + * @param float $cost + * + * @return mixed + * @throws \Exception + */ + public function getDocumentPrice($citySender, $cityRecipient, $serviceType, $weight, $cost) + { + return $this->novaPoshtaApiClient->request('InternetDocument', 'getDocumentPrice', array( + 'CitySender' => $citySender, + 'CityRecipient' => $cityRecipient, + 'ServiceType' => $serviceType, + 'Weight' => $weight, + 'Cost' => $cost, + )); + } + + /** + * Get approximately date of delivery between two cities. + * + * @param string $citySender City ID + * @param string $cityRecipient City ID + * @param string $serviceType (DoorsDoors|DoorsWarehouse|WarehouseWarehouse|WarehouseDoors) + * @param string $dateTime Date of shipping + * + * @return mixed + */ + public function getDocumentDeliveryDate($citySender, $cityRecipient, $serviceType, $dateTime) + { + return $this->novaPoshtaApiClient->request('InternetDocument', 'getDocumentDeliveryDate', array( + 'CitySender' => $citySender, + 'CityRecipient' => $cityRecipient, + 'ServiceType' => $serviceType, + 'DateTime' => $dateTime, + )); + } + + /** + * Get documents list. + * + * @param array $params List of params + * Not required keys: + * 'Ref', 'IntDocNumber', 'InfoRegClientBarcodes', 'DeliveryDateTime', 'RecipientDateTime', + * 'CreateTime', 'SenderRef', 'RecipientRef', 'WeightFrom', 'WeightTo', + * 'CostFrom', 'CostTo', 'SeatsAmountFrom', 'SeatsAmountTo', 'CostOnSiteFrom', + * 'CostOnSiteTo', 'StateIds', 'ScanSheetRef', 'DateTime', 'DateTimeFrom', + * 'RecipientDateTime', 'isAfterpayment', 'Page', 'OrderField => + * [ + * IntDocNumber, DateTime, Weight, Cost, SeatsAmount, CostOnSite, + * CreateTime, EstimatedDeliveryDate, StateId, InfoRegClientBarcodes, RecipientDateTime + * ], + * 'OrderDirection' => [DESC, ASC], 'ScanSheetRef' + * + * @return mixed + */ + public function getDocumentList($params = null) + { + return $this->novaPoshtaApiClient->request('InternetDocument', 'getDocumentList', $params ? $params : null); + } + + /** + * Get document info by ID. + * + * @param string $ref Document ID + * + * @return mixed + */ + public function getDocument($ref) + { + return $this->novaPoshtaApiClient->request('InternetDocument', 'getDocument', array( + 'Ref' => $ref, + )); + } +} \ No newline at end of file diff --git a/src/Services/OutputService.php b/src/Services/OutputService.php new file mode 100644 index 0000000..9a972e8 --- /dev/null +++ b/src/Services/OutputService.php @@ -0,0 +1,30 @@ +'); + foreach ($array as $key => $value) { + if (is_numeric($key)) { + $key = 'item'; + } + if (is_array($value)) { + $this->array2xml($value, $xml->addChild($key)); + } else { + $xml->addChild($key, $value); + } + } + return $xml->asXML(); + } + + +} \ No newline at end of file diff --git a/src/Services/PreparationDataService.php b/src/Services/PreparationDataService.php new file mode 100644 index 0000000..ecbca0f --- /dev/null +++ b/src/Services/PreparationDataService.php @@ -0,0 +1,36 @@ +format) { + $result = is_array($data) + ? $data + : json_decode($data, true); + // If error exists, throw Exception + if ($this->throwErrors and array_key_exists('errors', $result) and $result['errors']) { + throw new \Exception(is_array($result['errors']) ? implode("\n", $result['errors']) : $result['errors']); + } + return $result; + } + // Returns json or xml document + return $data; + } +} \ No newline at end of file diff --git a/src/Services/PrintLinksService.php b/src/Services/PrintLinksService.php new file mode 100644 index 0000000..3314273 --- /dev/null +++ b/src/Services/PrintLinksService.php @@ -0,0 +1,84 @@ +preparationDataService = new PreparationDataService(); + $this->novaPoshtaApiClient = new NovaPoshtaApiClient(); + } + + /** + * Get only link on internet document for printing. + * + * @param string $method Called method of NovaPoshta API + * @param array $documentRefs Array of Documents IDs + * @param string $type (html_link|pdf_link) + * + * @return mixed + */ + protected function printGetLink($method, $documentRefs, $type) + { + $data = 'https://my.novaposhta.ua/orders/'.$method.'/orders[]/'.implode(',', $documentRefs) + .'/type/'.str_replace('_link', '', $type) + .'/apiKey/'.$this->key; + // Return data in same format like NovaPoshta API + return $this->preparationDataService->prepare( + array( + 'success' => true, + 'data' => array($data), + 'errors' => array(), + 'warnings' => array(), + 'info' => array(), + ) + ); + } + + /** + * printDocument method of InternetDocument model. + * + * @param array|string $documentRefs Array of Documents IDs + * @param string|PrintMarkingType $type (pdf|html|html_link|pdf_link) + * + * @return mixed + */ + public function printDocument($documentRefs, string|PrintMarkingType $type = PrintMarkingType::HtmlLink) + { + $documentRefs = (array) $documentRefs; + // If needs link + if (PrintMarkingType::HtmlLink == $type || PrintMarkingType::PdfLink == $type) { + return $this->printGetLink('printDocument', $documentRefs, $type); + } + // If needs data + return $this->request('InternetDocument', 'printDocument', array('DocumentRefs' => $documentRefs, 'Type' => $type)); + } + + /** + * printMarkings method of InternetDocument model. + * + * @param array|string $documentRefs Array of Documents IDs + * @param string|PrintMarkingType $type (pdf|new_pdf|new_html|old_html|html_link|pdf_link) + * + * @return mixed + */ + public function printMarkings($documentRefs, string|PrintMarkingType $type = PrintMarkingType::NewHtml, $size = '85x85') + { + $documentRefs = (array) $documentRefs; + $documentSize = $size === '85x85' ? '85x85' : '100x100'; + $method = 'printMarking'.$documentSize; + // If needs link + if ('html_link' == $type or 'pdf_link' == $type) { + return $this->printGetLink($method, $documentRefs, $type); + } + // If needs data + return $this->novaPoshtaApiClient->request('InternetDocument', $method, array('DocumentRefs' => $documentRefs, 'Type' => $type)); + } +} \ No newline at end of file diff --git a/src/Services/TrackingDocumentService.php b/src/Services/TrackingDocumentService.php new file mode 100644 index 0000000..7a6448a --- /dev/null +++ b/src/Services/TrackingDocumentService.php @@ -0,0 +1,27 @@ +novaPoshtaApiClient = new NovaPoshtaApiClient(); + } + + /**` + * Get tracking information by track number. + * + * @param string $track Track number + * + * @return mixed + */ + public function documentsTracking($track) + { + $params = array('Documents' => array(array('DocumentNumber' => $track))); + + return $this->novaPoshtaApiClient->request('TrackingDocument', 'getStatusDocuments', $params); + } +} \ No newline at end of file diff --git a/tests/NovaPoshtaApi2Test.php b/tests/NovaPoshtaApi2Test.php index f276302..12aab99 100755 --- a/tests/NovaPoshtaApi2Test.php +++ b/tests/NovaPoshtaApi2Test.php @@ -2,7 +2,7 @@ namespace LisDev\Tests; -use LisDev\Delivery\NovaPoshtaApi2; +use LisDev\Controllers\NovaPoshtaApi2; /** * phpUnit test class.