Skip to content

Commit

Permalink
Merge pull request #28 from AlexisPPLIN/feature/add-service-points
Browse files Browse the repository at this point in the history
Adding service point support
  • Loading branch information
villermen authored Nov 21, 2023
2 parents 49893c6 + 0535cd9 commit a3120d3
Show file tree
Hide file tree
Showing 3 changed files with 399 additions and 2 deletions.
133 changes: 132 additions & 1 deletion src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use JouwWeb\Sendcloud\Model\ShippingMethod;
use JouwWeb\Sendcloud\Model\User;
use JouwWeb\Sendcloud\Model\WebhookEvent;
use JouwWeb\Sendcloud\Model\ServicePoint;
use Psr\Http\Message\RequestInterface;

/**
Expand Down Expand Up @@ -226,7 +227,7 @@ public function createMultiParcel(
?ShippingMethod $shippingMethod = null,
?string $errors = null,
int $quantity = 1
) : array {
): array {
$parcelData = $this->getParcelData(
null,
$shippingAddress,
Expand Down Expand Up @@ -521,6 +522,135 @@ public function getReturnPortalUrl(Parcel|int $parcel): ?string
}
}

/**
* Summary of searchServicePoints
*
* @see https://api.sendcloud.dev/docs/sendcloud-public-api/service-points%2Foperations%2Flist-service-points
* @param string $country A country ISO 2 code (Example : 'NL')
* @param string|null $address Address of the destination address. Can accept postal code instead of the street and the house number. (Example : 'Stadhuisplein 10')
* @param string|null $carrier A comma-separated list of carrier codes (stringified) (Example : 'postnl,dpd')
* @param string|null $city City of the destination address. (Example : 'Eindhoven')
* @param string|null $houseNumber House number of the destination address. (Example : '10')
* @param string|null $latitude Used as a reference point to calculate the distance of the service point to the provided location.
* @param string|null $longitude Used as a reference point to calculate the distance of the service point to the provided location.
* @param string|null $neLatitude Latitude of the northeast corner of the bounding box.
* @param string|null $neLongitude Longitude of the northeast corner of the bounding box.
* @param string|null $postalCode Postal code of the destination address. Using postal_code will return you service points located around that particular postal code. (Example : '5611 EM')
* @param string|null $pudoId DPD-specific query parameter. (<= 7 characters)
* @param int|null $radius Radius (in meter) of a bounding circle. Can be used instead of the ne_latitude, ne_longitude, sw_latitude, and sw_longitude parameters to define a bounding box. By default, it’s 100 meters. Minimum value: 100 meters. Maximum value: 50 000 meters.
* @param string|null $shopType Filters results by their shop type.
* @param string|null $swLatitude Latitude of the southwest corner of the bounding box.
* @param string|null $swLongitude Longitude of the southwest corner of the bounding box.
* @param float|null $weight Weight (in kg.) of the parcel to be shipped to the service points. Certain carriers impose limits for certain service points that cannot accept parcels above a certain weight limit.
* @return ServicePoint[]
*/
public function searchServicePoints(
string $country,
?string $address = null,
?string $carrier = null,
?string $city = null,
?string $houseNumber = null,
?string $latitude = null,
?string $longitude = null,
?string $neLatitude = null,
?string $neLongitude = null,
?string $postalCode = null,
?string $pudoId = null,
?int $radius = null,
?string $shopType = null,
?string $swLatitude = null,
?string $swLongitude = null,
?float $weight = null
): array {
try {
// Construct query array
$query = [];
$query['country_id'] = $country;

if (isset($address)) {
$query['address'] = $address;
}
if (isset($carrier)) {
$query['carrier'] = $carrier;
}
if (isset($city)) {
$query['city'] = $city;
}
if (isset($houseNumber)) {
$query['house_number'] = $houseNumber;
}
if (isset($latitude)) {
$query['latitude'] = $latitude;
}
if (isset($longitude)) {
$query['longitude'] = $longitude;
}
if (isset($neLatitude)) {
$query['ne_latitude'] = $neLatitude;
}
if (isset($neLongitude)) {
$query['ne_longitude'] = $neLongitude;
}
if (isset($postalCode)) {
$query['postal_code'] = $postalCode;
}
if (isset($pudoId)) {
$query['pudo_id'] = $pudoId;
}
if (isset($radius)) {
$query['radius'] = $radius;
}
if (isset($shopType)) {
$query['shop_type'] = $shopType;
}
if (isset($swLatitude)) {
$query['sw_latitude'] = $swLatitude;
}
if (isset($swLongitude)) {
$query['sw_longitude'] = $swLongitude;
}
if (isset($weight)) {
$query['weight'] = $weight;
}

// Send request
$response = $this->guzzleClient->get('service-point', [
'query' => $query,
]);

// Decode and create ServicePoint objects
$json = json_decode((string)$response->getBody(), true);

$servicePoints = [];
foreach ($json as $obj) {
$servicePoints[] = ServicePoint::fromData($obj);
}

return $servicePoints;
} catch (TransferException $exception) {
throw $this->parseGuzzleException($exception, 'Could not retrieve service point.');
}
}

