Привет друзья.
Хочу поделиться PHP библиотекой (SDK) для интеграции с API 2 Новой Почты (НП). Но сначала несколько слов о Новой Почте.
Новая Почта является лидером экспресс-доставки и перевозки грузов по всей Украине. В Новой Почте много услуг, что делает ее лидером на украинском рынке перевозок. Склады есть во всех городах Украины, очень быстрая курьерская служба. Основные услуги, которые компания надает: доставка и возврат грузов в розничных сетях; доставка паллетированного груза; обратная доставка,; наложенный платёж за товар; вызов машины; хранение груза; упаковка груза, доставка груза по городу и прочее. Для упрощения создание ТТН можно использовать API компании, что даст возможность оптимизировать создания ТТН.

Возможности которые дает SDK:
  • Работа с адресами
  • Работа со справочниками
  • Работа с контрагентами
  • Методы для получения печатных форм документов
  • Работа с реестрами экспресс-накладных
  • Работа с экспресс-накладными:
    • создавать экспресс-накладные
    • редактировать данные в созданных экспресс-накладные (до передачи отправления)
    • удалять/отменять созданные экспресс-накладные (до передачи отправления)
    • загружать списки документов используя фильтры
    • отслеживать статусы отправления


Подключить библиотеку (SDK)
Способ 1 (composer)

Создайте файл composer.json в корне Вашeго проекта:
{
      "require": {
          "serj1chen/nova-poshta-sdk-php": "2.0.*"
      }
}

Установить composer:
$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar install

Подключить автолоадер composer:
include_once "vendor/autoload.php";

Способ 2 (git)

Клонировать репозиторий:
git clone git://github.com/serj1chen/nova-poshta-sdk-php

Подключить автолоадер SDK:
include_once "nova-poshta-sdk-php/lib/NovaPoshta/bootstrap.php";


Перед тем как начать работать с SDK, нужно получить API ключ. Переходим за ссылкой https://my.novaposhta.ua, заходим под своим логином в личный кабинет. Далее п.м. Налаштування-> API 2.0. Нажимаем кнопку Створити новий ключ, копируем созданный ключ.

keyForApi

Настройка SDK


   use NovaPoshta\Config;

   Config::setApiKey('<Ваш ключ>');
   Config::setFormat(Config::FORMAT_JSONRPC2);
   Config::setLanguage(Config::LANGUAGE_UA);

Возможные форматы передачи данных (формат указывать в метод setFormat):
  • FORMAT_JSON
  • FORMAT_JSONRPC2 (рекомендую)
  • FORMAT_XML

По дефолту будет установлен формат JSONRPC2.

Работа с моделями SDK


В документации НП работа разбита на модели:

Работа с методами моделей

Работа с методами модели: save, update, delete. Заполнить модель нужными значениями и вызвать нужный метод. Пример:

    use NovaPoshta\ApiModels\Counterparty;

    $counterparty = new Counterparty();
    $counterparty->setCounterpartyProperty('Recipient');
    $counterparty->setCityRef('db5c88d0-391c-11dd-90d9-001a92567626');
    $counterparty->setCounterpartyType('PrivatePerson');
    $counterparty->setFirstName('Пилипко');
    $counterparty->setLastName('Вася');
    $counterparty->setMiddleName('Сергеевич');
    $counterparty->setPhone('+380661122333');
    $counterparty->setEmail('test@i.ua');

    $result = $counterparty->save();

Работа с статическими методами. В методы передавать объект MethodParameters:

    use NovaPoshta\ApiModels\Counterparty;
    use NovaPoshta\MethodParameters\MethodParameters;

    $data = new MethodParameters();
    $data->CounterpartyProperty = 'Recipient';
    $data->Page = 1;
    $data->CityRef = '8d5a980d-391c-11dd-90d9-001a92567626';
    $data->FindByString = 'Петр';

    $result = Counterparty::getCounterparties($data);

Или можно использовать классы MethodParameters, которые наследуются от класса MethodParameters. Классы имеют сеттеры параметров, которые можно передать статическому методу модели. Названия классов с параметрами складываются с двух частей, с названия модели (ApiModels) и названия статического метода модели. Пример использования:

    use NovaPoshta\ApiModels\Counterparty;
    use NovaPoshta\MethodParameters\MethodParameters;
    use NovaPoshta\MethodParameters\Counterparty_getCounterparties;

    $data = new Counterparty_getCounterparties();
    $data->setCounterpartyProperty('Recipient');
    $data->setPage(1);
    $data->setCityRef('8d5a980d-391c-11dd-90d9-001a92567626');
    $data->setFindByString('Петр');

    $result = Counterparty::getCounterparties($data);

