Git Product home page Git Product logo

russianpost-sdk's Introduction

SDK для бизнес-сервисов Почты России

Latest Version on Packagist Testing Quality Score Code Coverage StyleCI Total Downloads License MIT

Содержание

Работа с API пакетного трекинга и API отправки возможна только при наличии договора с Почтой России.

Работа с API единичного трекинга возможна как с договором, так и после простой регистрации (но с лимитом — 100 запросов в сутки).

Установка

Минимальные требования — PHP 7.1+, ext-soap, ext-json.

Для установки используйте менеджер пакетов Composer:

composer require appwilio/russianpost-sdk

При использовании фреймворка Laravel SDK автоматически регистрирует доступные сервисы.

Минимальная версия Laravel — 5.8.

Логирование

Для логирования запросов и ответов можно подключить любой логгер, реализующий стандарт PSR-3, например, Monolog:

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$log = (new Logger('pochta.ru'))
    ->pushHandler(new StreamHandler('path/to/your.log', Logger::INFO));

// SingleAccessClient, PacketAccessClient, DispatchingClient
$client->setLogger($log);

В случае использования фреймворка Laravel следует добавить логгер в контейнер под именем appwilio.russianpost.logger:

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$this->app->singleton('appwilio.russianpost.logger', static function () {
    return (new Logger('pochta.ru'))
        ->pushHandler(new StreamHandler('path/to/your.log', Logger::INFO));
});

Трекинг

Документация

Конфигурация в Laravel

Добавьте следющие ключи в services.php:

// ...
'russianpost' => [
    'tracking' => [
        'login' => \env('RUSSIAN_POST_TRACKING_LOGIN'),
        'password' => \env('RUSSIAN_POST_TRACKING_PASSWORD'),
    ],
],
// ...

Не забудьте перегенерировать кэш настроек, если они были закэшированы!

Единичный доступ

Конструктор класса SingleAccessClient принимает два параметра — логин и пароль от личного кабинета на сайте Почты России.

use Appwilio\RussianPostSDK\Tracking\SingleAccessClient;

$tracker = new SingleAccessClient($login = 'login', $password = 'secret');

Если информации по ШПИ (трек-комеру) не найдено, то выбрасывается исключение Appwilio\RussianPostSDK\Tracking\Exceptions\SingleAccessException с соответствующим сообщением.

Получение данных по ШПИ (трек-комеру)

$response = $tracker->getTrackingEvents('29014562148754');

Объект $response реализует интерфейс \IteratorAggregate, поэтому его можно сразу перебирать в цикле:

foreach ($response as $events) {
    $parameters = $events->getOperationParameters();
    
    echo $parameters->getOperationId();
    echo $parameters->getAttributeId();
    echo $parameters->getPerformedAt()->format('d.m.Y в h:i:s'); // 17.09.2019 в 17:20:48
}

Получение информации о наложенном платеже по ШПИ (трек-комеру)

$response = $tracker->getCashOnDeliveryEvents('29014562148754');

Объект $response реализует интерфейс \IteratorAggregate, поэтому его можно сразу перебирать в цикле:

foreach ($response as $event) {
    $parameters = $event->getOperationParameters();
    
    echo $parameters->getTransferNumber();
    echo $parameters->getPayment(); // 7410
    echo $parameters->getPerformedAt()->format('d.m.Y в h:i:s'); // 17.09.2019 в 17:20:48
}

Пакетный доступ

use Appwilio\RussianPostSDK\Tracking\PacketAccessClient;

$tracker = new PacketAccessClient($login = 'login', $password = 'secret');

Получение данных по ШПИ (трек-комеру)

$ticket = $tracker->getTicket(['29014562148754', 'RA325487125CN']); // максимум 3 000 треков

Рекомендуется подождать 15 минут перед запросом информации.

$response = $tracker->getTrackingEvents($ticket->getId());

echo $response->getPreparedAt()->format('d.m.Y в h:m:s');

