t3ko/dpd-pl-api-php

PHP DPD API客户端

0.4 2021-02-06 19:28 UTC

This package is auto-updated.

Last update: 2024-09-29 03:52:46 UTC


README

PHP语言编写的DPD快递公司API客户端,用于与以下Web服务进行通信:

  • PackageService (注册包裹、打印标签和交货协议、预约快递员上门取件)
  • AppService (处理第三方收件订单)
  • InfoService (跟踪包裹)

安装

最简单的方法是使用Composer安装(https://composer.php.ac.cn)。

通过composer.json文件

{
    "require": {
        "t3ko/dpd-pl-api-php": "^0"
    }
}

或使用命令行

composer require t3ko/dpd-pl-api-php

该库使用httplug作为HTTP客户端的抽象,不包含任何默认实现。在包含该库的项目中,负责提供符合PSR-18的HTTP客户端。更多信息请参阅:http://docs.php-http.org/en/latest/httplug/users.html

如果您的项目已经包含支持httplug的HTTP客户端(http://docs.php-http.org/en/latest/clients.html),则只需与库一起安装相应的适配器即可。

例如,对于curl

composer require php-http/curl-client:^1 t3ko/dpd-pl-api-php

如果您的代码中还没有兼容的HTTP客户端,则必须同时安装客户端和适配器。

例如,guzzle

composer require php-http/guzzle6-adapter:^1 guzzlehttp/guzzle:~6.0 t3ko/dpd-pl-api-php

使用

使用方法

要使用DPD API正确发送包裹,需要执行以下步骤(以下部分将详细说明):

  1. 注册包裹(方法generatePackageNumbers()

    将包裹的物理数据、寄件人和收件人的数据以及额外订购的服务(例如取件、送货保证等)发送到该方法。作为响应,我们获得每个包裹分配的运单号。

  2. 生成包裹标签(方法generateLabels()

    将上一步骤中获得的运单号发送到该方法,将获得包含标签的PDF文件,用于粘贴到包裹上。

  3. 生成交货协议(方法generateProtocol()

    与上述方法类似,将需要一起发送的运单号传递给该方法。作为响应,API返回一个PDF文件,其中包含为快递员准备的交货协议。

  4. 检查快递员在指定发货日期的可用性(方法getCourierAvailability()

    该方法在发送寄件地点的邮编后,将返回快递员在接下来的几天内的可用时间段。

  5. 通过快递员预约取件(待办事项)

    将上面方法返回的日期和时间范围以及取件地点传递给该方法,将获得取件确认。快递员将收集带有标签的包裹,并核对第3步生成的交货协议。

除了上述基本的包裹处理方法外,该库还允许

  • 第三方预约取件
  • 获取配送点列表(待办事项)
  • 跟踪包裹

0. 连接到API

要开始使用API,需要包含以下三个认证参数的数据

  • 用户名
  • 密码
  • FID号码

这些数据是在签订合同并声明希望使用API后从客户经理那里获取的。这些数据用于在本文档开头提到的所有三个网络服务中进行身份验证。

使用API是通过构建以下类的对象 T3ko\Dpd\Api 来实现的

require_once __DIR__.'/vendor/autoload.php';

$login = 'testlogin';
$password = 'testpassword';
$fid = 12345;

$api = new \T3ko\Dpd\Api($login, $password, $fid);

默认情况下,库连接到生产端点,但DPD的大部分API服务还提供测试端点,允许安全地测试自己的代码与网络服务的集成。要启用它们的使用,需要在对象上调用 ApisetSandboxMode 方法

$api->setSandboxMode(true);

从此时起,所有请求都将被引导到测试端点。对于不提供测试版本的服务的尝试,将使用 sandbox 模式结束,将引发 SandboxNotAvailableException 异常。

测试API需要单独的登录数据(这些数据与文档包一起由DPD IT部门提供,客户在申请集成API时提出)。使用生产数据访问测试端点将导致认证错误。

要禁用测试模式,当然可以使用

$api->setSandboxMode(false);

1. 注册包裹

GeneratePackageNumbersRequest

通过方法 generatePackageNumbers 发送包裹编号,该方法接受类型为 GeneratePackageNumbersRequest 的对象作为参数

use \T3ko\Dpd\Request\GeneratePackageNumbersRequest;

/** @var GeneratePackageNumbersRequest $request */
$response = $api->generatePackageNumbers($request);

请求对象是基于传递给工厂方法 fromPackagefromPackages(对于由多个包裹同时发送的请求)的包裹/包裹数据构建的

$singlePackageRequest = GeneratePackageNumbersRequest::fromPackage($package);
$multiplePackagesRequest = GeneratePackageNumbersRequest::fromPackages([$package1, $package2]);

Package

构建上述请求的加密是类型为 Package 的对象,其中包含包裹的配置。构建它需要至少三个数据 -发送者对象 Sender、接收者对象 Receiver 以及一个或多个表示组成包裹的物理包裹的 Parcel 类的实例。下面是一个创建 Package 对象的示例代码

use T3ko\Dpd\Objects\Sender;
use T3ko\Dpd\Objects\Receiver;
use T3ko\Dpd\Objects\Parcel;
use T3ko\Dpd\Objects\Package;

$sender = new Sender(12345, 501100100, 'Jan Kowalski', 'Puławska 1', '02566', 'Warszawa', 'PL');
$receiver = new Receiver(605600600, 'Piotr Nowak', 'Kwiatowa 2', '60814', 'Poznań', 'PL');

$parcel = new Parcel(30, 30, 15, 1.5);

$package = new Package($sender, $receiver, [$parcel]);

SenderReceiver 对象以类似的方式初始化,使用地址数据和必填的电话号码。此外,还将向 Sender 对象传递用于登录的 FID 号码(该API假定包裹的发送者是API客户)

$sender = new Sender(
    $fid,          //numer FID
    $phone,        //telefon
    $name,         //imię i nazwisko
    $address,      //adres
    $postalCode,   //kod pocztowy
    $city,         //miasto
    $countryCode,  //kod kraju
    $company,      //nazwa firmy (opcjonalnie)
    $email         //email (opcjonalnie)
    );
    
$receiver = new Receiver(
    $phone,        //telefon
    $name,         //imię i nazwisko
    $address,      //adres
    $postalCode,   //kod pocztowy
    $city,         //miasto
    $countryCode,  //kod kraju
    $company,      //nazwa firmy (opcjonalnie)
    $email         //email (opcjonalnie)
    );

Parcel 对象是按照以下方式构建的

$parcel = new Parcel(
    $sizeX,          //szerokość w cm
    $sizeY,          //wysokość w cm
    $sizeZ,          //głębokość w cm
    $weight,         //masa w kg
    $reference,      //unikalna referencja paczki
    $contents,       //opis zawartości
    $customerNotes   //notatka dla kuriera
    );

GeneratePackageNumbersResponse

generatePackageNumbers 方法返回一个类型为 GeneratePackageNumbersResponse 的对象

/** @var GeneratePackageNumbersResponse $response */
$response = $api->generatePackageNumbers($request);

我们有权访问注册包裹的列表 - RegisteredPackage 类对象的数组

/** @var RegisteredPackage[] $packages */
$packages = $response->getPackages()

在每份包裹中 - 注册包裹的列表,带有分配的运输单号

list($package) = $packages;

/** @var RegisteredParcel[] $parcels */
$parcels = $package->getParcels();
list($parcel) = $parcels;
 
$parcel->getWaybill(); //numer listu przewozowego, np. 0000092494467Q

2. 获取标签

使用方法 generateLabels 打印标签,该方法接受一个类型为 GenerateLabelsRequest 的对象

use \T3ko\Dpd\Request\GenerateLabelsRequest;

/** @var GenerateLabelsRequest $request */
$response = $api->generateLabels($request);

GenerateLabelsRequest

可以以三种方式构建请求对象

  • 使用步骤 1 中生成的运输单号。
use \T3ko\Dpd\Request\GenerateLabelsRequest;

$request = GenerateLabelsRequest::fromWaybills(['0000092494467Q']);
  • 使用步骤 1 中由DPD分配的包裹标识符。
use \T3ko\Dpd\Request\GenerateLabelsRequest;

$parcelId = $parcel->getId();
$request = GenerateLabelsRequest::fromParcelIds([$parcelId]);
  • 或,使用包裹的 reference 字段
use \T3ko\Dpd\Request\GenerateLabelsRequest;

$parcelRef = $parcel->getReference();
$request = GenerateLabelsRequest::fromReferences([$parcelRef]);

(当然,这里的 reference 是我们希望与包裹关联的任意字符串 - 例如,发货订单号等 - 因此,如果在步骤 1 注册包裹时没有传递任何值,则无法使用该字段)

GenerateLabelsResponse

在构建请求并使用 generateLabels 方法将其发送到API后,我们将获得一个类型为 GenerateLabelsResponse 的对象

/** @var GenerateLabelsResponse $response */
$response = $api->generateLabels($request);

在内部,我们有访问 fileContent 字段的权利,该字段包含包含标签的PDF文件二进制数据。下面的示例演示了将标签写入文件 etykieta.pdf

$response = $api->generateLabels($request);

$fp = fopen('etykieta.pdf', 'wb');
fwrite($fp, $response->getFileContent());
fclose($fp)

3. 生成交接协议

为了生成给快递员的交接协议,我们使用方法 generateProtocol

use \T3ko\Dpd\Request\GenerateProtocolRequest;

/** @var GenerateProtocolRequest $request */
$response = $api->generateProtocol($request);

GenerateProtocolRequest

创建请求对象与生成标签的情况类似。在这里,我们也可以通过运输单号、包裹标识符或包裹参考来创建对象,共有三种方法。

use \T3ko\Dpd\Request\GenerateProtocolRequest;

$request = GenerateProtocolRequest::fromWaybills([...]);
$request = GenerateProtocolRequest::fromParcelIds([...]);
$request = GenerateProtocolRequest::fromReferences([...]);

GenerateProtocolResponse

将构建的请求发送到API,我们将收到一个类型为 GenerateProtocolResponse 的对象作为响应,其中包含一个名为 fileContent 的字段,它包含PDF文件的文本内容。

/** @var GenerateLabelsResponse $response */
$response = $api->generateProtocol($request);

$response->getFileContent()); //treść pliku PDF z protokołem przekazania

4. 检查快递员的工作时间

DOC TODO

5. 下单快递员取件

DOC TODO

第三方预约取件

使用 AppService API可以提交一个由第三方取件的请求。为此,需要创建一个或多个描述包裹配置的 Package 对象,就像在常规发送时一样,记住在 $sender 字段中应包含实际向快递员发出包裹的实体的数据,而不是委托取件的!

此外,接收委托的端点仅接受已声明第三方付款(即委托取件的第三方)的 Package 对象

$package->setPayerType(\T3ko\Dpd\Objects\Enum\PayerType::THIRD_PARTY());

以及支付方的FID编号(实际上与我们用于连接API的编号相同)

$package->setThirdPartyFid(123);

CollectionOrderRequest

这样构建的 Package 用于生成 CollectionOrderRequest 对象

use \T3ko\Dpd\Request\CollectionOrderRequest;

$singlePackageRequest = CollectionOrderRequest::fromPackage($package);
$multiplePackagesRequest = CollectionOrderRequest::fromPackages([$package1, $package2]);

通过它我们可以调用API的接收委托方法 - collectionOrder()

use \T3ko\Dpd\Request\CollectionOrderRequest;

/** @var CollectionOrderRequest $request */
$response = $api->collectionOrder($request);

CollectionOrderResponse

我们得到一个类型为 CollectionOrdersResponse 的对象

/** @var CollectionOrderResponse $response */
$response = $api->collectionOrder($request);

其中包含一个列表,列出了成功委托的包裹信息,以 CollectionOrderedPackage 类型的对象的形式呈现

/** @var CollectionOrderedPackage[] $packages */
$packages = $response->getCollectionOrderedPackages();

list($package) = $packages;

$package->getPackageId();   //identyfikator przesyłki nadany przez DPD
$package->getReference();   //ewentualna referencja klienta nadana wiążąca paczkę z obiektem Package przesłanym w requeście
$package->getParcels();     //tablica obiektów typu CollectionOrderedParcel opisujących zlecona paczki tej przeysyłki
$package->getStatusInfo();  //status tego requestu
$package->getOrderNumber(); //numer zlecenia w systemie DPD

而在从 $package->getParcels() 获取的 CollectionOrderedParcel 对象中,记录了由DPD分配的包裹标识符以及该包裹的运输单号

list($parcel) = $package->getParcels();

$parcel->getParcelId(); //identyfikator paczki nadany przez DPD
$parcel->getWaybill();  //numer listu przewozowego dla tej paczki

在此处,第三方取件委托的组装工作完成。无需打印标签并传递给寄件人,或订购快递员 - 这将由DPD自动处理。

跟踪包裹

要获取关于特定包裹的信息,我们可以使用API的 InfoService 通过 getParcelTracking 方法。

use \T3ko\Dpd\Request\GetParcelTrackingRequest;

/** @var GetParcelTrackingRequest $request */
$response = $api->getParcelTracking($request);

GetParcelTrackingRequest

将运输单号传递给此方法来创建请求对象

use \T3ko\Dpd\Request\GetParcelTrackingRequest;

$request = GetParcelTrackingRequest::fromWaybill(...);

可选地,我们可以指定是查看包裹完整的历史记录还是只查看最近记录的事件

use \T3ko\Dpd\Request\GetParcelTrackingRequest;
use T3ko\Dpd\Objects\Enum\TrackingEventsCount;

$request = GetParcelTrackingRequest::fromWaybill('01234567890U', TrackingEventsCount::ALL()); 
$request = GetParcelTrackingRequest::fromWaybill('01234567890U', TrackingEventsCount::ONLY_LAST());

默认值是 TrackingEventsCount::ALL(),即获取包裹历史记录中的所有事件。

GetParcelTrackingResponse

我们得到一个类型为 GetParcelTrackingResponse 的对象

use \T3ko\Dpd\Response\GetParcelTrackingResponse;

/** @var GetParcelTrackingResponse $response */
$response = $api->getParcelTracking($request);

通过 getEvents() 方法,我们可以通过一个包含 ParcelEvent 类型对象的数组来访问,这些对象表示包裹历史中的单个事件。

/** @var GetParcelTrackingResponse $response */
$response = $api->getParcelTracking($request);
foreach ($response->getEvents() as $event) {
    printf("%s - %s - %s - %s - %s (%s %s) (%s) %s",
        $event->getEventTime()->format(DATE_ATOM),  //data zdarzenia
        $event->getWaybill(),                       //numer listu przewozowego
        $event->getPackageReference(),              //dowolne dane powiązane z przesyłką podane przez wysyłającego
        $event->getParcelReference(),               //j.w. związane z pojedynczą paczką
        $event->getCountry(),                       //kod kraju operacji
        $event->getDepot(),                         //numer oddziału DPD 
        $event->getDepotName(),                     //nazwa oddziału DPD
        $event->getBusinessCode(),                  //kod zdarzenia
        $event->getDescription()                    //opis słowny zdarzenia
    );
    $eventAdditionalData = [];
    if (!empty($event->getAdditionalData())) {      //dodatkowe dane zdarzenia
        foreach ($event->getAdditionalData() as $additionalData) {
            $eventAdditionalData[] = $additionalData->getValue();
        }
    }
    if (!empty($eventAdditionalData)) {
        printf(' [%s]', implode(', ', $eventAdditionalData));
    }
    echo "\n";
}

上述调用的示例效果如下

2020-08-26T09:05:18+00:00 - 0123456789012A -  -  - PL (1349 Warszawa3) (190101) Przesyłka doręczona  [Kowalski]
2020-08-26T07:02:15+00:00 - 0123456789012A -  -  - PL (1349 Warszawa3) (170304) Wysłano powiadomienie
2020-08-26T07:01:46+00:00 - 0123456789012A -  -  - PL (1305 Warszawa) (170309) Powiadomienie SMS [+48000000000, DELIVERED]
2020-08-26T06:38:21+00:00 - 0123456789012A -  -  - PL (1305 Warszawa) (170310) Powiadomienie mail [xxx@xxx.pl, SENT]
2020-08-26T06:19:49+00:00 - 0123456789012A -  -  - PL (1349 Warszawa3) (170102) Wydanie przesyłki do doręczenia [LOK9999WAC]
2020-08-26T00:44:23+00:00 - 0123456789012A -  -  - PL (1349 Warszawa3) (330137) Przyjęcie przesyłki w oddziale DPD  [LOK0002WAC]
2020-08-25T16:16:14+00:00 - 0123456789012A -  -  - PL (1320 Piotrków Tryb.) (330135) Przyjęcie przesyłki w oddziale DPD  [LOK0033PTR]
2020-08-25T14:46:29+00:00 - 0123456789012A -  -  - PL (1320 Piotrków Tryb.) (040101) Przesyłka odebrana przez Kuriera
2020-08-24T15:05:48+00:00 - 0123456789012A -  -  -  ( ) (030103) Zarejestrowano dane przesyłki, przesyłka jeszcze nie nadana