<repo_name>talapaillp/dpd.sdk<file_sep>/src/lib/Agents.php
<?php
namespace Ipol\DPD;

use \Ipol\DPD\API\User as API;
use \Ipol\DPD\Config\ConfigInterface;

/**
 * Класс содержит набор готовых методов реализующих выполнение периодических
 * заданий
 */
class Agents
{
	/**
	 * Обновляет статусы заказов
	 * 
	 * Обновление статусов происходит в 2 этапа.
	 * На первом этапе обрабатываются заказы, которые создались в статусе "Ожидают проверки менеджером DPD"
	 * На втором этапе обрабатываются остальные заказы. Для получения изменений по статусам используется 
	 * метод getStatesByClient
	 * 
	 * @param \Ipol\DPD\Config\ConfigInterface $config
	 * 
	 * @return void
	 */
	public static function checkOrderStatus(ConfigInterface $config)
	{
		self::checkPindingOrderStatus($config);
		self::checkTrakingOrderStatus($config);
	}

	/**
	 * Проверяет статусы заказов ожидающих проверки
	 * 
	 * @return void
	 */
	protected static function checkPindingOrderStatus(ConfigInterface $config)
	{
		$table  = \Ipol\DPD\DB\Connection::getInstance($config)->getTable('order');
		$orders = $table->find([
			'where' => 'ORDER_STATUS = :order_status',
			'order' => 'ORDER_DATE_STATUS ASC, ORDER_DATE_CREATE ASC',
			'limit' => '0,2',
			'bind'  => [
				':order_status' => \Ipol\DPD\Order::STATUS_PENDING
			]
		])->fetchAll(PDO::FETCH_CLASS|PDO::FETCH_PROPS_LATE, $table->getModelClass(), $table);
		
		foreach ($orders as $order) {
			$order->dpd()->checkStatus();
		}
	}

	/**
	 * Проверяет статусы заказов прошедшие проверку
	 * 
	 * @return void
	 */
	protected static function checkTrakingOrderStatus(ConfigInterface $config)
	{
		if (!$config->get('STATUS_ORDER_CHECK')) {
			return;
		}

		do {
			$ret = API::getInstanceByConfig($config)->getService('tracking')->getStatesByClient();
			if (!$ret) {
				return;
			}

			$states = (array) $ret['STATES'];
			$states = array_key_exists('DPD_ORDER_NR', $states) ? array($states) : $states;

			// сортируем статусы по их времени наступления
			uasort($states, function($a, $b) {
				if ($a['CLIENT_ORDER_NR'] == $b['CLIENT_ORDER_NR']) {
					$time1 = strtotime($a['TRANSITION_TIME']);
					$time2 = strtotime($b['TRANSITION_TIME']);

					return $time1 - $time2;
				}

				return $a['CLIENT_ORDER_NR'] - $b['CLIENT_ORDER_NR'];
			});

			foreach ($states as $state) {
				$order = \Ipol\DPD\DB\Connection::getInstance($config)->getTable('order')->getByOrderId($state['CLIENT_ORDER_NR']);
				if (!$order) {
					continue;
				}

				$status = $state['NEW_STATE'];
				
				if ($order->isSelfDelivery()
					&& $status == \Ipol\DPD\Order::STATUS_TRANSIT_TERMINAL
					&& $order->receiverTerminalCode == $state['TERMINAL_CODE']
				) {
					$status = \Ipol\DPD\Order::STATUS_ARRIVE;
				}

				$order->setOrderStatus($status, $statusTime);
				$order->orderNum = $state['DPD_ORDER_NR'] ?: $order->orderNum;
				$order->save();
			}

			if ($ret['DOC_ID'] > 0) {
				API::getInstanceByConfig($config)->getService('tracking')->confirm($ret['DOC_ID']);
			}
		} while($ret['RESULT_COMPLETE'] != 1);
	}