Объект $response реализует интерфейс \IteratorAggregate, поэтому его можно сразу перебирать в цикле:

foreach ($response as $item) {
    echo $item->getBarcode();
    
    foreach ($item as $events) {
        echo $events->getOperationId();
        echo $events->getAttributeId();
        echo $events->getPerformedAt()->format('d.m.Y в h:m:s'); // 17.09.2019 в 17:20:48
    }
}

Отправка

Документация

Конфигурация

Конструктор класса DispatchingClient принимает три обязательных параметра: логин и пароль от личного кабинета на сайте Почты России, а так же токен доступа, который высылается на почту при подключении сервиса «Отправка» и может быть изменён в личном кабинете.

use GuzzleHttp\Client as GuzzleClient;
use Appwilio\RussianPostSDK\Dispatching\DispatchingClient;

$dispatching = new DispatchingClient(
    $login = 'login', $password = 'secret', $token = 'QWERTY', new GuzzleClient()
);

Конфигурация в Laravel

Добавьте следющие ключи в services.php:

// ...
'russianpost' => [
    'dispatching' => [
        'token' => \env('RUSSIAN_POST_DISPATCHING_TOKEN'),
        'login' => \env('RUSSIAN_POST_TDISPATCHING_LOGIN'),
        'password' => \env('RUSSIAN_POST_DISPATCHING_PASSWORD'),
        'guzzle' => [
            'timeout' => 5,
        ],
    ],
],
// ...

Не забудьте перегенерировать кэш настроек, если они были закэшированы!

Расчёт стоимости пересылки

use Appwilio\RussianPostSDK\Dispatching\Enum\MailType;
use Appwilio\RussianPostSDK\Dispatching\Enum\MailCategory;
use Appwilio\RussianPostSDK\Dispatching\Enum\MailEntryType;
use Appwilio\RussianPostSDK\Dispatching\Endpoints\Services\Requests\CalculationRequest;

$response = $dispatching->services->calculate(
    CalculationRequest::create('123456', 200)
        ->ofMailType(MailType::PARCEL_POSTAL())
        ->ofMailCategory(MailCategory::ORDINARY())
        ->ofEntriesType(MailEntryType::GOODS())
        ->fragile()
        ->withSmsNotice()
);

echo $response->getTotal()->getRate();
echo $response->getTotal()->getVAT(); // НДС

Нормализация и валидация данных

Нормализация ФИО

use Appwilio\RussianPostSDK\Dispatching\Endpoints\Services\Requests\NormalizeFioRequest;

$response = $dispatching->services->normalizeFio(
    NormalizeFioRequest::one('иванов иван иванович')
);

if ($response[0]->isUseful()) {
    echo $response[0]->getFirstName().' '.$response[0]->getLastName(); // Иван Иванов
}

Нормализация адресов

use Appwilio\RussianPostSDK\Dispatching\Endpoints\Services\Requests\NormalizeAddressRequest;

$response = $dispatching->services->normalizeAddress(
    NormalizeAddressRequest::one('Москва варшавское шоссе 37-45')
);

Нормализация телефонов

use Appwilio\RussianPostSDK\Dispatching\Endpoints\Services\Requests\NormalizePhoneRequest;

$response = $dispatching->services->normalizePhone(NormalizePhoneRequest::one('89001234567'));

Проверка благонадёжности получателя

use Appwilio\RussianPostSDK\Dispatching\Endpoints\Services\Requests\CheckRecipientRequest;

$response = $dispatching->services->checkRecipient(
    CheckRecipientRequest::one('Москва, Варшавское шоссе, 37-45', 'Иванов Иван Иванович', '+7 123 456-78-90')
);

$response[0]->isFraud(); // ненадёжный
$response[0]->isReliable(); // надёжный
use Appwilio\RussianPostSDK\Dispatching\Endpoints\Services\Requests\CheckRecipientRequest;

