Skip to content

Commit

Permalink
Merge pull request #3 from mtcmedia/ship-v10
Browse files Browse the repository at this point in the history
PSR12 and  Shipment api update to V10
  • Loading branch information
MaFx authored Jun 17, 2021
2 parents 68cff7a + 71420fc commit 1d7cd30
Show file tree
Hide file tree
Showing 121 changed files with 868 additions and 401 deletions.
7 changes: 7 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Change Log

v1.0.0 - Initial refactoring to DHL v6.2 for Shipment Validation

v1.0.1 - Fixed issues with Route Requests

v2.0.0 - Updated Shipment Validation to DHL v10
7 changes: 6 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
"name": "mtcmedia/dhl-api",
"description": "PHP library to communicate with the DHL XML Services.",
"require": {
"php": ">=7.0"
"php": ">=7.1",
"ext-xmlwriter": "*",
"ext-curl": "*"
},
"require-dev": {
"squizlabs/php_codesniffer": "^3.5"
},
"license": "MIT",
"autoload": {
Expand Down
197 changes: 150 additions & 47 deletions docs/shipment.md
Original file line number Diff line number Diff line change
@@ -1,100 +1,203 @@
Example request:

```php
use Mtc\Dhl\Client\Web;
use Mtc\Dhl\Datatype\AM\DocImage;
use Mtc\Dhl\Datatype\EU\AdditionalProtection;
use Mtc\Dhl\Datatype\EU\ExportLineItem;
use Mtc\Dhl\Datatype\EU\GrossWeight;
use Mtc\Dhl\Datatype\EU\Piece;
use Mtc\Dhl\Datatype\EU\RegistrationNumber;
use Mtc\Dhl\Datatype\EU\SpecialService;
use Mtc\Dhl\Datatype\EU\Weight;
use Mtc\Dhl\Entity\EU\ShipmentRequest;

$shipment = new ShipmentRequest();
$shipment->SiteID = $order->auth->account_number;
$shipment->Password = $order->auth->password;
$shipment->MessageTime = Carbon::now()->format(Carbon::ATOM);
$shipment->MessageReference = substr($reference, 0, 30);
$shipment->LanguageCode = 'en';
$shipment->PiecesEnabled = 'Y';
$shipment->Reference->ReferenceID = $client->account . '-' . $order->id;
$shipment->Reference->ReferenceID = $reference_prefix . '-' . $order->id;

$shipment->SoftwareName = '3PV';
$shipment->SoftwareVersion = '6.2';

$shipment->Billing->ShipperAccountNumber = $order->auth->shipper_account;
$shipment->Billing->ShippingPaymentType = 'S';
$shipment->Billing->BillingAccountNumber = $order->auth->billing_account;

// Outside EU changes Tax info
if (!Country::isEu($shipping_address->country)) {
$shipment->Billing->DutyPaymentType = 'R';
$contact_name = $order->address->shipping->first_name . ' ' . $order->address->shipping->last_name;
$shipment->Consignee->CompanyName = $order->address->shipping->organisation ?? $contact_name;
$shipment->Consignee->Contact->PersonName = $contact_name;
$shipment->Consignee->AddressLine1 = substr($order->address->shipping->address1, 0, 35);
if (!empty($order->address->shipping->address2)) {
$shipment->Consignee->AddressLine2 = substr($order->address->shipping->address2, 0, 35);
}
$shipment->Consignee->City = $order->address->shipping->city;
$shipment->Consignee->PostalCode = $order->address->shipping->postcode;
if (!empty($order->address->shipping->state)) {
$shipment->Consignee->Division = $order->address->shipping->state ?? '';
$shipment->Consignee->DivisionCode = $order->address->shipping->state ?? '';
}

$contact_name = $shipping_address->first_name . ' ' . $shipping_address->last_name;
$shipment->Consignee->CompanyName = $shipping_address->organisation ?? '--';
$shipment->Consignee->Contact->PersonName = $contact_name;
$shipment->Consignee->addAddressLine(substr($shipping_address->address1, 0, 35));
$shipment->Consignee->addAddressLine(substr($shipping_address->address2, 0, 35));
$shipment->Consignee->City = $shipping_address->city;
$shipment->Consignee->PostalCode = $shipping_address->postcode;
$shipment->Consignee->Division = $shipping_address->state ?? '';
$shipment->Consignee->CountryCode = $shipping_address->country;
$shipment->Consignee->CountryName = Country::getNameFromCode($shipping_address->country);
if (!empty($order->address->shipping->tax_id)) {
$shipment->Consignee->FederalTaxId = $order->address->shipping->tax_id;
}

$shipment->Consignee->CountryCode = $order->address->shipping->country;
$shipment->Consignee->CountryName = Country::getNameFromCode($order->address->shipping->country);
$shipment->Consignee->Contact->PhoneNumber = $order->info->contact_no;
$shipment->Consignee->Contact->Email = $order->info->email;
$shipment->Consignee->Contact->PhoneExtension = '';
$shipment->Consignee->Contact->FaxNumber = '';
$shipment->Consignee->Contact->Telex = '';
$shipment->RegionCode = Country::getDHLRegionCode($shipping_address->country);
$shipment->Consignee->Contact->MobilePhoneNumber = $order->info->contact_no;
$shipment->RegionCode = Country::getDHLRegionCode($order->address->shipping->country);
$shipment->Shipper->BusinessPartyTypeCode = 'DC';

$order_value = $order->order_cost - $order->delivery_cost > 0 ? $order->order_cost - $order->delivery_cost : 1.0;
$shipment->Dutiable->DeclaredValue = $order_value;
$order_value = $this->getOrderValue($order);
$shipment->Dutiable->DeclaredValue = number_format($order_value, 2, '.', '');
$shipment->Dutiable->DeclaredCurrency = 'GBP';
$shipment->Dutiable->TermsOfTrade = 'DDP';
$shipment->Dutiable->TermsOfTrade = $this->termsOfTrade($order);

$special_service_type = $this->getSpecialServiceType($order);

if ($special_service_type) {
$special_service = new SpecialService();
$special_service->SpecialServiceType = $special_service_type;
$shipment->SpecialService = $special_service;
}
// DocImage is required for paperless
if ($special_service_type === 'WY') {
$image = new DocImage();
$image->Type = 'INV';
$image->Image = $order->invoice;
$image->ImageFormat = 'PDF';
$shipment->addDocImage($image);
}
$shipment->Shipper->ShipperID = $order->auth->shipper_id;
$shipment->Shipper->RegisteredAccount = $order->auth->shipper_account_number;
$shipment->Shipper->CompanyName = $collection_address->organisation;
$shipment->Shipper->addAddressLine($collection_address->address1);
$shipment->Shipper->addAddressLine($collection_address->address2);
$shipment->Shipper->City = $collection_address->city;
$shipment->Shipper->PostalCode = $collection_address->postcode;
$shipment->Shipper->CountryCode = $collection_address->country;
$shipment->Shipper->CountryName = Country::getNameFromCode($collection_address->country);

$shipment->Shipper->Contact->PersonName = $collection_address->contact_name;
$shipment->Shipper->Contact->PhoneNumber = $collection_address->contact_phone;
$shipment->Shipper->Contact->Email = $collection_address->contact_email;
$shipment->Shipper->CompanyName = $order->address->collection->organisation;
$shipment->Shipper->AddressLine1 = $order->address->collection->address1;
if (!empty($order->address->collection->address2)) {
$shipment->Shipper->AddressLine2 = $order->address->collection->address2;
}
$shipment->Shipper->City = $order->address->collection->city;
if ($order->address->collection->country === 'GB') {
$shipment->Shipper->PostalCode = $this->normalizeUkPostcode($order->address->collection->postcode);
} else {
$shipment->Shipper->PostalCode = $order->address->collection->postcode;
}
$shipment->Shipper->CountryCode = $order->address->collection->country;
$shipment->Shipper->CountryName = Country::getNameFromCode($order->address->collection->country);

$shipment->Shipper->Contact->PersonName = $order->address->collection->contact_name;
$shipment->Shipper->Contact->PhoneNumber = $order->address->collection->contact_phone;
$shipment->Shipper->Contact->Email = $order->address->collection->contact_email;
$shipment->Shipper->Contact->PhoneExtension = '';
$shipment->Shipper->Contact->FaxNumber = '';
$shipment->Shipper->Contact->Telex = '';
$shipment->Shipper->Contact->MobilePhoneNumber = $order->address->collection->contact_phone;

// Delivery Service is obtained via Quote request which will find valid services for shipment
if (!empty($order->courier->registration_number)) {
$registration_number = new RegistrationNumber();
$registration_number->Number = $order->courier->registration_number;
$registration_number->NumberTypeCode = $order->courier->registration_number_type;
$registration_number->NumberIssuerCountryCode = $order->courier->registration_number_country;
$shipment->Shipper->addRegistrationNumber($registration_number);
}
$shipment->Shipper->BusinessPartyTypeCode = 'BU';

$delivery_service = $this->getDeliveryService($client, $order);
$shipment->ShipmentDetails->GlobalProductCode = $delivery_service->code;
$shipment->ShipmentDetails->LocalProductCode = $delivery_service->format;

if (Country::isEu($shipping_address->country) === false) {
$shipment->ShipmentDetails->DoorTo = 'DD';
}
$shipment->ShipmentDetails->Contents = 'Shipment Description';
$shipment->ShipmentDetails->Contents = $order->description ?? '';
$shipment->ShipmentDetails->CurrencyCode = 'GBP';
$shipment->ShipmentDetails->WeightUnit = 'K';
$shipment->ShipmentDetails->Weight = collect($packages)->sum('weight');
$shipment->ShipmentDetails->Date = Carbon::now()->format('Y-m-d');
$shipment->ShipmentDetails->DimensionUnit = 'C';
$shipment->ShipmentDetails->InsuredAmount = $order->insurance_total ?? 0;
$shipment->ShipmentDetails->InsuredAmount = !empty($order->insurance_total) ? $order->insurance_total : 0;
$shipment->ShipmentDetails->PackageType = $order->package_type ?? 'PA';
$shipment->ShipmentDetails->IsDutiable = Country::isEu($shipping_address->country) ? 'Y' : 'N';

$shipment->ShipmentDetails->IsDutiable = $this->is_dutiable_shipment ? 'Y' : 'N';
// paperless needs IsDutiable set to 'Y'
if ($special_service_type === 'WY') {
$shipment->ShipmentDetails->IsDutiable = 'Y';
}
$shipment->ShipmentDetails->AdditionalProtection = new AdditionalProtection();
$shipment->ShipmentDetails->DOSFlag = 'N';
$shipment->ShipmentDetails->CustData = $contact_name;

$shipment->DHLInvoiceType = 'CMI';
if (!empty($order->invoice_date)) {
$shipment->ExportDeclaration->InvoiceDate = $order->invoice_date;
}
if (!empty($order->invoice_number)) {
$shipment->ExportDeclaration->InvoiceNumber = (string)$order->invoice_number;
}
$shipment->ExportDeclaration->ExportReason = 'Sales';
$shipment->ExportDeclaration->ExportReasonCode = 'P';
$shipment->ExportDeclaration->ShipmentPurpose = 'PERSONAL';
$shipment->ExportDeclaration->InvoiceTotalGrossWeight = collect($packages)->sum('weight');
$shipment->ExportDeclaration->PlaceOfIncoterm = $order->address->shipping->city;

foreach ($order->items as $index => $item) {
$export_item = new ExportLineItem();
$export_item->LineNumber = $index + 1;
$export_item->Value = $item->price;
$export_item->Quantity = $item->quantity;
$export_item->QuantityUnit = 'PCS';
$weight = new Weight();
$weight->Weight = $item->weight;
$weight->WeightUnit = 'K';
$export_item->Weight = $weight;
$weight = new GrossWeight();
$weight->Weight = $item->weight;
$weight->WeightUnit = 'K';
$export_item->GrossWeight = $weight;
$export_item->Description = $item->name;

if (!empty($item->manufacture_country)) {
$export_item->ManufactureCountryCode = $item->manufacture_country;
}
if (!empty($item->commodity_code)) {
$export_item->CommodityCode = $item->commodity_code;
}
if (!empty($item->import_commodity_code)) {
$export_item->ImportCommodityCode = $item->import_commodity_code;
}

$shipment->ExportDeclaration->addExportLineItem($export_item);
}

// Information about Packages in shipment
$shipment->ShipmentDetails->NumberOfPieces = count($packages);
foreach ($packages as $package_id => $package) {
$piece = new Piece();
$piece->PieceID = $client->account . $order->id . $package_id;
$piece->PackageType = $order->package_type ?? 'CP';
$piece->PackageType = $order->package_type ?? 'PA';
$piece->Weight = $package['weight'];
$piece->DimWeight = $package['weight'];
$piece->Width = $package['width'];
$piece->Height = $package['height'];
$piece->Depth = $package['length'];
$piece->PieceContents = $package['contents'];
$shipment->ShipmentDetails->addPiece($piece);
}

$shipment->EProcShip = 'N';
$shipment->LabelImageFormat = 'PDF';
$shipment->Label->LabelTemplate = '8X4_PDF';

$client = new Web($this->getEnvironment());
$xml_response = $client->call($shipment);
switch (strtolower($order->courier->label_format)) {
case 'zpl':
$shipment->LabelImageFormat = 'ZPL2';
$shipment->Label->LabelTemplate = '8X4_thermal';
break;
case 'pdf':
default:
$shipment->LabelImageFormat = 'PDF';
$shipment->Label->LabelTemplate = '8X4_PDF';
}

$api_client = new Web($this->getEnvironment());
$xml_response = $api_client->call($shipment);
```

If you need XML request for the DHL certification you can obtain by calling the following code
Expand Down
10 changes: 8 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Package should be installed through composer:
composer require mtcmedia/dhl-api
```

Package requires a php min version of 7.0, however it has has been developed and tested on php 7.2.*
Package requires a php min version of 7.1, however it has has been developed and tested on php 7.2.*

## Usage

Expand All @@ -28,12 +28,18 @@ DHL XML Services Test server for customer certification: https://xmlpitest-ea.dh

[Route Requests (v1.0)](docs/route.md)

[Shipment Requests (v6.2)](docs/shipment.md)
[Shipment Requests (v10.0)](docs/shipment.md)

[Pickup Request (v1.0)](docs/pickup.md)

[Tracking Requests (v1.0)](docs/tracking.md)

# Changelog

v1.x - uses Shipment API v6.2

v2.x - uses Shipment API v10.0


## Contributing

Expand Down
20 changes: 10 additions & 10 deletions src/Client/Web.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ class Web
* Url to services
* @var string
*/
private $_stagingUrl = 'https://xmlpitest-ea.dhl.com/XMLShippingServlet?isUTF8Support=true';
private $stagingUrl = 'https://xmlpitest-ea.dhl.com/XMLShippingServlet?isUTF8Support=true';

/**
* Url to services
* @var string
*/
private $_productionUrl = 'https://xmlpi-ea.dhl.com/XMLShippingServlet?isUTF8Support=true';
private $productionUrl = 'https://xmlpi-ea.dhl.com/XMLShippingServlet?isUTF8Support=true';

/**
* Use production server or staging
* @var string
*/
protected $_mode = 'staging';
protected $mode = 'staging';

/**
* Class constructor
Expand All @@ -35,9 +35,10 @@ class Web
public function __construct($mode = 'staging')
{
if (!in_array($mode, array('staging', 'production'))) {
throw new \InvalidArgumentException('Invalid mode : ' . $mode . '. Accepted values are : staging or production.');
$message = 'Invalid mode : ' . $mode . '. Accepted values are : staging or production.';
throw new \InvalidArgumentException($message);
}
$this->_mode = $mode;
$this->mode = $mode;
}

/**
Expand All @@ -54,17 +55,16 @@ public function call(Request $request)
}

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $this->_getUrl());
curl_setopt($ch, CURLOPT_URL, $this->getUrl());
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_PORT, 443);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request->toXML());
$result = curl_exec($ch);

if (curl_error($ch)) {
return false;
} else {
curl_close($ch);
}
curl_close($ch);

return $result;
}
Expand All @@ -74,8 +74,8 @@ public function call(Request $request)
*
* @return string URL for the service
*/
private function _getUrl()
private function getUrl()
{
return ('staging' == $this->_mode) ? $this->_stagingUrl : $this->_productionUrl;
return ('staging' === $this->mode) ? $this->stagingUrl : $this->productionUrl;
}
}
2 changes: 1 addition & 1 deletion src/Datatype/AM/AWBInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class AWBInfo extends Base
* Is this object a subobject
* @var boolean
*/
protected $_isSubobject = true;
protected $isSubobject = true;

/**
* Parameters of the datatype
Expand Down
2 changes: 1 addition & 1 deletion src/Datatype/AM/BarCodes.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class BarCodes extends Base
* Is this object a subobject
* @var boolean
*/
protected $_isSubobject = true;
protected $isSubobject = true;

/**
* Parameters of the datatype
Expand Down
2 changes: 1 addition & 1 deletion src/Datatype/AM/Billing.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Billing extends Base
* Is this object a subobject
* @var boolean
*/
protected $_isSubobject = true;
protected $isSubobject = true;

/**
* Parameters of the datatype
Expand Down
Loading

0 comments on commit 1d7cd30

Please sign in to comment.