	/**
	 * Загружает в локальную БД данные о местоположениях и терминалах
	 * 
	 * @param \Ipol\DPD\Config\ConfigInterface $config
	 * 
	 * @return string
	 */
	public static function loadExternalData(ConfigInterface $config)
	{
		$api = API::getInstanceByConfig($config);

		$locationTable  = \Ipol\DPD\DB\Connection::getInstance($config)->getTable('location');
		$terminalTable  = \Ipol\DPD\DB\Connection::getInstance($config)->getTable('terminal');

		$locationLoader = new \Ipol\DPD\DB\Location\Agent($api, $locationTable);
		$terminalLoader = new \Ipol\DPD\DB\Terminal\Agent($api, $terminalTable);

		$currStep = $config->get('LOAD_EXTERNAL_DATA_STEP');
		$position = $config->get('LOAD_EXTERNAL_DATA_POSITION');

		switch ($currStep) {
			case 'LOAD_LOCATION_ALL':
				$ret      = $locationLoader->loadAll($position);
				$currStep = 'LOAD_LOCATION_ALL';
				$nextStep = 'LOAD_LOCATION_CASH_PAY';

				if ($ret !== true) {
					break;
				}

			case 'LOAD_LOCATION_CASH_PAY':
				$ret      = $locationLoader->loadCashPay($position);
				$currStep = 'LOAD_LOCATION_CASH_PAY';
				$nextStep = 'LOAD_TERMINAL_UNLIMITED';

				if ($ret !== true) {
					break;
				}

			case 'LOAD_TERMINAL_UNLIMITED':
				$ret      = $terminalLoader->loadUnlimited($position);
				$currStep = 'LOAD_TERMINAL_UNLIMITED';
				$nextStep = 'LOAD_TERMINAL_LIMITED';

				if ($ret !== true) {
					break;
				}

			case 'LOAD_TERMINAL_LIMITED':
				$ret      = $terminalLoader->loadLimited($position);
				$currStep = 'LOAD_TERMINAL_LIMITED';
				$nextStep = 'LOAD_FINISH';

				if ($ret !== true) {
					break;
				}
			
			default:
				$ret      = true;
				$currStep = 'LOAD_FINISH';
				$nextStep = 'LOAD_LOCATION_ALL';
			break;
		}

		$nextStep = is_bool($ret) ? $nextStep : $currStep;
		$position = is_bool($ret) ? ''        : $ret;

		$config->set('LOAD_EXTERNAL_DATA_STEP', $nextStep);
		$config->set('LOAD_EXTERNAL_DATA_POSITION', $position);
	}
}<file_sep>/src/lib/DB/Order/Model.php
<?php
namespace Ipol\DPD\DB\Order;

use \Ipol\DPD\Order as DpdOrder;
use \Ipol\DPD\DB\Model as BaseModel;
use \Ipol\DPD\Shipment;

/**
 * Модель одной записи таблицы заказов
 */
class Model extends BaseModel
{
	const SERVICE_VARIANT_D = 'Д';
	const SERVICE_VARIANT_T = 'Т';
	
	/**
	 * Отправление
	 * @var \Ipol\DPD\Shipment
	 */
	protected $shipment;

	/**
	 * Возвращает список статусов и их описаний
	 * 
	 * @return array
	 */
	public static function StatusList()
	{
		return array(
			DpdOrder::STATUS_NEW              => 'Новый заказ, еще не отправлялся в DPD',
			DpdOrder::STATUS_OK               => 'Успешно создан',
			DpdOrder::STATUS_PENDING          => 'Принят, но нуждается в ручной доработке сотрудником DPD',
			DpdOrder::STATUS_ERROR            => 'Не принят, ошибка',
			DpdOrder::STATUS_CANCEL           => 'Заказ отменен',
			DpdOrder::STATUS_CANCEL_PREV      => 'Заказ отменен ранее',
			DpdOrder::STATUS_NOT_DONE         => 'Заказ отменен в процессе доставки',
			DpdOrder::STATUS_DEPARTURE        => 'Посылка находится на терминале приема отправления',
			DpdOrder::STATUS_TRANSIT          => 'Посылка находится в пути (внутренняя перевозка DPD)',
			DpdOrder::STATUS_TRANSIT_TERMINAL => 'Посылка находится на транзитном терминале',
			DpdOrder::STATUS_ARRIVE           => 'Посылка находится на терминале доставки',
			DpdOrder::STATUS_COURIER          => 'Посылка выведена на доставку',
			DpdOrder::STATUS_DELIVERED        => 'Посылка доставлена получателю',
			DpdOrder::STATUS_LOST             => 'Посылка утеряна',
			DpdOrder::STATUS_PROBLEM          => 'C посылкой возникла проблемная ситуация',
			DpdOrder::STATUS_RETURNED         => 'Посылка возвращена с курьерской доставки',
			DpdOrder::STATUS_NEW_DPD          => 'Оформлен новый заказ по инициативе DPD',
			DpdOrder::STATUS_NEW_CLIENT       => 'Оформлен новый заказ по инициативе клиента',
		);
	}

