GithubHelp home page GithubHelp logo

laravel-shipstation's Introduction

LaravelShipStation

Latest Version on Packagist Software License Latest Version on Packagist Build Status

This is a simple PHP API wrapper for ShipStation built for Laravel.

Installation

This package can be installed via Composer by requiring the campo/laravel-shipstation package in your project's composer.json

{
    "require": {
        "campo/laravel-shipstation": "^5.0"
    }
}

Then at your Laravel project root run:

composer update

Second, add the LaravelShipStation service provider to your providers array located in config/app.php

LaravelShipStation\ShipStationServiceProvider::class

After installing via composer you will need to publish the configuration:

php artisan vendor:publish

This will create the configuration file for your API key and API secret key at config/shipstation.php. You will need to obtain your API & Secret key from ShipStation: How can I get access to ShipStation's API?

If ShipStation has provided you with a partner API key, set it in your configuration file.

Dependencies

LaravelShipStation uses GuzzleHttp\Guzzle

Endpoints

Endpoints for the API are accessed via properties (e.g. $shipStation->orders->get($options) will make a GET request to /orders/{$options}). The default endpoint is /orders/. Valid endpoints include:

  • accounts
  • carriers
  • customers
  • fulfillments
  • orders
  • products
  • shipments
  • stores
  • users
  • warehouses
  • webhooks

Methods

GET

$shipStation->{$endpoint}->get($options = [], $endpoint = '');