$request = CheckRecipientRequest::create();
$request->addRecipient('123456 Москва, Варшавское шоссе, 37-45', 'Иванов Иван Иванович', '+7 123 456-78-90');

$response = $dispatching->services->checkRecipient($request);

foreach ($response as $recipient) {
    echo $recipient->getAddress.': '.$recipient->isReliable();
}

Документы

$file = $dispatching->documents->orderF7Form('12345678');

echo $file->getClientFilename(); // f7p.pdf

// Сохранение
$file->moveTo("storage/printforms/12345678-{$file->getClientFilename()}");

// Перенаправление в браузер (Laravel)
return \response()->streamDownload(staticfunction () use ($file) {
    (string) $file->getStream();
}, $file->getClientName(), ['Content-Type' => $file->getClientMediaType()]);

Форма Ф7п для заказа

use Appwilio\RussianPostSDK\Dispatching\Enum\PrintType;

$pdf = $dispatching->documents->orderF7Form(
    '12345678', new \DateTime('2019-01-01'), PrintType::PAPER()
);

Форма Ф112ЭК для заказа

$pdf = $dispatching->documents->orderF112Form('12345678', new \DateTime('2019-01-01'));

Пакет документов для заказа (до формирования партии)

$zip = $dispatching->documents->orderFormsBundleBacklog('12345678', new \DateTime('2019-01-01'));

Пакет документов для заказа (после формирования партии)

use Appwilio\RussianPostSDK\Dispatching\Enum\PrintType;

$zip = $dispatching->documents->orderFormBundle(
    '12345678', new \DateTime('2019-01-01'), PrintType::THERMO()
);

Пакет документов для партии

$zip = $dispatching->documents->batchFormBundle('87654321');

Акт осмотра содержимого партии

$pdf = $dispatching->documents->batchCheckingForm('87654321');

Форма Ф103 для партии

$pdf = $dispatching->documents->batchF103Form('87654321');

Возвратный ярлык

use Appwilio\RussianPostSDK\Dispatching\Enum\PrintType;

$pdf = $dispatching->documents->easyReturnForm('29014562148754', PrintType::THERMO());

Запуск тестов

$ vendor/bin/phpunit

Авторы

Лиценция

Данный SDK распространяется под лицензией MIT.

russianpost-sdk's People

Contributors

dva-re avatar greabock avatar janrydrych avatar jhaoda avatar sanmai avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

russianpost-sdk's Issues

Что делаем с ошибками?

Что делаем с ошибками?