	/**
	 * Возвращает отправку
	 *
	 * @param bool $forced true - создает новый инстанс на основе полей записи
	 * 
	 * @return \Ipol\DPD\Shipment
	 */
	public function getShipment($forced = false)
	{
		if (is_null($this->shipment) || $forced) {
			$this->shipment = new Shipment($this->getTable()->getConfig());
			$this->shipment->setSender($this->senderLocation);
			$this->shipment->setReceiver($this->receiverLocation);
			$this->shipment->setPaymentMethod($this->personeTypeId, $this->paySystemId);
			$this->shipment->setItems($this->orderItems, $this->sumNpp);

			list($selfPickup, $selfDelivery) = array_values($this->getServiceVariant());
			$this->shipment->setSelfPickup($selfPickup);
			$this->shipment->setSelfDelivery($selfDelivery);

			if ($this->isCreated()) {
				$this->shipment->setWidth($this->dimensionWidth);
				$this->shipment->setHeight($this->dimensionHeight);
				$this->shipment->setLength($this->dimensionLength);
				$this->shipment->setWeight($this->cargoWeight);
			}
		}

		return $this->shipment;
	}

	/**
	 * Ассоциирует внешнюю отправку с записью
	 * Происходит заполнение полей записи на основе данных отправки
	 * 
	 * @param \Ipol\DPD\Shipment $shipment
	 * 
	 * @return self
	 */
	public function setShipment(Shipment $shipment)
	{
		$this->shipment         = $shipment;
		$this->senderLocation   = $shipment->getSender()['ID'];
		$this->receiverLocation = $shipment->getReceiver()['ID'];
		$this->cargoWeight      = $shipment->getWeight();
		$this->cargoVolume      = $shipment->getVolume();
		$this->dimensionWidth   = $shipment->getWidth();
		$this->dimensionWidth   = $shipment->getHeight();
		$this->dimensionLength  = $shipment->getLength();
		$this->personeTypeId    = $shipment->getPaymentMethod()['PERSONE_TYPE_ID'];
		$this->paySystemId      = $shipment->getPaymentMethod()['PAY_SYSTEM_ID'];
		$this->orderItems       = $shipment->getItems();
		$this->price            = $shipment->getPrice();
		$this->serviceVariant   = [
			'SELF_PICKUP'   => $shipment->getSelfPickup(),
			'SELF_DELIVERY' => $shipment->getSelfDelivery(),
		];

		return $this;
	}

	/**
	 * Сеттер св-ва ORDER_ITEMS
	 * 
	 * @param array $items
	 */
	public function setOrderItems($items)
	{
		$this->fields['ORDER_ITEMS'] = \serialize($items);

		return $this;
	}

	/**
	 * Геттер св-ва ORDER_ITEMS
	 * 
	 * @return array
	 */
	public function getOrderItems()
	{
		return \unserialize($this->fields['ORDER_ITEMS']);
	}

	/**
	 * Сеттер св-ва NPP
	 * 
	 * @param float $npp
	 * 
	 * @return self
	 */
	public function setNpp($npp)
	{
		$this->fields['NPP']     = $npp;
		$this->fields['SUM_NPP'] = $npp == 'Y' ? $this->price : 0;

		return $this;
	}

	/**
	 * Устанавливает вариант доставки
	 *
	 * @param string $variant
	 * 
	 * @return self
	 */
	public function setServiceVariant($variant)
	{
		$D = self::SERVICE_VARIANT_D;
		$T = self::SERVICE_VARIANT_T;

		if (is_string($variant) && preg_match('~^('. $D .'|'. $T .'){2}$~sUi', $variant)) {
			$this->fields['SERVICE_VARIANT'] = $variant;
		} else if (is_array($variant)) {
			$selfPickup   = $variant['SELF_PICKUP'];
			$selfDelivery = $variant['SELF_DELIVERY'];
		
			$this->fields['SERVICE_VARIANT'] = ''
				. ($selfPickup   ? $T : $D)
				. ($selfDelivery ? $T : $D)
			;
		}

		return $this;
	}

	/**
	 * Возвращает вариант доставки
	 *
	 * @return array
	 */
	public function getServiceVariant()
	{
		$D = self::SERVICE_VARIANT_D;
		$T = self::SERVICE_VARIANT_T;

		return array(
			'SELF_PICKUP'   => mb_substr($this->fields['SERVICE_VARIANT'], 0, 1) == $T,
			'SELF_DELIVERY' => mb_substr($this->fields['SERVICE_VARIANT'], 1, 1) == $T,
		);
	}

