神刀安全网

Easily handle shipping in Laravel with Shippo

Easily handle shipping in Laravel with Shippo

When building an e-commerce store one of the hardest parts is dealing with shipping carriers. Each one has their own rules, their own API, and it’s easy to get overwhelmed.

To give you an idea of the current shipping landscape look at what all is required through many of the most popular services:

  • Many of the carriers only provide SOAP or XML API’s.
  • Each carrier requires you to go through a certification process for the integration and will not allow certain functions until the certification is complete.
  • USPS doesn’t even have an available API.
  • None of the carriers offer webhooks to notify you about tracking status and other events.

Shippo is a service that simplifies all of these crazy requirements into a single simple JSON API that integrates with numerous providers. It also handles address validation, multi-carrier support, tracking API, label creation, and webhooks.

Easily handle shipping in Laravel with Shippo

Best of all it’s affordable, no monthly fees, setup fees, or cancellation fees. You only pay for the shipping cost plus five cents per shipment.

Let’s take a look at integrating Shippo into a Laravel application and how it can save you time and hassle.

Adding Shippo to our Laravel Project

Before we get started, head over to Shippo and create a free account. It’s free to use and you can test out the system in trial mode so you are not charged anything until you go live.

Shippo has many different libraries available and we will be using their PHP-Client that can be installed through Composer.

composer require shippo/shippo-php

Next, we need to grab our private API key from the Shippo admin. ( This is found from the API section of the admin )

Open up your “.env” file and add this:

SHIPPO_PRIVATE=yourkeyhere

With this set let’s build out a new Shipping service class so we can have all shipping isolated to a single class.

Shipping Class

Create a new file “Services/Shipping.php” and add our private key to the constructor:

<?php
namespace App/Services;
use Shippo;
class Shipping 
{
public function __construct()
{
// Grab this private key from
// .env and setup the Shippo api
Shippo::setApiKey(env('SHIPPO_PRIVATE'));
}
}

Now if we think about the typical flow of an e-commerce checkout system it goes from a shopping cart, to confirmation, to completion.

The three primary items with shipping would be validating their address, getting a list of rates, and finally process the transaction to get a shipping label.

Address Validation

When a customer is purchasing from you, one of the first things you’ll need to do is validate their address to make sure they’ve entered their address correctly and it’s a location you can actually ship your products too.

Going back to our Shipping.php class let’s add a new method for validating the shipping address:

/**
* Validate an address through Shippo service
*
* @param User $user
* @return Shippo_Adress
*/
public function validateAddress(User $user)
{
// Grab the shipping address from the User model
$toAddress = $user->shippingAddress();
// Pass a validate flag to Shippo
$toAddress['validate'] = true;
// Verify the address data
return Shippo_Address::create($toAddress);
}

What I am doing here is passing in a standard Laravel User model, grabbing their shipping address, and passing it over to Shippo with a “validate” flag.

The $user->shippingAddress() calls a method off the User model like this: (I’m assuming the shipping address is columns on the users table)

/**
* Return the shipping data for a user
*
* @return array
*/
public function shippingAddress()
{
return [
'name' => $this->name,
'company' => $this->company,
'street1' => $this->street1,
'city' => $this->city,
'state' => $this->state,
'zip' => $this->zip,
'country' => $this->country,
'phone' => $this->phone,
'email' => $this->email,
];
}

From our controller we can now validate the address easily with the following:

// Try and validate the address
$validate = $this->shipping->validateAddress($user);
// Make sure it's not an invalid address this
// could also be moved to a custom validator rule
if ($validate->object_state == 'INVALID') {
return back()->withMessages($validate->messages);
}

With the address validation in place let’s move on to getting a list of shipping rates.

Shipping Rates

The shipping rates allow users to choose between different providers, see pricing, and select how fast they want the product.

To generate the list you will need a few items, the address you are shipping from, the customers to address, and information on the actual product you are shipping.

Open the Shipping class again and let’s add a new method for getting rates:

/**
* Create a Shippo shipping rates
*
* @param User $user
* @param Product $product
* @return Shippo_Shipment
*/
public function rates(User $user, Product $product)
{
// Grab the shipping address from the User model
$toAddress = $user->shippingAddress();
// Pass the PURCHASE flag.
$toAddress['object_purpose'] = 'PURCHASE';
// Get the shipment object
return Shippo_Shipment::create([
'object_purpose'=> 'PURCHASE',
'address_from'=> $this->fromAddress,
'address_to'=> $toAddress,
'parcel'=> $product->toArray(),
'insurance_amount'=> '30',
'insurance_currency'=> 'USD',
'async'=> false
]);
}