/**
* Returns service point by ID.
*
* @see https://api.sendcloud.dev/docs/sendcloud-public-api/service-points%2Foperations%2Fget-a-service-point
* @return ServicePoint
* @throws SendcloudRequestException
*/
public function getServicePoint(ServicePoint|int $servicePoint): ServicePoint
{
$servicePointId = $servicePoint instanceof ServicePoint ? $servicePoint->getId() : $servicePoint;

try {
$response = $this->guzzleClient->get('service-point/' . $servicePointId);
return ServicePoint::fromData(json_decode((string)$response->getBody(), true));
} catch (TransferException $exception) {
throw $this->parseGuzzleException($exception, 'Could not retrieve service point.');
}
}

/**
* Returns the given arguments as data in Sendcloud parcel format.
*
Expand Down Expand Up @@ -719,6 +849,7 @@ protected function parseGuzzleException(
return new SendcloudRequestException($message, $code, $exception, $responseCode, $responseMessage);
}

// TODO: Remove parseParcelArgument() now we use native unions.
protected function parseParcelArgument(Parcel|int $parcel): int
{
if (is_int($parcel)) {
Expand Down
184 changes: 184 additions & 0 deletions src/Model/ServicePoint.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
<?php

namespace JouwWeb\Sendcloud\Model;

/**
* Implementation of Sendcloud service point object.
*
* @see https://api.sendcloud.dev/docs/sendcloud-public-api/service-points%2Foperations%2Fget-a-service-point
*/
class ServicePoint
{
public static function fromData(array $data): self
{
return new self(
(int)$data['id'],
(string)$data['code'],
(bool)$data['is_active'],
isset($data['shop_type']) ? (string)$data['shop_type'] : null,
(array)$data['extra_data'],
(string)$data['name'],
(string)$data['street'],
(string)$data['house_number'],
(string)$data['postal_code'],
(string)$data['city'],
(string)$data['latitude'],
(string)$data['longitude'],
(string)$data['email'],
(string)$data['phone'],
(string)$data['homepage'],
(string)$data['carrier'],
(string)$data['country'],
(array)$data['formatted_opening_times'],
(bool)$data['open_tomorrow'],
(bool)$data['open_upcoming_week'],
(int)$data['distance']
);
}

/**
* @param array<string, string> $extraData Can contain carrier specific data
* @param array<int, string[]> $formattedOpeningTimes
* @param int $distance Distance between the reference point and the service point in meters.
*/
public function __construct(
protected int $id,
protected string $code,
protected bool $isActive,
protected ?string $shopType,
protected array $extraData,
protected string $name,
protected string $street,
protected string $houseNumber,
protected string $postalCode,
protected string $city,
protected string $latitude,
protected string $longitude,
protected string $email,
protected string $phone,
protected string $homepage,
protected string $carrier,
protected string $country,
protected array $formattedOpeningTimes,
protected bool $openTomorrow,
protected bool $openUpcomingWeek,
protected int $distance,
) {
}

public function getId(): int
{
return $this->id;
}

public function getCode(): string
{
return $this->code;
}

public function isActive(): bool
{
return $this->isActive;
}

public function getShopType(): ?string
{
return $this->shopType;
}

/**
* Can contain carrier specific data.
*
* @return array<string, string>
*/
public function getExtraData(): array
{
return $this->extraData;
}

public function getName(): string
{
return $this->name;
}

public function getStreet(): string
{
return $this->street;
}

public function getHouseNumber(): string
{
return $this->houseNumber;
}

public function getPostalCode(): string
{
return $this->postalCode;
}

public function getCity(): string
{
return $this->city;
}

public function getLatitude(): string
{
return $this->latitude;
}

public function getLongitude(): string
{
return $this->longitude;
}

public function getEmail(): string
{
return $this->email;
}

public function getPhone(): string
{
return $this->phone;
}

public function getHomepage(): string
{
return $this->homepage;
}

public function getCarrier(): string
{
return $this->carrier;
}

public function getCountry(): string
{
return $this->country;
}

/**
* @return array<int, string[]>
*/
public function getFormattedOpeningTimes(): array
{
return $this->formattedOpeningTimes;
}

public function isOpenTomorrow(): bool
{
return $this->openTomorrow;
}

public function isOpenUpcomingWeek(): bool
{
return $this->openUpcomingWeek;
}

/**
* Distance between the reference point and the service point in meters.
*/
public function getDistance(): int
{
return $this->distance;
}
}
Loading

0 comments on commit a3120d3

Please sign in to comment.