	/**
	 * Возвращает флаг доставка от ТЕРМИНАЛА или ДВЕРИ
	 * 
	 * @return bool
	 */
	public function isSelfPickup()
	{
		$serviceVariant = $this->getServiceVariant();
		return $serviceVariant['SELF_PICKUP'];
	}

	/**
	 * Возвращает флаг доставка до ТЕРМИНАЛА или ДВЕРИ
	 * 
	 * @return bool
	 */
	public function isSelfDelivery()
	{
		$serviceVariant = $this->getServiceVariant();
		return $serviceVariant['SELF_DELIVERY'];
	}

	/**
	 * Возвращает текстовое описание статуса заказа
	 *
	 * @return string
	 */
	public function getOrderStatusText()
	{
		$statusList = static::StatusList();
		$ret = $statusList[$this->orderStatus];

		if ($this->orderStatus == DpdOrder::STATUS_ERROR) {
			$ret .= ': '. $this->orderError;
		}

		return $ret;
	}

	/**
	 * Возвращает ифнормацию о тарифе
	 *
	 * @param  bool $forced пересоздать ли экземпляр отгрузки
	 *
	 * @return array
	 */
	public function getTariffDelivery($forced = false)
	{
		return $this->getShipment($forced)->calculator()->calculateWithTariff($this->serviceCode, $this->currency);
	}

	/**
	 * Возвращает стоимость доставки в заказе
	 *
	 * @return float
	 */
	public function getActualPriceDelivery()
	{
		$tariff = $this->getTariffDelivery();
		
		if ($tariff) {
			return $tariff['COST'];
		}

		return false;
	}

	/**
	 * Сеттер для номера заказа, попутно устанавливаем номер отправления
	 *
	 * @param $orderNum
	 * 
	 * @return self
	 */
	public function setOrderNum($orderNum)
	{
		$this->fields['ORDER_NUM']         = $orderNum;
		$this->fields['ORDER_DATE_CREATE'] = $orderNum ? date('Y-m-d H:i:s') : null;

		return $this;
	}

	/**
	 * Сеттер для статуса заказа
	 * 
	 * @param $orderStatus
	 * @param $orderStatusDate
	 * 
	 * @return self
	 */
	public function setOrderStatus($orderStatus, $orderStatusDate = false)
	{
		if (empty($orderStatus)) {
			return;
		}

		if (!array_key_exists($orderStatus, self::StatusList())) {
			return;
		}

		$this->fields['ORDER_STATUS'] = $orderStatus;
		$this->fields['ORDER_DATE_STATUS'] = $orderStatusDate ?: date('Y-m-d H:i:s');

		if ($orderStatus == DpdOrder::STATUS_CANCEL) {
			$this->fields['ORDER_DATE_CANCEL'] = $orderStatusDate ?: date('Y-m-d H:i:s');
		}
	}

	/**
	 * Возвращает флаг новый заказ
	 * 
	 * @return bool
	 */
	public function isNew()
	{
		return $this->fields['ORDER_STATUS'] == DpdOrder::STATUS_NEW;
	}

	/**
	 * Проверяет отправлялся ли заказ в DPD
	 *
	 * @return bool
	 */
	public function isCreated()
	{
		return $this->fields['ORDER_STATUS'] != DpdOrder::STATUS_NEW
			&& $this->fields['ORDER_STATUS'] != DpdOrder::STATUS_CANCEL;
	}

	/**
	 * Проверяет отправлялся ли заказ в DPD и был ли он там успешно создан
	 *
	 * @return bool
	 */
	public function isDpdCreated()
	{
		return $this->isCreated() && !empty($this->fields['ORDER_NUM']);
	}

	/**
	 * Возвращает инстанс для работы с внешним заказом
	 *
	 * @return \Ipol\DPD\Order;
	 */
	public function dpd()
	{
		return new DpdOrder($this);
	}
}<file_sep>/src/lib/DB/Terminal/Model.php
<?php
namespace Ipol\DPD\DB\Terminal;

use \Ipol\DPD\DB\Model as BaseModel;
use Ipol\DPD\Shipment;

/**
 * Модель одной записи таблицы терминалов
 */