У нас есть следующие уровни ошибок

  1. Все виды системных (ОС) ошибок
  2. Ошибки при передаче запрос (http status code != 200 и тп)
  3. Ошибки при парсинге ответа (API выдал null вместо json'а и тп)
  4. Ошибки самого API в ответе ($errors[0]["error-code"] = "ALL_SHIPMENTS_SENT")

Вопрос - когда выбрасывать Exception'ы, а когда просто строки error_code и error_message?

По аналогии с ларой можно реализовывать два метода:

$orders->find('56445645645');
$orders->findOrFail('56445645645');
  1. В первом случае Exception'ы выбрасываются на 1-3 уровни ошибок, а 4й уровень программист анализирует сам
$response = $orders->find('56445645645');
if (is_null($response->body)) //мне важно только найден ли заказ
if (!empty($response->errors)) //мне важно почему не найден заказ
  1. Во втором случае Exception'ы выбрасываются на всех уровнях ошибок
try{
	$response = $orders->findOrFail('56445645645');
}catch(IncorrectOrderIdException $e){
	//Обработка такой ошибки с бизнес-логикой
}catch(APIException $e){
	//Уведомление пользователя об ошибке
}catch(Exception $e){
	//Все совсем плохо, только логгирование
}

При этом IncorrectOrderIdException extends APIException

К моменту когда это дописал - уже не уверен нужно ли реализовывать второй вариант, т.к. это очень много работы сверху. Много кастомных Exception'ов, которые к тому же надо маппить к кодам ошибки из документации.
Но уверен что такой вариант очень полезен в целом ряде задач.

Обсуждаем?

P.S: Судя по всему findOrFail довольно независим, т.е. в качестве компромисса можно сначала реализовать весь API только c find, а только потом думать над findOrFail.

401 Unauthorized response

Добрый день. Спасибо за вашу работу. Не знаю куда еще написать. Возможно, ошибка в моей невнимательности.

Появляется такая ошибка. Делаю все в точности как в разделе отправка в пунктах: Конфигурация, Расчёт стоимости пересылки (может, еще что-то необходимо настроить). Только использую свои логин, пароль и токен. Если вывести dd($dispatching->services), ошибки еще нет. А при создании $response = $dispatching->services->calculate(...) появляется ошибка:
ILLEGAL_CREDENTIALS - Ошибка авторизации пользователя: invalid_grant Client error: POST https://otpravka-api.pochta.ru/1.0/tariff resulted in a 401 Unauthorized response
У вас в конфигах логин и пароль называются по-разному: TRACKING и DISPATCHING для трекинга и отправки. Это имеет значение? Я брала из личного кабинета почты. Причем, из личного кабинета - это набор латинских букв, а на странице генерации ключа на сайте почты написано: Имя пользоватателя (емайл). Чей емайл... Токен я уже 10 раз проверила - скопирован из личного кабинета.

Пробовала добавлять в свои данные токена 'AccessToken ', появляется ошибка:
cURL error 18: transfer closed with 103 bytes remaining to read (see https://curl.haxx.se/libcurl/c/libcurl-errors.html),
причем тоже на этапе $response = $dispatching->services->calculate(...). Но вроде бы подпись 'AccessToken ' должна генерироваться со стороны вашего пакета, так что добавление этой подписи должно быть ненужно. Так?

Совершенно запуталась в каком месте происходит ошибка и какие данные являются неверными. Если поможете, буду очень благодарна.

Как нам обсустроить API отправки

Предполагается что-то типа:

$api->service->cleanPhone('89012345678');
$api->service->cleanAddress('Красноярск, Добрых Комбайнёров, 587');

$api->orders->create(new InputOrder(...));
$api->orders->find('56445645645');

и так далее.

Корневой класс:

/**
 * @property-read Orders $orders
 * @property-read Service $services
 * @property-read Shipments $shipments
 * ...
 */
class Api
{
    // ...
}

cc @greabock @krylov123

Поддержка Guzzle 7

Всем привет.
Планируется апнуть guzzle до 7? А то у меня все проекты на 7ой версии работают, соответственно, нет возможности использовать ваш SDK :(

findOrderByTrackingNumber возвращает заказ с некорректными данными

Appwilio\RussianPostSDK\Dispatching\Endpoints\Batches\Batches::findOrderByTrackingNumber обращается к /1.0/shipment/search, который возвращает несколько объектов, а не один, за счет чего на выходе имеем Order внутри которого массив заказов.

Корректный вариант:

    /**
     * @param  string  $barcode
     * @return Order[]|null
     */
    public function findOrdersByTrackingNumber(string $barcode)
    {
        return $this->client->get('/1.0/shipment/search', GenericRequest::create(['query' => $barcode]), new ArrayOf(Order::class));
    }

Слабо ориентируюсь в этом API, в моем случае $barcode это был внутренний номер заказа в интернет-магазине, а не трек-номер.

Отправка с разных адресов

Добрый день! Возможна ли в данном пакете реализация отправки с разных адресов? Как в случае маркетплейса

И еще: при работе с пакетом у меня возникла ошибка - "неверное имя или пароль, про1дите регистрацию на сайте почты России". Но при этом имя и пароль верные

Enum вместо обычных констант

Отправка

Общие

  • Тип адреса (AddressType)
  • Категория партии (BatchCategory)
  • Категория РПО (MailCategory)
  • Вид РПО (MailType)
  • Статус партии (BatchStatus)
  • Способ оплаты (PaymentType)
  • Вид транспортировки (TransportType)
  • Категория уведомления о вручении РПО (NotifyCategory)
  • Код качества нормализации адреса (AddressQuality)
  • Код проверки нормализации адреса (AddressValidity)
  • Код качества нормализации ФИО (FioQuality)
  • Код качества нормализации телефона (PhoneQuality)
  • Тип конверта (EnvelopeType)
  • Разряд письма (MailRank)
  • Тип печати (формат адресного ярлыка) (PrintType)
  • Категория вложения (MailEntryType)
  • Коды видов сервиса ECOM (EcomService)
  • Тип объекта в паспорте ОПС (OpsType)
  • Типоразмер РПО (DimensionType)
  • Способ идентификации получателя ECOM (EcomIdentityMethod)
  • Способ расчета (PaymentMode54FZ)
  • Предмета расчета (PaymentSubject54FZ)
  • Продукты
  • Коды отметок внутренних и международных отправлений
  • Тип операции из трекинга
  • Атрибут операции из трекинга
  • Страны
  • Валюты
  • Статус заявки на вызов курьера
  • Тип пункта выдачи

Валидация

  • Ошибки партий (BatchError)
  • Ошибки удаления из бэклога (RemoveBacklogErrorCode)
  • Ошибки удаления из партии (RemoveFromBatchErrorCode)
  • Ошибки валидации заказа (OrderValidationError)
  • Ошибки тарификации (TariffErrorCode)

Трекинг

Ваш SDK еще живой?

Все привет, реально ли ваш АПИ использовать в проекте, где надо общаться с АПИ почты России?

Реализация API Отправки

Данные

  • Нормализация ФИО
  • Нормализация адреса
  • Нормализация телефона
  • Расчёт стоимости
  • Неблагонадёжный получатель
  • Отображение баланса

Настройки

  • Текущие настройки пользователя

Заказы

  • Создание
  • Поиск по идентификатору магазина
  • Поиск по идентификатору Почты России
  • Редактирование
  • Удаление
  • Возврат в «Новые»

Партии

  • Создание партии заказов
  • Изменение дня отправки партии в ОПС
  • Перенос заказов в партию
  • Добавление заказов в партию
  • Удаление заказов из партии
  • Запрос данных о заказах в партии
  • Поиск партии по наименованию
  • Поиск всех партий
  • Поиск заказов по ШПИ
  • Поиск заказа по идентификатору Почты России

Документы

  • Генерация документов для партии
  • Генерация документов для заказа
  • Генерация акта осмотра содержимого
  • Генерация Ф7п
  • Генерация Ф112ЭК
  • Генерация Ф103
  • Подготовка и отправка электронной формы Ф103
  • Генерация возвратного ярлыка на одной печатной странице

Архив

  • Запрос данных о партиях
  • Перевод партии в архив
  • Возврат партии из архива

Поиск ОПС

  • По индексу
  • По адресу
  • По координатам
  • Поиск индексов в населённом пункте
  • Почтовые сервисы ОПС
  • Почтовые сервисы ОПС по идентификатору группы сервисов
  • Выгрузка информации об объектах почтовой связи в zip-архиве

Долгосрочное хранение

  • Запрос данных о заказах

Как будем получать свойства объектов

Как будем получать свойства объектов?

Почти все свойства в API содержат тире в названии

"location-to": "string",
"mail-category": "SIMPLE",
"mail-type": "UNDEFINED",
"manual-address-input": true

Поскольку мы не можем сделать $order->mail-category, то варианты такие:

//либо маппить названия к варианту с подчеркиванием
["mail-category"=>"mail_category"]
$order->mail_category

//либо реализовать доступ так
$order["mail-category"]

//либо не париться совсем
$order->{'mail-category'}

У кого какие пристрастия?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.