Example of getting an order with the order id (ShipStation's internal order id) of 123 & Getting ShipStations internal order id by the order number.

$shipStation = $this->app['LaravelShipStation\ShipStation'];

// Fetch an order by orderId == 123, orderId is defined by ShipStation
$order = $shipStation->orders->get([], $endpoint = 123); // returns \stdClass

// Fetch an orderId by the orderNumber, which may be user defined
$order = $shipStation->orders->getOrderId('ORD-789'); // returns integer

POST

$shipStation->{$endpoint}->post($options = [], $endpoint = '');

The second parameter ($endpoint) is for any additional endpoints that need to be added. For example, to create an order the POST request would go to /orders/createorder. "createorder" is the additional endpoint since we specify the root endpoint as a property: $shipstation->orders->post($options, 'createorders')

There are models that contain all of the properties available via the API. These models will be converted to arrays when passed to the API.

An example on how to create a new order to be shipped:

    $shipStation = $this->app['LaravelShipStation\ShipStation'];

    $address = new LaravelShipStation\Models\Address();

    $address->name = "Joe Campo";
    $address->street1 = "123 Main St";
    $address->city = "Cleveland";
    $address->state = "OH";
    $address->postalCode = "44127";
    $address->country = "US";
    $address->phone = "2165555555";

    $item = new LaravelShipStation\Models\OrderItem();

    $item->lineItemKey = '1';
    $item->sku = '580123456';
    $item->name = "Awesome sweater.";
    $item->quantity = '1';
    $item->unitPrice  = '29.99';
    $item->warehouseLocation = 'Warehouse A';

    $order = new LaravelShipStation\Models\Order();

    $order->orderNumber = '1';
    $order->orderDate = '2016-05-09';
    $order->orderStatus = 'awaiting_shipment';
    $order->amountPaid = '29.99';
    $order->taxAmount = '0.00';
    $order->shippingAmount = '0.00';
    $order->internalNotes = 'A note about my order.';
    $order->billTo = $address;
    $order->shipTo = $address;
    $order->items[] = $item;

    // This will var_dump the newly created order, and order should be wrapped in an array.
    var_dump($shipStation->orders->post($order, 'createorder'));
    // or with the helper: $shipStation->orders->create($order); would be the same.

DELETE

$shipStation->{$endpoint}->delete($resourceEndPoint);

Example of deleting an order by it's order ID:

$shipStation->orders->delete($orderId);

UPDATE

$shipStation->{$endpoint}->update($query = [], $resourceEndPoint);

Simple Wrapper Helpers

Helpers are located in /src/Helpers and will be named after the endpoint. Currently there is only a helper for the /orders endpoint and /shipments endpint. I will be adding more; feel free to send a PR with any you use.

Check to see if an order already exists in ShipStation via an Order Number:

$orderExists = $shipStation->orders->existsByOrderNumber($orderNumber) // returns bool

Note: When using the orderNumber query parameter ShipStation will return any order that contains the search term. e.g. orderNumber = 1 will return any order that CONTAINS 1 in ascending order and not an exact match to the query. If you have two orders 123, and 1234 in your ShipStation and call $shipStation->orders->get(['orderNumber' => 123]); you will return both orders.

Check how many orders are in awaiting_fulfillment status:

$count = $shipStation->orders->awaitingShipmentCount(); // returns int

Create an order in ShipStation:

$newOrder = $shipStation->orders->create($order);

Get the shipments for a specific order number.

$shipments = $shipStation->shipments->forOrderNumber($orderNumber);

ShipStation API Rate Limit

ShipStation only allows for 40 API calls that resets every 60 seconds (or 1 call every 1.5 seconds). By default, LaravelShipStation will protect against any calls being rate limited by pausing when we are averaging more than 1 call every 1.5 seconds.

Once a request has been made, information about the current rate limiting values can be accessed using the following methods:

Get the maximum number of requests that can be sent per window:

// integer
$shipStation->getMaxAllowedRequests()

Get the remaining number of requests that can be sent in the current window:

// integer
$shipStation->getRemainingRequests()

Get the number of seconds remaining until the next window begins:

// integer
$shipStation->getSecondsUntilReset()

Check if requests are currently being rate limited:

// boolean
$shipStation->isRateLimited()

Tests

Tests can be ran using phpunit. Please note that tests will create an order, check the order, and delete the order in your production environment. By default, tests are disabled. If you would like to run the tests edit the phpunit.xml file to set the environment variable SHIPSTATION_TESTING to true and set your API Key & Secret Key.

Contribution

Pull requests are most certainly welcomed! This is a WIP.

License

The MIT License (MIT). Please see License File for more information.

laravel-shipstation's People

Contributors

ajohnson6494 avatar brandonsurowiec avatar danrichards avatar joecampo avatar squatto avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

laravel-shipstation's Issues

How to manage multiple orders update?

Hello , Everybody.
Thanks for your work.
Well Can I ask some questions ?
Now I am using this code for shipstation API.
I am updating the multiple orders at a time for example +5000 orders - update the tagIds.
So I am using $shipstation->orders->post($option,'createorders');
it works only when I try to add new tagIds.
But When I try remove some tagIds it is not working..
Is there any some advice for this issue ?
Hope to hear from you soon.
Thanks
Chao

Create label for order

How can i create label for an order.
Everytime i hit the command it gives me 500 Error

I am passing these arguments
$label = new LaravelShipStation\Models\Order();
$label->orderId = $orderid;
$label->carrierCode = 'stamps_com';
$label->serviceCode = 'stamps_com';
$label->packageCode = 'package';
$label->confirmation = null;
$label->testLabel = false;
$label->shipDate = '2019-09-28';

    $label_data = $shipStation->orders->post($label, 'createlabelfororder');

Error getting:
Server error: POST https://ssapi.shipstation.com/orders/createlabelfororder resulted in a 500 Internal Server Error response: {"Message":"An error has occurred.","ExceptionMessage":"Object reference not set to an instance of an object.","Exceptio (truncated...)

Creating Multiple Orders

Hey there, firstly, thanks for making this, it's been very useful to me so far!

I have been trying to get the "Create / Update Multiple Orders" endpoint working and can't seem to figure it out... I'm close... but apparently something is still formatted incorrectly? I was hoping you might have an idea of what else I could try, or show me an example of using that endpoint correctly?

Here's a snippet of what I was trying:

        // An array to keep our orders to be sent
        $toSend = [];

        foreach ($orders as $o) {
            // Build items array
            $items = [];
            foreach ($o->items as $item) {
                $i              = new OrderItem();
                $i->lineItemKey = $item->id;
                $i->name        = $item->title;
                $i->quantity    = $item->quantity;
                $i->sku         = $item->sku;  
                $items[]        = $i;          
            }

            // Shipping Address
            $shipTo = new Address();
            $shipTo->name       = $o->ship_name;
            $shipTo->company    = $o->ship_company;
            $shipTo->street1    = $o->ship_street;
            $shipTo->street2    = $o->ship_street2;
            $shipTo->city       = $o->ship_city;
            $shipTo->state      = $o->ship_statecode;
            $shipTo->postalCode = $o->ship_zip;
            $shipTo->country    = $o->ship_countrycode;
            $shipTo->phone      = $o->ship_phone;        

            // Billing Address
            $billTo = new Address();
            $billTo->name       = $o->bill_name;
            $billTo->company    = $o->bill_company;
            $billTo->street1    = $o->bill_street;
            $billTo->street2    = $o->bill_street2;
            $billTo->city       = $o->bill_city;
            $billTo->state      = $o->bill_statecode;
            $billTo->postalCode = $o->bill_zip;
            $billTo->country    = $o->bill_countrycode;
            $billTo->phone      = $o->bill_phone;   

            $new = new Order();
            $new->orderNumber = $o->orderId;
            $new->orderDate   = $o->order_date;
            $new->orderStatus = 'awaiting_shipment';
            $new->billTo      = $billTo; 
            $new->shipTo      = $shipTo;
            $new->items       = $items;

            $toSend[] = $new;
        }

        $response = $this->ss->orders->post($toSend, 'createorders');

        dd($response);

I've verified that if I use the single (createorder) endpoint, it works fine. Here's the error I'm getting when I use the multiple order endpoint with the above code:

 [GuzzleHttp\Exception\ServerException]
  Server error: `POST https://ssapi.shipstation.com/orders/createorders` resulted in a `500 Internal Server Error` response:
  {"Message":"An error has occurred.","ExceptionMessage":"orders are required","ExceptionType":"System.ArgumentException", (truncated...)

The orders are required error is what I get no matter how I try to format the main array, so thanks in advance if you have any ideas as to what to try!

PrintLabel, get carriers lbs price

Hello,
Thank for this package. It helps too much for our project. We have questions.
How can we create labels for our orders that created manually?
How can we check prices for our account, which carrier, which lbs return price?
Thank you,
Best regards

Example view usage?

Hi,

I am trying to use this package to pull from Shipstation into Laravel. All goes well as I am able to get the results from Controller using dd($orders). But when i go to use it in view (eg: foreach $orders as $order), when I attempt to access the properties like so $order->orderNumber or $order->orders["orderNumber"] . Can you please help me to understand why I am getting the following error "htmlspecialchars() expects parameter 1 to be string, array given" or just show me what I need to do to be able to display the get requests from Shipstation in a view. It works fine for $users but the $orders is giving me a problem.

Thanks, a Million

Why i get error for $this->app['LaravelShipStation\ShipStation'];

Hi all,

i'm new for both laravel and shipstation. I'm trying to send / create new order. but when i try to send new order returns error for $shipStation = $this->app['LaravelShipStation\ShipStation'];

Undefined property: App\Http\Controllers\SettingsController::$app

what should i do for overcome this issue? any information will be appreciated.

Best Regards

Shipstation api gives me an 400 error when posting an order

Hi there,

I'm trying to create a order and make a post request. However, I get this error when doing so:

"{"Message":"The request is invalid.","ModelState":{"apiOrder":["Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'SS.OpenApi.Models.Orders.Order' because the type requires a JSON object (e.g. {\"name\":\"value\"}) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON object (e.g. {\"name\":\"value\"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.\r\nPath '', line 1, position 1."]}}"

I tried your example order and still got the same error.

Here's my relevant code.

    function newShipStationOrder($reqArray) {


        $order = new \LaravelShipStation\Models\Order();

        $order->orderNumber =  $reqArray['content']['invoiceNumber'];
        $order->orderDate = $reqArray['content']['creationDate'];
        $order->orderStatus = $reqArray['content']['status'];
        $order->amountPaid = $reqArray['content']['grandTotal'];
        $order->taxAmount = $reqArray['content']['taxesTotal'];
        $order->shippingAmount = $reqArray['content']['shippingFees'];

        if ($order->shippingAmount == null) {
            $order->shippingAmount = 0;
        }

        $order->internalNotes = $reqArray['content']['notes'];

        if ($order->shippingAmount == null) {
            $order->internalNotes = "N/A";
        }

        $tempAddressArray = $this->createPhysicalAddresses($reqArray['content']);
        $order->billTo = $tempAddressArray['billingAddress'];
        $order->shipTo = $tempAddressArray['shippingAddress'];

        $jsonOrderItemArray = $reqArray['content']['items'];

        foreach ($jsonOrderItemArray as $item) {
            $newOrderItem = new \LaravelShipStation\Models\OrderItem();

            $newOrderItem->lineItemKey = $item['id'];
            $newOrderItem->sku = $item['id'];
            $newOrderItem->name = $item['name'];
            $newOrderItem->quantity = $item['quantity'];
            $newOrderItem->unitPrice  = $item['unitPrice'];

            $newOrderItem->weight = $item['weight'];
            $newOrderItem->warehouseLocation = "N/A";

            $order->items[] = $newOrderItem;
        }

        return $order;
    }

    private function createPhysicalAddresses($data)
    {
        $shippingAddress = new \LaravelShipStation\Models\Address();
        $billingAddress = new \LaravelShipStation\Models\Address();

        $billingAddress->name = $data['billingAddressName'];
        $billingAddress->street1 = $data['billingAddressAddress1'];
        $billingAddress->street2 = $data['billingAddressAddress2'];
        $billingAddress->city = $data['billingAddressCity'];
        $billingAddress->state = $data['billingAddressProvince'];
        $billingAddress->postalCode = $data['billingAddressPostalCode'];
        $billingAddress->country = $data['billingAddressCountry'];
        $billingAddress->phone = $data['billingAddressPhone'];

        if ($data['shippingAddressSameAsBilling'] == true) {

            $shippingAddress = $billingAddress;
        } else {
            $shippingAddress->name = $data['shippingAddressName'];
            $shippingAddress->street1 = $data['shippingAddressAddress1'];
            $shippingAddress->street2 = $data['shippingAddressAddress2'];
            $shippingAddress->city = $data['shippingAddressCity'];
            $shippingAddress->state = $data['shippingAddressProvince'];
            $shippingAddress->postalCode = $data['shippingAddressPostalCode'];
            $shippingAddress->country = $data['shippingAddressCountry'];
            $shippingAddress->phone = $data['shippingAddressPhone'];
        }

        $addressArray['billingAddress'] = $billingAddress;
        $addressArray['shippingAddress'] = $shippingAddress;

        return $addressArray;
    }

Here is the order object.

Order {#152
  +orderNumber: "SNIP-1019"
  +orderKey: null
  +orderDate: "2017-08-12T05:37:41Z"
  +paymentDate: null
  +shipByDate: null
  +orderStatus: "Processed"
  +customerUsername: null
  +customerEmail: null
  +billTo: Address {#167
    +name: "dev1"
    +company: null
    +street1: "r4weghtjrt"
    +street2: null
    +street3: null
    +city: "ddd"
    +state: "AL"
    +postalCode: "111111"
    +country: "US"
    +phone: "7209998888"
    +residential: null
  }
  +shipTo: Address {#167}
  +items: array:3 [
    0 => OrderItem {#157
      +lineItemKey: "90397737-0d97-4863-bdae-bda267dce34e"
      +sku: "90397737-0d97-4863-bdae-bda267dce34e"
      +name: "bvlah1"
      +imageUrl: null
      +weight: null
      +quantity: 1
      +unitPrice: 111111111
      +taxAmount: null
      +shippingAmount: null
      +warehouseLocation: "N/A"
      +options: null
      +productId: null
      +fulfillmentSku: null
      +adjustment: false
      +upc: null
    }
    1 => OrderItem {#168
      +lineItemKey: "ad39db8f-23ee-47b6-8a5b-578ae213c72d"
      +sku: "ad39db8f-23ee-47b6-8a5b-578ae213c72d"
      +name: "Majora's mask"
      +imageUrl: null
      +weight: null
      +quantity: 1
      +unitPrice: 9000
      +taxAmount: null
      +shippingAmount: null
      +warehouseLocation: "N/A"
      +options: null
      +productId: null
      +fulfillmentSku: null
      +adjustment: false
      +upc: null
    }
    2 => OrderItem {#169
      +lineItemKey: "d094638e-f5ed-4de0-b9d3-db508a618d17"
      +sku: "d094638e-f5ed-4de0-b9d3-db508a618d17"
      +name: "Ocarina"
      +imageUrl: null
      +weight: null
      +quantity: 1
      +unitPrice: 7500
      +taxAmount: null
      +shippingAmount: null
      +warehouseLocation: "N/A"
      +options: null
      +productId: null
      +fulfillmentSku: null
      +adjustment: false
      +upc: null
    }
  ]
  +amountPaid: 111127611
  +taxAmount: 0
  +shippingAmount: 0
  +customerNotes: null
  +internalNotes: "N/A"
  +gift: null
  +giftMessage: null
  +paymentMethod: null
  +requestedShippingService: null
  +carrierCode: null
  +serviceCode: null
  +packageCode: null
  +confirmation: null
  +shipDate: null
  +holdUntilDate: null
  +weight: null
  +dimensions: null
  +insuranceOptions: null
  +internationalOptions: null
  +advancedOptions: null
  +tagIds: null
}

Any ideas?

Rate Limiting / Too Many Requests

Hello,

I noticed even though you have a pause to detect if making a lot of requests by average, I still get occasional "too many requests" from ShipStation. When this happens it is usually the addtags orders call and it can loop through literally 1000+ orders that need to either add a tag and/or removetag call both per order.

Would you suggest I increase the 1.5 sleep or do you suggest something else?

Honor development environments

Has there been any thought given to development environment handling?

I didn't anything with a quick scan so I added a property to the src/ShipStation.php of:
private $devel_uri = 'private-anon-74400a3262-shipstation.apiary-mock.com';

Then in the constructor I updated the 'base_uri' initialization to use a ternary operator checking the environment and then using the appropriate api endpoint:
parent::__construct([ 'base_uri' => (App::environment() == 'production') ? $this->base_uri : $this->devel_uri,

This is a temporary solution for me until I (or someone else if they feel up to it) has time to create a pull request with a cleaner solution.

Update: It looks like the 'sandbox' api doesn't accept connections outside of the apiary domain, which makes this irrelevant. It looks like I will have to bug ShipStation about this one sorry.

What should be the right format for weight and dimensions attributes?

Hello,

I am trying to create a shipment with weight and dimensions of the product. But its showing me an error pasted below:

message: "Client error: POST https://ssapi.shipstation.com/orders/createorder resulted in a 400 Bad Request response:↵{"Message":"The request is invalid.","ModelState":{"apiOrder.items[0].weight":["Cannot deserialize the current JSON arra (truncated...)↵

In the package the datatype for the weight is array, so I am trying to send this kind of format there.

$order->weight = [1,2];
$order->dimensions =[1,2,3];

Please suggest me the exact format to send with and also I need assistance with

$requestedShippingService

How could I get the existing shipping service from my account to map?

Thanks!

Custom Store

How to create custom store endpoints? Is this something that your plugin is able to do. If not, is this a feature you would be interested in adding?

webhooks

I'm confused on how these are implemented in Shipstation. The docs don't say much about them other than in the custom store guide. I have some questions.

  1. Do they allow JSON like their apis or what? I'd prefer to go with JSON.
  2. If they do, how can I receive JSON, not XML?

Missing /fulfillments endpoint

according to shipstation docs now we can list /fulfillments as a separate request, this wrapper does not include that endpoint and there's no way to extend it in laravel because $endpoints is a private property and there is no setter method to add any.

anyone encountered this issue? can we simply add '/fulfillments' to the $endpoints array?

thanks in advance

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.