class Model extends BaseModel
{
	/**
	 * Проверяет может ли терминал принять посылку
	 * 
	 * @param  \Ipol\DPD\Shipment $shipment
	 * @param  bool               $checkLocation
	 * 
	 * @return bool
	 */
	public function checkShipment(Shipment $shipment, $checkLocation = true)
	{
		if ($checkLocation 
			&& !$this->checkLocation($shipment->getReceiver())
		) {
			return false;
		}

		if ($shipment->isPaymentOnDelivery() 
			&& !$this->checkShipmentPayment($shipment)
		) {
			return false;
		}

		if (!$this->checkShipmentDimessions($shipment)) {
			return false;
		}

		return true;
	}

	/**
	 * Сверяет местоположение терминала и переданного местоположения
	 * 
	 * @param  array  $location
	 * 
	 * @return bool
	 */
	public function checkLocation(array $location)
	{
		return $this->fields['LOCATION_ID'] == $location['CITY_ID'];
	}

	/**
	 * Проверяет возможность принять НПП на терминале
	 * 
	 * @param \Ipol\DPD\Shipment $shipment
	 * 
	 * @return bool
	 */
	public function checkShipmentPayment(Shipment $shipment)
	{
		if ($this->fields['NPP_AVAILABLE'] != 'Y')  {
			return false;
		}

		return $this->fields['NPP_AMOUNT'] >= $shipment->getPrice();
	}

	/**
	 * Проверяет габариты посылки на возможность ее принятия на терминале
	 * 
	 * @param \Ipol\DPD\Shipment $shipment
	 * 
	 * @return bool
	 */
	public function checkShipmentDimessions(Shipment $shipment)
	{
		if ($this->fields['IS_LIMITED'] != 'Y') {
			return true;
		}

		return (
				$this->fields['LIMIT_MAX_WEIGHT'] <= 0
				|| $shipment->getWeight() <= $this->fields['LIMIT_MAX_WEIGHT']
			)

			&& (
				$this->fields['LIMIT_MAX_VOLUME'] <= 0
				|| $shipment->getVolume() <= $this->fields['LIMIT_MAX_VOLUME']
			)

			&& (
				$this->fields['LIMIT_SUM_DIMENSION'] <= 0
				|| array_sum([$shipment->getWidth(), $shipment->getHeight(), $shipment->getLength()]) <= $this->fields['LIMIT_SUM_DIMENSION']
			)
		;
	}
}<file_sep>/examples/create.php
<?php<?php
require __DIR__ .'/../src/autoload.php';

$config = new \Ipol\DPD\Config\Config([
    'KLIENT_NUMBER'   => '',
    'KLIENT_KEY'      => '',
    'KLIENT_CURRENCY' => 'RUB',
    'IS_TEST'         => true,
]);

$shipment = new \Ipol\DPD\Shipment($config);
$shipment->setSender('Россия', 'Москва', 'г. Москва');
$shipment->setReceiver('Россия', 'Тульская область', 'г. Тула');

$shipment->setSelfDelivery(true);
$shipment->setSelfPickup(true);

$shipment->setItems([
    [
        'NAME'       => '<NAME>',
        'QUANTITY'   => 1,
        'PRICE'      => 1000,
        'VAT_RATE'   => 18,
        'WEIGHT'     => 1000,
        'DIMENSIONS' => [
            'LENGTH' => 200,
            'WIDTH'  => 100,
            'HEIGHT' => 50,
        ]
    ],

    [
        'NAME'       => '<NAME>',
        'QUANTITY'   => 1,
        'PRICE'      => 1000,
        'VAT_RATE'   => 18,
        'WEIGHT'     => 1000,
        'DIMENSIONS' => [
            'LENGTH' => 350,
            'WIDTH'  => 70,
            'HEIGHT' => 200,
        ]
    ],

    [
        'NAME'       => '<NAME>',
        'QUANTITY'   => 1,
        'PRICE'      => 1000,
        'VAT_RATE'   => 18,
        'WEIGHT'     => 1000,
        'DIMENSIONS' => [
            'LENGTH' => 220,
            'WIDTH'  => 100,
            'HEIGHT' => 70,
        ]
    ],
], 3000);

$order = \Ipol\DPD\DB\Connection::getInstance($config)->getTable('order')->makeModel();
$order->setShipment($shipment);

$order->orderId = 1;
$order->currency = 'RUB';

$order->serviceCode = 'PCL';

$order->senderName = 'Наименование отправителя';
$order->senderFio = 'ФИО отправителя';
$order->senderPhone = 'Телефон отправителя';
$order->senderTerminalCode = '009M';