This passes the Users address, an object_purpose flag, a from address, and finally the information on the product. Here are three example arrays of these items:

$fromAddress = [
'object_purpose' => 'PURCHASE',
'name' => 'Shawn Ippotle',
'company' => 'Shippo',
'street1' => '215 Clayton St.',
'city' => 'San Francisco',
'state' => 'CA',
'zip' => '94117',
'country' => 'US',
'phone' => '+1 555 341 9393',
'email' => 'shippotle@goshippo.com'
];
$toAddress = [
'object_purpose' => 'PURCHASE',
'name' => 'Mr Hippo"',
'company' => '',
'street1' => 'Broadway 1',
'street2' => '',
'city' => 'New York',
'state' => 'NY',
'zip' => '10007',
'country' => 'US',
'phone' => '+1 555 341 9393',
'email' => 'mrhippo@goshippo.com'
];
$parcel = [
'length'=> '5',
'width'=> '5',
'height'=> '5',
'distance_unit'=> 'in',
'weight'=> '2',
'mass_unit'=> 'lb',
];

Our controller for grabbing the rates would look something like this:

$user = auth()->user();
$product = new Product([
'length'=> '5',
'width'=> '5',
'height'=> '5',
'distance_unit'=> 'in',
'weight'=> '2',
'mass_unit'=> 'lb',
]);
$rates = $this->shipping->rates($user, $product);
// The $rates is a complete object but for our view we
// only need the rates_list items and will pass that to it
return view('checkout.index', ['rates' => $rates->rates_list]);

Finally, for showing the list of rates to the user:

@foreach ($rates as $rate)
<tr>
<td>
<img src="{{ $rate->provider_image_75 }}" alt="">
{{ $rate->provider }} ({{ $rate->duration_terms }})
</td>
<td width="20%">
<input type="radio"
name="rate"
value="{{ $rate->object_id }}">
${{ $rate->amount }}
</td>
</tr>
@endforeach

Notice how the radio’s value is the $rate->object_id . That will be used when we create the final shipping transaction.

Generating the transaction

The final step after the customer has selected their shipping provider and rate is to create a transaction in the Shippo service to generate a shipping label.

Let’s open the Shipping class again and create a new method to handle this:

/**
* Create the shipping label transaction
*
* @param $rateId -- object_id from rates_list
* @return Shippo_Transaction
*/
public function createLabel($rateId)
{
return Shippo_Transaction::create([
'rate' => $rateId,
'label_file_type' => "PDF",
'async' => false
]);
}

Because we’ve already grabbed the list of rates for a purchase all that is required is passing in the object id of the rate they want and you can complete the transaction.

Here is what our controller would look like:

// now that the user has selected the rate
// build out the shipping label and tracking
// in this situation the rate is the object_id
$transaction = $this->shipping->createLabel($request->rate);
// If it failed then redirect back and tell them whats wrong
if ($transaction["object_status"] != "SUCCESS"){
return back()->withMessage($transaction["messages"]);
}
return view('checkout.thanks', [
'shipping' => $transaction,
]);

This $transaction object has the following items:

Some important ones to take notice of are the tracking_number , tracking_url_provider , and label_url .

The tracking_url_provider is what you can send your customer to check the status of their order through the carriers website.

The label_url is for your use. By visiting it you can print the shipping label and attach it to the parcel you are sending out.

Easily handle shipping in Laravel with Shippo
Example Shipping Label

Shipment Tracking

After the package is sent out, Shippo automatically keeps up with the package status through the corresponding carrier’s system. Then it will send you status updates through a webhook.

By having immediate status updates, you can delight your customers by:

  • Sending them an email when it’s delivered.
  • Warning them if it’s delayed.
  • Or go crazy by creating your own IFTTT recipe.

Going Further

This article barely touches the surface on all of Shippo’s features. Checkout their site for more details on everything they offer.

Also, I have a sample Laravel app with all the code used in this tutorial that can be used as a quick guide and here is the direct link to the Shipping class .

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Easily handle shipping in Laravel with Shippo

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址