Code Monkey home page Code Monkey logo

sendcloud's Introduction

Sendcloud

This is a PHP library that provides a simple way to communicate with the Sendcloud API. It was created because there were no simple alternatives that follow good object-oriented code practices.

NOTE: This library does not implement all Sendcloud API functionality. If you require functionality that is missing please request it through a GitHub issue or pull request.

Example

use JouwWeb\Sendcloud\Client;
use JouwWeb\Sendcloud\Model\Address;
use JouwWeb\Sendcloud\Model\Parcel;
use JouwWeb\Sendcloud\Model\ParcelItem;
use JouwWeb\Sendcloud\Model\WebhookEvent;
use JouwWeb\Sendcloud\Exception\SendcloudRequestException;

$client = new Client('your_public_key', 'your_secret_key');

// Print prices for all enabled shipping methods that ship to the Netherlands
foreach ($client->getShippingMethods() as $shippingMethod) {
    $price = $shippingMethod->getPriceForCountry('NL');
    if ($price) {
        echo $shippingMethod->getName() . ': €' . ($price / 100) . PHP_EOL;
    }
}

// Create a parcel and label
try {
    // Most of these arguments are optional and will fall back to defaults configured in Sendcloud
    $parcel = $client->createParcel(
        shippingAddress: new Address(
            name: 'John Doe',
            companyName: 'Big Box Co.',
            addressLine1: 'Office Street 2834A',
            city: 'Metropolis',
            postalCode: '9999ZZ',
            countryCode: 'NL',
            emailAddress: '[email protected]',
            phoneNumber: '+31612345678'
        ),
        servicePointId: null,
        orderNumber: '20190001',
        weight: 2500, // 2.5kg
        // Below options are only required when shipping outside the EU
        customsInvoiceNumber: 'CI-8329823',
        customsShipmentType: Parcel::CUSTOMS_SHIPMENT_TYPE_COMMERCIAL_GOODS,
        items: [
            new ParcelItem('green tea', 1, 123, 15.20, '090210', 'EC'),
            new ParcelItem('cardboard', 3, 50, 0.20, '090210', 'NL'),
        ],
        postNumber: 'PO BOX 42',
    );

    $parcel = $client->createLabel(
        parcel: $parcel,
        shippingMethod: 8,
        senderAddress: null, // Default sender address.
    );

    $pdf = $client->getLabelPdf($parcel, Parcel::LABEL_FORMAT_A4_BOTTOM_RIGHT);

    var_dump($parcel, $pdf);
} catch (SendcloudRequestException $exception) {
    echo $exception->getMessage();
}

// Verify and parse a webhook request
$webhookEvent = $client->parseWebhookRequest($request);
if ($webhookEvent->getType() === WebhookEvent::TYPE_PARCEL_STATUS_CHANGED) {
    $parcel = $webhookEvent->getParcel();
}

Retieve a list of service points

use JouwWeb\Sendcloud\ServicePointsClient;
use JouwWeb\Sendcloud\Exception\SendcloudRequestException;

$client = new ServicePointsClient('your_public_key', 'your_secret_key');

try {
    // Search for service points in the Netherlands.
    $servicePoints = $client->searchServicePoints('NL');

    var_dump($servicePoints[0]->isActive()); // bool(true)
    var_dump($servicePoints[0]->getName()); // string(7) "Primera"
    var_dump($servicePoints[0]->getCarrier()); // string(6) "postnl"
    var_dump($servicePoints[0]->getDistance()); // NULL ↓

    // If we want Sendcloud to calculate the distance between us and each service point, we need to supply latitude and
    // longitude.
    $servicePointsWithDistance = $client->searchServicePoints(
        country: 'NL',
        latitude: 51.4350511,
        longitude: 5.4746339
    );

    var_dump($servicePointsWithDistance[0]->getName()); // string(14) "Pakketautomaat"
    var_dump($servicePointsWithDistance[0]->getDistance()); // int(553)

    // Obtain a specific service point by ID.
    $servicePoint = $client->getServicePoint(1);
} catch (SendcloudRequestException $exception) {
    echo $exception->getMessage();
}

Installation

composer require jouwweb/sendcloud

sendcloud's People

Contributors

alexispplin avatar ivan-white avatar linaori avatar lukas-jansen avatar odraska avatar roelvanduijnhoven avatar villermen avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

sendcloud's Issues

address_2 is not available for Address Model

We have german "Poststation" addresses and the expected format from sendcloud side is:
Example Address: 21234567 Packstation 123
address: Packstation
address_2: 21234567
house_number: 123

Seems we can not set the Address2 for address and have no influence on the createParcel method.

Why not give an option to add an array with additional data to the Address Model and this will be merged into the data consumed by the createParcel method?

3.8 breaks the parcel create

Seems the signature of API function to create a parcel has changed. In my opinion this should not be included in a 3.8 release without a warning.

createParcel() fails in v3.8.0. A valid number is required for weight.

First of all. Thanks for open-sourcing this.
The package is very helpful.

I am running into the following error when trying to create a parcel using JouwWeb\SendCloud\Client->createParcel().

Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: `POST https://panel.sendcloud.sc/api/v2/parcels` resulted in a `400 Bad Request` response: {"error":{"code":400,"request":"api/v2/parcels","message":"weight: \"A valid number is required.\""}}