$order->receiverName = 'Наименование получателя';
$order->receiverFio = 'ФИО получателя';
$order->receiverPhone = 'Телефон получателя';
$order->receiverTerminalCode = '012K';

$order->pickupDate = '2017-12-02';
$order->pickupTimePeriod = '9-18';

$result = $order->dpd()->create();

print_r($result);<file_sep>/data/db/install/mysql/b_ipol_dpd_location.sql
create table IF NOT EXISTS b_ipol_dpd_location (
	ID int not null auto_increment,
	
	COUNTRY_CODE varchar(255) null,
	COUNTRY_NAME varchar(255) null,
	
	REGION_CODE varchar(255) null,
	REGION_NAME varchar(255) null,
	
	CITY_ID bigint UNSIGNED NOT NULL default '0',
	CITY_CODE varchar(255) null,
	CITY_NAME varchar(255) null,
	CITY_ABBR varchar(255) null,
	
	LOCATION_ID int not null default '0',

	IS_CASH_PAY char(1) not null default 'N',

	ORIG_NAME varchar(255) null,
	ORIG_NAME_LOWER varchar(255) null,

	primary key (ID)
);

CREATE INDEX IF NOT EXISTS b_ipol_dpd_location_crc ON b_ipol_dpd_location (CITY_NAME, REGION_NAME, COUNTRY_NAME);
CREATE INDEX IF NOT EXISTS b_ipol_dpd_location_search_text ON b_ipol_dpd_location (ORIG_NAME_LOWER);<file_sep>/examples/load_terminals.php
<?php
require __DIR__ .'/../src/autoload.php';

$config = new \Ipol\DPD\Config\Config([
    'KLIENT_NUMBER'   => '',
    'KLIENT_KEY'      => '',
    'KLIENT_CURRENCY' => 'RUB',
]);

$table  = \Ipol\DPD\DB\Connection::getInstance($config)->getTable('terminal');
$api    = \Ipol\DPD\API\User\User::getInstanceByConfig($config);

$loader = new \Ipol\DPD\DB\Terminal\Agent($api, $table);
$loader->loadUnlimited();
$loader->loadLimited();
<file_sep>/examples/calculate.php
<?php<?php
require __DIR__ .'/../src/autoload.php';

$config = new \Ipol\DPD\Config\Config([
    'KLIENT_NUMBER'   => '',
    'KLIENT_KEY'      => '',
    'KLIENT_CURRENCY' => 'RUB',
]);

$shipment = new \Ipol\DPD\Shipment($config);
$shipment->setSender('Россия', 'Москва', 'г. Москва');
$shipment->setReceiver('Россия', 'Тульская область', 'г. Тула');

// $shipment->setSelfDelivery(false);
// $shipment->setSelfPickup(false);

$shipment->setItems([
    [
        'NAME'       => '<NAME>',
        'QUANTITY'   => 1,
        'PRICE'      => 1000,
        'VAT_RATE'   => 18,
        'WEIGHT'     => 1000,
        'DIMENSIONS' => [
            'LENGTH' => 200,
            'WIDTH'  => 100,
            'HEIGHT' => 50,
        ]
    ],

    [
        'NAME'       => '<NAME>',
        'QUANTITY'   => 1,
        'PRICE'      => 1000,
        'VAT_RATE'   => 18,
        'WEIGHT'     => 1000,
        'DIMENSIONS' => [
            'LENGTH' => 350,
            'WIDTH'  => 70,
            'HEIGHT' => 200,
        ]
    ],

    [
        'NAME'       => '<NAME>',
        'QUANTITY'   => 1,
        'PRICE'      => 1000,
        'VAT_RATE'   => 18,
        'WEIGHT'     => 1000,
        'DIMENSIONS' => [
            'LENGTH' => 220,
            'WIDTH'  => 100,
            'HEIGHT' => 70,
        ]
    ],
], 3000);

$tariff = $shipment->calculator()->calculate();<file_sep>/examples/cancel.php
<?php<?php
require __DIR__ .'/../src/autoload.php';

$config = new \Ipol\DPD\Config\Config([
    'KLIENT_NUMBER'   => '',
    'KLIENT_KEY'      => '',
    'KLIENT_CURRENCY' => 'RUB',
    'IS_TEST'         => true,
]);

// получить созданный ранее заказ и отменить его
$orderId = 1; // внешний ID заказа
$order = \Ipol\DPD\DB\Connection::getInstance($config)->getTable('order')->getByOrderId($orderId);

$ret = $order->dpd()->cancel();

var_dump($ret);