Логирования запросов
Если Вам нужно логировать данные отправки/получения запросов. Нужно создать класс который наследуется от Logger.php и передать экземпляр этого класса в метод setClassLogger файла Config.php.

use NovaPoshta\Logger;
use NovaPoshta\Config;

class Logger_example extends Logger
{
    public static function setOriginalData($toData, $fromData)
    {
        // ...
    }

    public static function setData($toData, $fromData)
    {
        // ...
    }
}

Config::setClassLogger($ new Logger_example());


Метод setOriginalData: запрос/ответ API Новой Почты. Параметры: toData — запрос (тип: string); fromData — ответ (тип: string).

Метод setData: запрос/ответ API Новой Почты у формате SDK. Параметры: toData — запрос (объект: DataContainer); fromData — ответ (объект: DataContainerResponse).

Создания экспресс накладной (ТТН)
Выбираем город отправителя:
    $data = new \NovaPoshta\MethodParameters\Address_getCities();
    $data->setFindByString('Полтава');
    $result = \NovaPoshta\ApiModels\Address::getCities($data);

    $citySender = $result->data[0]->Ref;

Выбираем город получателя:
   $result = \NovaPoshta\ApiModels\Address::getCities(); // список городов

   $cityRecipient = $result->data[60]->Ref;

Выбираем тип контрагента:
    $result = \NovaPoshta\ApiModels\Common::getTypesOfCounterparties();

    $counterpartyType = $result->data[1]->Ref; // со списка выбираем тип PrivatePerson

Создаем контрагента получателя:
    $counterparty = new \NovaPoshta\ApiModels\Counterparty();
    $counterparty->setCounterpartyProperty(\NovaPoshta\ApiModels\Counterparty::RECIPIENT);
    $counterparty->setCityRef($cityRecipient);
    $counterparty->setCounterpartyType($counterpartyType);
    $counterparty->setFirstName('Пилипко');
    $counterparty->setLastName('Вася');
    $counterparty->setMiddleName('Сергеевич');
    $counterparty->setPhone('+380661122333');
    $counterparty->setEmail('test@i.ua');
    $result = $counterparty->save();

    $counterpartyRecipient = $result->data[0]->Ref;

Если нет контрагента отправителя в городе Полтава, создаем там контрагента отправителя. Контрагент создастся через несколько минут:
    $data = new \NovaPoshta\MethodParameters\Counterparty_cloneLoyaltyCounterpartySender();
    $data->setCityRef($citySender);
    $result = \NovaPoshta\ApiModels\Counterparty::cloneLoyaltyCounterpartySender($data);

Если у Вас есть контрагент отправитель, то получаем его так же как контрагента получателя, только сюда: setCounterpartyProperty передаем \NovaPoshta\ApiModels\Counterparty::SENDER. Методом cloneLoyaltyCounterpartySender можно использовать только если Вы клиент лояльности, если Вы корпоративный клиент, то у Вас уже должен быть контрагент отправитель в нужном городе.
Теперь получим контрагента отправителя:
    $data = new \NovaPoshta\MethodParameters\Counterparty_getCounterparties();
    $data->setCityRef($citySender);
    $data->setCounterpartyProperty(\NovaPoshta\ApiModels\Counterparty::SENDER);
    $result = \NovaPoshta\ApiModels\Counterparty::getCounterparties($data);

    $counterpartySender = $result->data[0]->Ref;

Получим контактных персон для контрагентов:
    $data = new \NovaPoshta\MethodParameters\Counterparty_getCounterpartyContactPersons();
    $data->setRef($counterpartySender);
    $result = \NovaPoshta\ApiModels\Counterparty::getCounterpartyContactPersons($data);

    $contactPersonSender = $result->data[0]->Ref;

    $data = new \NovaPoshta\MethodParameters\Counterparty_getCounterpartyContactPersons();
    $data->setRef($counterpartyRecipient);
    $result = \NovaPoshta\ApiModels\Counterparty::getCounterpartyContactPersons($data);

    $contactPersonRecipient = $result->data[0]->Ref;