As seen on https://github.com/JouwWeb/sendcloud/blob/master/src/Client.php#L520 the weight is being cast to a string. Which is fine according to https://docs.sendcloud.sc/api/v2/shipping/#create-a-parcel. The problem now, for as far as I can see is that for Sendcloud is currently not accepting not rounded weights for parcels in kilograms. For example, the results of different input data for https://github.com/JouwWeb/sendcloud/blob/master/src/Client.php#L192:

name:"Firstname Lastname"
company_name:""
address:"Street"
address_2:""
house_number:"1"
city:"Amsterdam"
postal_code:"1234AB"
country:"NL"
email:"[email protected]"
telephone:"0612345678"
country_state:""
order_number:"1"
weight:"6,525"

Results in an error

name:"Firstname Lastname"
company_name:""
address:"Street"
address_2:""
house_number:"1"
city:"Amsterdam"
postal_code:"1234AB"
country:"NL"
email:"[email protected]"
telephone:"0612345678"
country_state:""
order_number:"1"
weight:"6"

Works perfectly

Changing https://github.com/JouwWeb/sendcloud/blob/master/src/Client.php#L519 fixes it for me.

$parcelData['weight'] = (string)($weight / 1000);

// change to 

$parcelData['weight'] = (string) round($weight / 1000); 

Laravel 8 compatibility

I'm using this package with Laravel 7 but when I want to upgrade to Laravel 8 the Guzzle version conflicts. Is there a possibility to upgrade to Guzzle ^7.0.1

Thanks

Support for canonicalized header names

Hello!

In the function verifyWebhookRequest of file src/Utility.php, you are retrieving the header 'SendCloud-Signature' which is correct according to the SendCloud API documentation.

I used your library on inside WordPress, and there the request object enforces certain rules for the header names (https://developer.wordpress.org/reference/classes/wp_rest_request/canonicalize_header_name/). Basically, it stores 'SendCloud-Signature' as 'sendcloud_signature'.

Funny thing is, the call to getHeader in the verifyWebhookRequest method works equally well for both 'SendCloud-Signature' and 'sendcloud-signature', but the dash instead of underscore causes the exception to be thrown always.

I was wondering if it would be possible to update the method to look a bit like this:

$signatureHeader = $request->getHeader('SendCloud-Signature');
if (count($signatureHeader) === 0) {
    $signatureHeader = $request->getHeader('SendCloud_Signature');
    if (count($signatureHeader) === 0) {
      throw new SendCloudWebhookException(
          'Webhook request does not specify a signature header.',
          SendCloudWebhookException::CODE_INVALID_REQUEST
      );
    }
}

Looking forward to your reply!

Fix distorted min_weigth and max_height

(int)($data['min_weight'] * 1000),

Using (int) in the result of ShippingMethod::fromData() distorts the result of the min_weight and max_weight in some cases.
Indeed, the result of (int)(1.001*1000) is 1000, while we expect to have 1001.

To avoid this, it could be possible to combine intval() and ceil(), like this:

intval(ceil($data['min_weight'] * 1000)),
intval(ceil($data['max_weight'] * 1000)),

Parcel documents endpoint

Currently the only way of retrieving labels is through the Labels endpoint from what I can tell. I was advised by Sendcloud to use the Parcel Documents endpoint as we rely on ZPL.

Is this something that's currently in the works behind the scenes, or would this be something that I would have to make a PR for?

Suggestion : moving service point methods to new class

As I stated in my PR #33,
service points endpoints uses a different url : https://servicepoints.sendcloud.sc/api/v2/.

This can quite a bit confusing to use :

use JouwWeb\Sendcloud\Client;

$client = new Client('your_public_key', 'your_secret_key');
$client->getUser(); // HTTP 200 OK
$client->searchServicePoints('NL'); // HTTP 404 NOT FOUND

$client_2 = new Client('your_public_key', 'your_secret_key', null, 'https://servicepoints.sendcloud.sc/api/v2/');
$client_2->getUser(); // HTTP 404 NOT FOUND
$client_2->searchServicePoints('NL'); // HTTP 200

So I suggest something like this :

  • Client.php : Everything related to https://panel.sendcloud.sc/api/v2/
  • ServicePointsClient.php : Everything related to https://servicepoints.sendcloud.sc/api/v2/
  • Move parseGuzzleException() to Utility.php

So now :

use JouwWeb\Sendcloud\Client;
use JouwWeb\Sendcloud\ServicePointsClient;

$client = new Client('your_public_key', 'your_secret_key');
$client->getUser(); // HTTP 200 OK
$client->searchServicePoints('NL'); // Method does not exist

$client_2 = new ServicePointsClient('your_public_key', 'your_secret_key');
$client_2->getUser(); // Method does not exist
$client_2->searchServicePoints('NL'); // HTTP 200 OK

Is this a good idea ?

Improve client methods taking a lot of optional parameters

The parameters of the createParcel() method grew naturally, but I think it would be better to model them (and parameters of other methods) using a value object instead. That way, mandatory parameters are enforced and the dedicated model can be documented and extended better.

sendcloud/src/Client.php

Lines 156 to 168 in 7796205

public function createParcel(
Address $shippingAddress,
?int $servicePointId,
?string $orderNumber = null,
?int $weight = null,
?string $customsInvoiceNumber = null,
?int $customsShipmentType = null,
?array $items = null,
?string $postNumber = null,
?ShippingMethod $shippingMethod = null,
?string $errors = null,
?string $shippingMethodCheckoutName = null,
): Parcel {

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.