Для контрагента отправителя получим склад отправки:
    $data = new \NovaPoshta\MethodParameters\Address_getWarehouses();
    $data->setCityRef($citySender);
    $result = \NovaPoshta\ApiModels\Address::getWarehouses($data);

    $addressSender = $result->data[5]->Ref;

Создадим адрес для получателя:
    $address = new \NovaPoshta\ApiModels\Address();
    $address->setCounterpartyRef($counterpartyRecipient);
    $address->setBuildingNumber('2/2');
    $address->setFlat('22');
    $address->setNote('Первый подъезд');
    $address->setStreetRef('c55c9056-4148-11dd-9198-001d60451983');
    $result = $address->save();

    $addressRecipient = $result->data[0]->Ref;

Теперь получим тип услуги:
    $result = \NovaPoshta\ApiModels\Common::getServiceTypes();

    $serviceType = $result->data[3]->Ref; // Выбрали: WarehouseDoors

Выбираем плательщика:
    $result = \NovaPoshta\ApiModels\Common::getTypesOfPayers();

    $payerType = $result->data[1]->Ref; // Выбрали: Recipient

Форму оплаты:
    $result = \NovaPoshta\ApiModels\Common::getPaymentForms();
    $paymentMethod = $result->data[1]->Ref; // Выбрали: Cash

Тип груза:
    $result = \NovaPoshta\ApiModels\Common::getCargoTypes();

    $cargoType = $result->data[0]->Ref; // Выбрали: Cargo

Мы выбрали все данные которые нам нужны для создания ЭН. Создаем ЭН:
    // Контрагент отправитель
    $sender = new \NovaPoshta\Models\CounterpartyContact();
    $sender->setCity($citySender)
        ->setRef($counterpartySender)
        ->setAddress($addressSender)
        ->setContact($contactPersonSender)
        ->setPhone('+380660000000');

    // Контрагент получатель
    $recipient = new \NovaPoshta\Models\CounterpartyContact();
    $recipient->setCity($cityRecipient)
        ->setRef($counterpartyRecipient)
        ->setAddress($addressRecipient)
        ->setContact($contactPersonRecipient)
        ->setPhone('+380660000000');

    // Выбираем тип
    $result = \NovaPoshta\ApiModels\Common::getTypesOfPayersForRedelivery();
    $redeliveryPayer = $result->data[1]->Ref;

    // Выбираем тип обратной доставки
    $result = \NovaPoshta\ApiModels\Common::getBackwardDeliveryCargoTypes();
    $redeliveryCargoType = $result->data[1]->Ref;

    // Обратная доставка ценные бумаги
    $backwardDeliveryData = new \NovaPoshta\Models\BackwardDeliveryData();
    $backwardDeliveryData->setPayerType($redeliveryPayer);
    $backwardDeliveryData->setCargoType($redeliveryCargoType);
    $backwardDeliveryData->setRedeliveryString(452);

    $internetDocument = new \NovaPoshta\ApiModels\InternetDocument();
    $internetDocument->setSender($sender)
        ->setRecipient($recipient)
        ->setServiceType($serviceType)
        ->setPayerType($payerType)
        ->setPaymentMethod($paymentMethod)
        ->setCargoType($cargoType)
        ->setWeight(1)
        ->setSeatsAmount(1)
        ->setCost(452)
        ->setDescription('ТЦ')
        ->setDateTime('10.09.2015')
        ->addBackwardDeliveryData($backwardDeliveryData);
    $result = $internetDocument->save();

    $refInternetDocument = $result->data[0]->Ref;

Получить ссылку на печать ЭН:
    $data = new \NovaPoshta\MethodParameters\InternetDocument_printDocument();
    $data->addDocumentRef($refInternetDocument);
    $data->setCopies(\NovaPoshta\ApiModels\InternetDocument::PRINT_COPIES_FOURFOLD);

    $link = \NovaPoshta\ApiModels\InternetDocument::printDocument($data);

После печати ЭН, клеем ЭН на коробку и отправляем груз))

Надеюсь SDK Вам поможет интегрироваться с API Новой Почты. Сейчас я доделываю аналогичное SDK для Python, когда доделаю SDK выложу статью на хабр.

Удачи!

Комментарии (17)


  1. achekalin
    05.08.2015 16:47
    +5

    Ничего не хочу сказать, но лично мне слова «Новая почта» ничего ничего не сказали. Было бы, наверное, разумно хотя бы первое предложение поста написать в смысле «на Украине существует такой провайдер, он хорош тем и тем, и я им пользуюсь. Недавно они запустили вторую версию API для работы с их сервисами. Возникла такая вот техническая задача, для решения которой я написал SDK для работы с ее API.»

    Мне кажется, многие читатели Хабра присоединятся к моей просьбе.

    P.S. Тем более что по приведенной Вами в начале статьи ссылке вижу словеса вида «между информационной системой компании «Новая Почта» и программным комплексом Партнера/Клиента», что, как бы, намекает, что почта не простая, так что пояснить было бы вполне разумно.


    1. jhekasoft
      06.08.2015 02:28
      +2

      Это да. А какие есть аналоги «Новой Почты» на России? Интересно просто.


      1. FractalizeR
        06.08.2015 10:27
        +1

        Я так понимаю, это просто служба доставки. Пусть и с продвинутыми инструментами.


      1. achekalin
        06.08.2015 13:46
        +2

        В России тоже хватает грузоперевозчиков. По поводу API и прочего не скажу, а вот чем «Новая почта» (второе слово-то зачем с заглавной писать?) выделяется, кроме того, что более ИТ-дружественна — это, кстати, хорошая тема как для вступления к этой статье (о чем я и написал выше), так и для целой заметки обзорного характера «как я пересылаю грузы» (на Украине, в России, в Крыму, в Армении… да где угодно, от автора и его знаний зависит!)


        1. cbeta7910
          06.08.2015 16:37
          +2

          Новая Почта — это не просто очередной грузоперевозчик, это реальная замена почты, у нее отделения в каждом городе и уже даже селе Украины. Вот этим, собственно, они и выделяются. Благодаря Новой Почте в Украине стало возможно нормально покупать/продавать через интернет в любую точку страны, а не как раньше только в крупных городах через региональных перевозчиков, или укрпочтой, ожидая товар неделями без страховки и гарантии дойдет ли он вообще.

          PS. Второе слово именно с большой буквы, такое официальное название, а, как известно, названия не изменяются, даже если они написаны синтаксически не верно.


          1. cbeta7910
            06.08.2015 16:48
            +2

            При этом стоимость доставки за сутки из любой точки страны в любую точку всего 1$. Учитывая быструю скорость доставки, пересортировку посылок в промежуточных точках, стоимость бензина это недорого. Иностранцы, посещающие Украину, поражаются такой низкой цене за подобный сервис. Наши знакомые итальянцы и немцы восторгались, у них аналогичные службы за подобные услуги берут 10-15 евро и при этом скорость доставки медленнее.


          1. achekalin
            06.08.2015 18:00

            По моему, первый абзац вашего ответа — отличное введение для статьи )


    1. tangro
      06.08.2015 09:09
      +3

      Ну, в защиту автора надо сказать, что «Новая почта» это не «существует такой провайдер, я им пользуюсь», а система, реально заменившая обычную почту для всех людей, кому нужно чтобы посылка вот правда пришла и вот прямо завтра. Количество отделений Новой Почты, их доступность и сервис сделали их не просто какой-то там ещё одной службой доставки, а дефолтным способом отправки документов, наложенных платежей, лотов с аукционов и т.д. Обычной почтой пользуются теперь разве-что гос.учереждения и те, кому в общем то плевать, дойдёт их письмо или нет.


      1. achekalin
        06.08.2015 12:20

        Ничего против не имею. Просто считаю, что без вступления рассказывать про сервис, пусть и хороший, но а) работающий в одной стране и б) не всем даже в этой стране известный, и вовсе не являющийся дефолтным синонимом слова «почта» — это неверно по отношению к другим читателям сайта.

        С тем же успехом я могу написать статью про работу с API компании «Н??р Мал аж ахуйн компани», а что это компания из Монголии, что она к ИТ не имеет особого отношения — этого не написать, имея в виду, что все читатели Хабра до таких простых вещей легко догадаются.

        То, о чем я написал, требует элементарной вежливости к читателю в виде одного-двух предложений. Уверен, что человек не написал их без умысла — просто для него тема привычная и локально-дефолтно-понятная. С другой стороны, будь введение, многие, даже не знакомые с сервисом «Нвоой почты», могли бы хотя бы прочесть и, возможно, попробовать использовать сервис, а так они просто пропустили статью, поскольку до ката не увидели слов «удобный сервис доставки грузов» и «Украина».


        1. neverice
          06.08.2015 15:59
          -1

          В Украине про Новую Почту знают все. Нет смысла уточнять. А если вы не знаете про Новую Почту, то Вам ее API тем более не нужно и можете смело пропускать статью. Одним словом, критика немного надуманная. Я понимаю, что Хабр находится в ru зоне, но это все таки международный ресурс. Читатели из Украины не возмущаются же, что какой-то сервис доступен только в РФ, а в заголовке этого не уточнили.


          1. achekalin
            06.08.2015 16:07

            Так, давайте географию отложим в сторону. Алгоритм «не понял — пропускай» не подходит к Хабру, здесь аудитория другая. Немного уважения к читателю — совсем небольшое требование.

            А что на Украине все или не все знают про ту или иную компанию, так, извините, если мы все с упорством будем писать без указания и без вводной о предметах, нам самим понятным (повторюсь, я не о географии), то кому мы сделаем лучше?

            Давайте вместе подумаем: что лучше, статья в стиле «Есть такой сервис, нравится тем-то и тем-то, я написал либу для работы с его API» или «Те, кто в теме, поняли, о чем я написал». Если разговор бы шел в записи в личном блоге где-то в ЖЖ (где по дефолту никто не видит записей того, кем не интересуется) — вопроса бы не было. Здесь же пост попадает на глаза с куда большей вероятностью, а варианта настроек «показывать мне ТОЛЬКО то, на что я подписался» особо нет. Из этого я и получаю вывод, что часть читателей, будучи не в теме про НП, должны замереть в процессе прокрутки страницы над незнакомым названием, покопаться в памяти, получить пустой результат, и только тогда скролить дальше.


          1. Vyazovoi
            06.08.2015 19:30

            Я вот открыл статью из рассылки с мыслью «что это за почта такая и чем она лучше gmail» и потратил много времени чтобы понять, что, во-первых, это мне не нужно, во-вторых, не доступно мне регионально. По моему тут даже обсуждать нечего — введения этой статье категорически не хватает, отсутствие вводного абзаца это ошибка.


    1. chen14
      08.08.2015 09:19

      Вы правы, Добавил несколько слов о Новой Почте. В Украине про Новою Почту знаю все, но не учел что большинство читателей хабра не знают украинские компании)


  1. softm
    05.08.2015 20:13

    * Если можно, ответьте — вообще работа с «новой поштой» через апи — хоть на копейку уменьшает цену отправления?
    * Потому, что это конечно супер вещь, но если у тебя три посылки в неделю есть ли смысл привинчивать АПИ?


    1. cbeta7910
      06.08.2015 00:33

      За каждую оформленную накладную через кабинет Новой почты, ну и через API тоже, начисляют 2 грн на карту. Это кажется не так уж важно, но вот, к примеру, у меня набегает 700-800 грн в месяц бонусов на оформлении посылок через API, а это уже существенная экономия, можно коммунальные оплатить ))


  1. rustem_ck
    05.08.2015 23:52

    Я Вам скажу, как владелец IT-интернет магазина по продаже бубнов (http://habrahabr.ru/post/226361/), что использую такую библиотеку.
    К примеру, когда клиент оформляет заказ на сайте и указывает адрес доставки склада Новой Почты, данная библиотека вытягивает актуальный список населённых пунктов, и уже по ним список отделений в этих населённых пунктах. Ввиду нестабильной географической (политической) ситуации в Украине, есть место поддерживать актуальный список населённых пунктов в которые осуществляется доставка.

    Одна серйозная проблема — это время отклика работы самого сервера API. Порою бывают такие задержки, когда много клиентов хотят получить запрос отделений разных городов, что мне кажется что сам API включает какую-то защиту от DDOS, либо имеет ограничение на к-во запросов в период времени. Так что пока боремся путём кеширования (ввиде локального хранения списка отделений/городов и обновления через API).


    1. cbeta7910
      06.08.2015 00:37
      +1

      Хорошее решение, имхо. Постоянно дергать их список отделений, учитывая тормознутость и частую недоступность их серверов, а потом еще json обрабатывать, на это все уходит время, ресурсы. Мы затягиваем списки отделений раз в неделю в базу данных и уже с ним работаем из магазина.