<file_sep><?php

use Carbon\Carbon;
use Arkade\Bronto\RestClient;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Handler\MockHandler;
use Arkade\Bronto\RestAuthentication;
use PHPUnit\Framework\TestCase;

class RestClientTest extends TestCase
{
    public function testRequest()
    {
        $auth = new RestAuthentication(
            HandlerStack::create(new MockHandler([
                new Response(
                    200, [], json_encode(
                        [
                            'access_token' => 'aRandom<PASSWORD>',
                            'refresh_token' => '<PASSWORD>',
                            'expires_in'  => 3600,
                        ]
                    )
                ),
            ]))
        );

        $auth->setAuthUrl('https://auth.bronto.com/oauth2/token');
        $auth->setClientId('arkade');
        $auth->setClientSecret('secret');
        $auth->setEndpoint('https://rest.bronto.com');

        // Set up our request(s) history
        $container = [];
        $history = Middleware::history($container);

        // Set up our mock handler for the auth response(s)
        $mock = new MockHandler(
            [new Response(200, [], json_encode([]))]
        );

        // Set up our Guzzle Handler Stack History (for requests)
        $stack = HandlerStack::create($mock);
        $stack->push($history);

        // Let's make the client with our mock responses and history container
        $client = new RestClient($auth, $stack);

        // Let's test!
        $client->request('GET', 'some-endpoint',
            ['query' => ['foo' => 'bar']]);

        // Check the correct outgoing call was made
        $this->assertEquals('GET', $container[0]['request']->getMethod());
        $this->assertEquals('/some-endpoint?foo=bar',
            $container[0]['request']->getRequestTarget());

    }
}<file_sep><?php

namespace Omneo\Bronto\Modules;

use Omneo\Bronto\Entities\Order;
use Omneo\Bronto\Parsers\OrderParser;
use Omneo\Bronto\Serializers\OrderSerializer;
use Illuminate\Support\Collection;

class OrderService extends AbstractRestModule
{
    /**
     * Order find.
     * Uses Bronto order ID
     *
     * @param $id
     * @return Order
     */
    public function find($id)
    {
        return (new OrderParser)->parse(
            $this->client->get('orders/'.$id,['debug' => env('APP_DEBUG')])
        );
    }

    /**
     * Order search.
     * Uses customer order ID
     *
     * @param $id
     * @return Collection
     */
    public function findById($id)
    {
        $data = $this->client->get('orders?customerOrderId='.$id,['debug' => env('APP_DEBUG')]);

        $collection = new Collection;

        if(!count($data)) return $collection;

        foreach($data as $item){
            $collection->push(
                (new OrderParser)->parse($item)
            );
        }

        return $collection;
    }

    /**
     * Order add.
     *
     * @param Order $order
     * @param boolean $createContact
     * @param boolean $triggerEvents
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function add(Order $order, $createContact = false, $triggerEvents = false)
    {
        $query = 'createContact='.$createContact;
        $query .= 'triggerEvents='.$createContact;

        return (new OrderParser)->parse(
            $this->client->post(
                'orders?'.$query,
                [
                    'headers' => ['Content-Type' => 'application/json'],
                    'body' => (new OrderSerializer)->serialize($order),
                    'debug' => env('APP_DEBUG')
                ]
            )
        );
    }

    /**
     * Order update.
     * Uses Bronto order ID
     *
     * @param Order $order
     * @param boolean $createContact
     * @param boolean $triggerEvents
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function update(Order $order, $createContact = false, $triggerEvents = false)
    {
        $query = 'createContact='.$createContact;
        $query .= 'triggerEvents='.$createContact;

        return (new OrderParser)->parse(
            $this->client->post(
                'orders/'.$order->getOrderId().'?'.$query,
                [
                    'headers' => ['Content-Type' => 'application/json'],
                    'body' => (new OrderSerializer)->serialize($order),
                    'debug' => env('APP_DEBUG')
                ]
            )
        );
    }

    /**
     * Order update.
     * Uses customer order ID
     *
     * @param Order $order
     * @param boolean $createContact
     * @param boolean $triggerEvents
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function updateById(Order $order, $createContact = false, $triggerEvents = false)
    {
        $query = 'createContact='.$createContact;
        $query .= 'triggerEvents='.$createContact;

        return (new OrderParser)->parse(
            $this->client->post(
                'orders/customerOrderId/'.$order->getCustomerOrderId().'?'.$query,
                [
                    'headers' => ['Content-Type' => 'application/json'],
                    'body' => (new OrderSerializer)->serialize($order),
                    'debug' => env('APP_DEBUG')
                ]
            )
        );
    }

    /**
     * Order delete.
     * Uses Bronto order ID
     *
     * @param string $id
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function delete($id)
    {
        return $this->client->delete('orders/'.$id, ['debug' => env('APP_DEBUG')]);
    }

    /**
     * Order delete.
     * Uses customer order ID
     *
     * @param string $id
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function deleteById($id)
    {
        return $this->client->delete('orders/customerOrderId/'.$id,['debug' => env('APP_DEBUG')]);
    }
}<file_sep><?php

namespace Omneo\Bronto;

use Bronto_Api;
use Illuminate\Support\Collection;

class SoapClient
{
    /**
     * @var Bronto_Api
     */
    protected $client;

    /**
     * @var string
     */
    protected $token;

    /**
     * @var string
     */
    protected $listId;

    /**
     * @var Collection
     */
    protected $contactMappings;

    /**
     * Client constructor.
     *
     */
    public function __construct()
    {
        $this->client = new \Bronto_Api();
    }

    /**
     * @return Bronto_Api
     */
    public function getClient()
    {
        return $this->client;
    }

    /**
     * @param Bronto_Api $client
     * @return SoapClient
     */
    public function setClient($client)
    {
        $this->client = $client;
        return $this;
    }

    /**
     * @return string
     */
    public function getToken()
    {
        return $this->token;
    }

    /**
     * @param string $token
     * @return SoapClient
     */
    public function setToken($token)
    {
        $this->token = $token;
        $this->client->setToken($token);
        $this->client->login();
        return $this;
    }

    /**
     * @return string
     */
    public function getListId()
    {
        return $this->listId;
    }

    /**
     * @param string $listId
     * @return SoapClient
     */
    public function setListId($listId)
    {
        $this->listId = $listId;
        return $this;
    }

    /**
     * @return Collection
     */
    public function getContactMappings()
    {
        return $this->contactMappings;
    }

    /**
     * @param Collection $contactMappings
     * @return SoapClient
     */
    public function setContactMappings($contactMappings)
    {
        $this->contactMappings = $contactMappings;
        return $this;
    }

    /**
     * Contact service module.
     *
     * @return Modules\ContactService
     */
    public function contactService()
    {
        return new Modules\ContactService($this, $this->contactMappings);
    }

    /**
     * Delivery service module.
     *
     * @return Modules\DeliveryService
     */
    public function deliveryService()
    {
        return new Modules\DeliveryService($this);
    }

}
<file_sep><?php

namespace Omneo\Bronto\Exceptions;

use Exception;

class NotFoundException extends Exception
{
    //
}
<file_sep><?php

namespace Omneo\Bronto\Entities;

use Carbon\Carbon;
use Illuminate\Support\Collection;

class DeliveryField extends AbstractEntity
{
    /**
     * @var string
     */
    protected $name;

    /**
     * @var string
     */
    protected $type;

    /**
     * @var string
     */
    protected $content;

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * The name of the API message tag. API message tags can be placed in the body or subject line of an email message
     * with a prepended ‘#’, as in “%%#tag_name%%“). When you reference the name of an API message tag via the API,
     * be sure to leave off the “%%# %%” portion of the API message tag.
     * For example, name => tag_name, rather than name => %%#tag_name%%.
     * Loop tags use a slightly different syntax (%%#tagname_#%%) and can only be added to the body of an email message.
     * When you reference the the name of a Loop tag via the API,
     * be sure to leave off the “%%# %%” portion of the Loop tag,
     * and replace the underscore “_#” with an underscore followed by a number.
     * @param string $name
     * @return DeliveryField
     */
    public function setName($name)
    {
        $this->name = $name;
        return $this;
    }

    /**
     * @return string
     */
    public function getType()
    {
        return $this->type;
    }

    /**
     * The version of the message into which API message tag content should be inserted {text or html}.
     * @param string $type
     * @return DeliveryField
     */
    public function setType($type)
    {
        $this->type = $type;
        return $this;
    }

    /**
     * @return string
     */
    public function getContent()
    {
        return $this->content;
    }

    /**
     * @param string $content
     * @return DeliveryField
     */
    public function setContent($content)
    {
        $this->content = $content;
        return $this;
    }

    /**
     * @return Array
     */
    public function jsonSerialize()
    {
        $result = get_object_vars($this);

        return $result;
    }

}
<file_sep><?php

use Carbon\Carbon;
use Arkade\Bronto\RestAuthentication;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Handler\MockHandler;
use PHPUnit\Framework\TestCase;

class AuthenticationTest extends TestCase
{

    public function testAuthUrlSetterGetter()
    {
        $auth = new RestAuthentication;
        $auth->setAuthUrl('https://auth.bronto.com/oauth2/token');
        $this->assertEquals('https://auth.bronto.com/oauth2/token', $auth->getAuthUrl());
    }

    public function testClientIdGetterSetter()
    {
        $auth = new RestAuthentication;
        $auth->setClientId('arkade');
        $this->assertEquals('arkade', $auth->getClientId());
    }

    public function testPasswordGetterSetter()
    {
        $auth = new RestAuthentication;
        $auth->setClientSecret('secret');
        $this->assertEquals('secret', $auth->getClientSecret());
    }

    public function testEndpointGetterSetter()
    {
        $auth = new RestAuthentication;
        $auth->setEndpoint('https://rest.bronto.com');
        $this->assertEquals('https://rest.bronto.com', $auth->getEndpoint());
    }

    public function testTokenExpiryGetterSetter()
    {
        $auth = new RestAuthentication;
        $auth->setTokenExpiry(Carbon::createFromTimestamp('3600'));
        $this->assertEquals(Carbon::createFromTimestamp('3600'),
            $auth->getTokenExpiry());
    }

    public function testTokenIsExpired()
    {
        $auth = new RestAuthentication;

        $auth->setTokenExpiry(Carbon::now()->addHour());
        $this->assertEquals(false, $auth->isTokenExpired());

        $auth->setTokenExpiry(Carbon::now()->subHour());
        $this->assertEquals(true, $auth->isTokenExpired());
    }


    public function testTokenSetter()
    {
        $auth = new RestAuthentication;
        $auth->setToken('my<PASSWORD>');
        $auth->setTokenExpiry(Carbon::now()->addHour());
        $this->assertEquals('mytoken', $auth->getToken());
    }

    public function testTokenGetter()
    {
        $auth = new RestAuthentication(
            HandlerStack::create(new MockHandler([
                new Response(
                    200, [], json_encode(
                        [
                            'access_token' => '<PASSWORD>',
                            'refresh_token' => '<PASSWORD>',
                            'expires_in'  => 3600,
                        ]
                    )
                ),
            ]))
        );
        $this->assertEquals('aRandomToken', $auth->getToken());
        $this->assertEquals('aRandomRefreshToken', $auth->getRefreshToken());
        $this->assertEquals(Carbon::now()->addSeconds(3600)->toDateTimeString(), $auth->getTokenExpiry()->toDateTimeString());
    }


    public function testCreateToken(){
        // Set up our request(s) history
        $container = [];
        $history = Middleware::history($container);

        // Set up our mock handler for the auth response(s)
        $mock = new MockHandler(
            [
                new Response(
                    200, [], json_encode(
                        [
                            'access_token' => '<PASSWORD>',
                            'refresh_token' => '<PASSWORD>',
                            'expires_in'  => 3600,
                        ]
                    )
                ),
            ]
        );

        // Set up our Guzzle Handler Stack History (for requests)
        $stack = HandlerStack::create($mock);
        $stack->push($history);

        // Let's make the client with our mock responses and history container
        $auth = new RestAuthentication($stack);
        $auth->setAuthUrl('https://auth.bronto.com/oauth2/token');
        $auth->setClientId('arkade');
        $auth->setClientSecret('secret');

        // Let's call create token
        $auth->createOauthToken();

        // Check that only one call was made to get q new token
        $this->assertCount(1, $container);

        // Check that it was a POST request
        $this->assertEquals('POST', $container[0]['request']->getMethod());

        // Ensure that it went to the Auth URL specified
        $this->assertEquals('/oauth2/token',
            $container[0]['request']->getRequestTarget());

        // Lastly, make sure the body has the correct form params
        $this->assertEquals(
            "grant_type=client_credentials&client_id=arkade&client_secret=secret",
            (string)$container[0]['request']->getBody()
        );

        $this->assertEquals('aRandomToken', $auth->getToken());
        $this->assertEquals('aRandomRefreshToken', $auth->getRefreshToken());
    }

    public function testRefreshToken(){
        // Set up our request(s) history
        $container = [];
        $history = Middleware::history($container);

        // Set up our mock handler for the auth response(s)
        $mock = new MockHandler(
            [
                new Response(
                    200, [], json_encode(
                        [
                            'access_token' => 'aRandomToken',
                            'refresh_token' => '<PASSWORD>',
                            'expires_in'  => 3600,
                        ]
                    )
                )
            ]
        );

        // Set up our Guzzle Handler Stack History (for requests)
        $stack = HandlerStack::create($mock);
        $stack->push($history);

        // Let's make the client with our mock responses and history container
        $auth = new RestAuthentication($stack);
        $auth->setAuthUrl('https://auth.bronto.com/oauth2/token');
        $auth->setClientId('arkade');
        $auth->setClientSecret('secret');
        $auth->setRefreshToken('<PASSWORD>');

        // Let's call create token
        $auth->refreshOauthToken();

        // Check that only one call was made to get q new token
        $this->assertCount(1, $container);

        // Check that it was a POST request
        $this->assertEquals('POST', $container[0]['request']->getMethod());

        // Ensure that it went to the Auth URL specified in the setClientConfig
        $this->assertEquals('/oauth2/token',
            $container[0]['request']->getRequestTarget());

        // Lastly, make sure the body has the correct form params
        $this->assertEquals(
            "grant_type=refresh_token&client_id=arkade&client_secret=secret&refresh_token=aRandom<PASSWORD>",
            (string)$container[0]['request']->getBody()
        );

        $this->assertEquals('aRandomToken', $auth->getToken());
        $this->assertEquals('anotherRandomRefreshToken', $auth->getRefreshToken());

    }

}<file_sep><?php

namespace Omneo\Bronto\Parsers;

use Carbon\Carbon;
use Omneo\Bronto\Entities;
use Illuminate\Support\Collection;

class LineItemParser
{
    /**
     * Parse the given array to a LineItem entity.
     *
     * @param  array $payload
     * @return Entities\LineItem
     */
    public function parse($payload)
    {
        $lineItem = (new Entities\LineItem())
            ->setCategory($payload->category)
            ->setDescription($payload->description)
            ->setImageUrl($payload->imageUrl)
            ->setName($payload->name)
            ->setOther($payload->other)
            ->setProductUrl($payload->productUrl)
            ->setQuantity($payload->quantity)
            ->setSalePrice($payload->salePrice)
            ->setSku($payload->sku)
            ->setTotalPrice($payload->totalPrice)
            ->setUnitPrice($payload->unitPrice);

        return $lineItem;
    }
}<file_sep><?php

namespace Omneo\Bronto\Parsers;

use Omneo\Bronto\Entities;
use Illuminate\Support\Collection;

class ContactUnsubscribeParser
{
    /**
     * Parse the given array to a Contact entity.
     *
     * @param  array $payload
     * @return Collection
     */
    public function parse($payload)
    {
        $result = collect([]);

        foreach($payload as $item){
            $contact = (new Entities\Contact)
                ->setId($item->id)
                ->setEmail($item->email)
                ->setMobileNumber($item->mobileNumber)
                ->setStatus($item->status);

            $result->push($contact);
        }

        return $result;
    }
}<file_sep><?php

namespace Arkade\Bronto\Factories;

use Arkade\Bronto\Entities\Product;
use Carbon\Carbon;

class ProductsFactory
{
    /**
     * Make an array of product entities.
     *
     * @return array
     */
    public function make()
    {
        $products = [];

        $product = new Product();
        $product->setProductId('9330947716452');
        $product->setTitle('SPARKLE CARDI CHEESE');
        $product->setColor('REBLK001');
        $product->setUpc('9330947716452');
        $product->setBrand('TEST');
        $product->setAvailabilityDate(Carbon::parse('2017-05-12'));

        $products[] = $product;

        $product = new Product();
        $product->setProductId('9330947716315');
        $product->setTitle('AMITY LACE DRESS');
        $product->setColor('REBLK001');
        $product->setUpc('9330947716315');
        $product->setBrand('TEST');
        $product->setAvailabilityDate(Carbon::parse('2017-06-12'));

        $products[] = $product;

        $product = new Product();
        $product->setProductId('9330947716179');
        $product->setTitle('PEARLY QUEEN JUMPER');
        $product->setColor('REBLK001');
        $product->setUpc('9330947716179');
        $product->setBrand('TEST');
        $product->setAvailabilityDate(Carbon::parse('2017-07-12'));

        $products[] = $product;

        return $products;
    }
}<file_sep><?php

namespace Arkade\Bronto\Serializers;

use PHPUnit\Framework\TestCase;
use Arkade\Bronto\Factories;

class ProductSerializerTest extends TestCase
{
    /**
     * @test
     */
    public function returns_populated_json()
    {
        $json = (new ProductSerializer)->serialize(
            (new Factories\ProductFactory)->make()
        );

        $this->assertEquals(file_get_contents(__DIR__.'/../Stubs/Products/serialized_product.json'), $json);
    }
}<file_sep><?php

namespace Omneo\Bronto\Modules;

use Omneo\Bronto;

abstract class AbstractSoapModule
{
    /**
     * @var Bronto\SoapClient
     */
    protected $client;

    /**
     * Abstract Module constructor.
     *
     * @param Bronto\SoapClient|null $client
     */
    public function __construct(Bronto\SoapClient $client)
    {
        $this->client = $client;
    }
}
<file_sep><?php

namespace Arkade\Bronto\Factories;

use Arkade\Bronto\Entities\Product;
use Carbon\Carbon;

class ProductFactory
{
    /**
     * Make an product entity.
     *
     * @return Entities\Product
     */
    public function make()
    {
        $product = new Product();
        $product->setProductId('9330947716452');
        $product->setTitle('SPARKLE CARDI CHEESE');
        $product->setColor('REBLK001');
        $product->setUpc('9330947716452');
        $product->setBrand('TEST');
        $product->setAvailabilityDate(Carbon::parse('2017-05-12'));

        return $product;
    }
}<file_sep><?php

namespace Arkade\Bronto\Modules;

use GuzzleHttp\Psr7\Response;
use Arkade\Bronto\Factories;
use PHPUnit\Framework\TestCase;
use Arkade\Bronto\InteractsWithClient;
use Arkade\Bronto\Entities\Product;
use Illuminate\Support\Collection;

class ProductServiceTest extends TestCase
{
    use InteractsWithClient;

    /**
     * @test
     */
    public function product_find()
    {
        // Create the container.
        $history = [];

        // Create a mock response object.
        $client = $this->createClient([
            new Response(200, ['Content-Type' => 'application/json'],
                file_get_contents(__DIR__.'../../Stubs/Products/product.json')
            )
        ], $history);

        $response = $client->productService()->find('9330947716452');

        $this->assertInstanceOf(Product::class, $response);

    }

    /**
     * @test
     */
    public function product_feed_import()
    {
        // Create the container.
        $history = [];

        // Create a mock response object.
        $client = $this->createClient([
            new Response(200, [], null
            )
        ], $history);

        $products = (new Factories\ProductsFactory)->make();
        $response = $client->productService()->feedImport($products);

        $this->assertNull($response);

    }

    /**
     * @test
     */
    public function product_update()
    {
        // Create the container.
        $history = [];

        // Create a mock response object.
        $client = $this->createClient([
            new Response(200, [], null
            )
        ], $history);

        $product = (new Factories\ProductFactory)->make();
        $response = $client->productService()->update($product);

        $this->assertNull($response);

    }

}<file_sep><?php

namespace Omneo\Bronto\Serializers;

use Omneo\Bronto\Entities;

class DeliverySerializer
{
    /**
     * Serialize.
     *
     * @param Entities\Delivery $delivery
     * @return string
     */
    public function serialize(Entities\Delivery $delivery)
    {
        // trigger the entities jsonSerialize method
        $serialized = json_decode(json_encode($delivery));

        $serialized->start = $delivery->getStart()->toIso8601String();

        return json_encode($serialized);
    }
}<file_sep><?php

namespace Omneo\Bronto\Modules;

use Omneo\Bronto\Entities\Product;
use Omneo\Bronto\Parsers\ProductParser;
use Omneo\Bronto\Serializers\ProductSerializer;
use Illuminate\Support\Collection;
use League\Csv\Writer;

class ProductService extends AbstractRestModule
{
    /**
     * Product find.
     * Uses product ID
     *
     * @param $id
     * @return Product
     */
    public function find($id)
    {
        return (new ProductParser)->parse(
            $this->client->get(
                'products/public/catalogs/' . $this->client->getProductsApiId() . '/products/' . $id,
                ['debug' => env('APP_DEBUG')]
            )
        );
    }

    /**
     * Product feed import.
     *
     * @param array $products
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function feedImport($products)
    {
        $csv = Writer::createFromFileObject(new \SplTempFileObject());
        $csv->insertOne(array_keys(json_decode((new ProductSerializer())->serialize($products[0]), true)));

        foreach ($products as $product) {
            $csv->insertOne(array_values(json_decode((new ProductSerializer())->serialize($product), true)));
        }

        return $this->client->post('products/public/feed_import/', [
            'debug'     => env('APP_DEBUG'),
            'multipart' => [
                [
                    'name'     => 'catalogId',
                    'contents' => $this->client->getProductsApiId()
                ],
                [
                    'name'     => 'feed',
                    'contents' => $csv->__toString()
                ]
            ]
        ]);
    }

    /**
     * Product update.
     *
     * @param $product
     * @return Product
     */
    public function update(Product $product)
    {
        $payload         = new \stdClass();
        $payload->fields = json_decode((new ProductSerializer)->serialize($product));
        $payload         = json_encode([$payload]);

        $this->client->put(
            'products/public/catalogs/' . $this->client->getProductsApiId() . '/products',
            [
                'headers' => ['Content-Type' => 'application/json'],
                'body'    => $payload,
                'debug'   => env('APP_DEBUG')
            ]
        );
    }

}<file_sep><?php

namespace Arkade\Bronto\Factories;

use Arkade\Bronto\Entities\OrderState;
use Arkade\Bronto\Entities\LineItem;
use Arkade\Bronto\Entities\Order;
use Carbon\Carbon;

class OrderFactory
{
    /**
     * Make an order entity.
     *
     * @return Entities\Order
     */
    public function make()
    {
        $orderState = new OrderState();
        $orderState->setProcessed(true);
        $orderState->setShipped(false);

        $orderItem1 = new LineItem();
        $orderItem1->setName('someItemName1');
        $orderItem1->setDescription('item description');
        $orderItem1->setQuantity(1);
        $orderItem1->setSku('AS1210000');
        $orderItem1->setSalePrice('90.00');
        $orderItem1->setTotalPrice('100.00');

        $orderItem2 = new LineItem();
        $orderItem2->setName('someItemName2');
        $orderItem2->setDescription('item description');
        $orderItem2->setQuantity(1);
        $orderItem2->setSku('AS3420000');
        $orderItem2->setSalePrice('40.00');
        $orderItem2->setTotalPrice('50.00');

        $order = new Order();
        $order->setGrandTotal('160.00');
        $order->setOrderDate(Carbon::parse('2017-05-12T00:00:00.000Z'));
        $order->setTaxAmount('15.00');
        $order->setCurrency('AUD');
        $order->setCustomerOrderId('ORDER-123456789');

        $order->setLineItems(collect([$orderItem1,$orderItem2]));
        $order->setStates($orderState);

        return $order;
    }
}<file_sep><?php

namespace Omneo\Bronto\Modules;

use Omneo\Bronto\SoapClient;
use Omneo\Bronto\Entities\Contact;
use Omneo\Bronto\Parsers\ContactUnsubscribeParser;
use Omneo\Bronto\Serializers\ContactSerializer;
use Omneo\Bronto\Parsers\ContactParser;
use Omneo\Bronto\Exceptions;
use Carbon\Carbon;
use Illuminate\Support\Collection;

class ContactService extends AbstractSoapModule
{
    /**
     * @var Collection
     */
    protected $mappings;

    /**
     * constructor.
     *
     * @param SoapClient|null $client
     * @param Collection $mappings
     */
    public function __construct(SoapClient $client, Collection $mappings)
    {
        $this->mappings = $mappings;

        parent::__construct($client);
    }

    /**
     * Create a contact in Bronto
     *
     * @param Contact $contact
     * @return Contact
     * @throws Exceptions\BrontoException
     */
    public function create(Contact $contact)
    {
        $contactRow = $this->buildContactRow($contact);

        // Save
        try {
            return (new ContactParser)->parse($contactRow->save(), $this->mappings);
        } catch (\Exception $e) {
            throw new Exceptions\BrontoException((string)$e->getMessage(),
                $e->getCode());
        }
    }

    /**
     * @param Contact $contact
     * @return \Bronto_Api_Rowset
     * @throws Exceptions\BrontoException
     */
    public function update(Contact $contact) {
        $contactRow = $this->buildContactRow($contact);

        // Update
        try {
            return $contactRow->getApiObject()->update($contactRow->getData());
        } catch (\Exception $e) {
            throw new Exceptions\BrontoException((string)$e->getMessage(),
                $e->getCode());
        }
    }

    /**
     * @param Contact $contact
     * @return \Bronto_Api_Contact_Row
     */
    public function buildContactRow(Contact $contact){
        $contactObject = $this->client->getClient()->getContactObject();

        $contactRow = $contactObject->createRow();
        $contactRow->id = $contact->getId();
        $contactRow->email = $contact->getEmail();
        $contactRow->status = $contact->getStatus();
        $contactRow->mobileNumber = $contact->getMobileNumber();

        // Add Contact to List
        $contactRow->addToList($this->client->getListId());

        // Transform the Contact entity to a flattened array
        $contactArray = array_filter(json_decode((new ContactSerializer())->serialize($contact),true));

        // Map the fields to Bronto field ID's and set the fields on the contact row
        foreach ($contactArray as $key => $value){
            if($key === 'email' || $key === 'id' || $key === 'status' || $key === 'mobileNumber') continue;
            $this->mappings->each(function($mapping) use($key, $value, &$contactRow){
                if($key === $mapping['bronto_name']){
                    $contactRow->setField($mapping['bronto_id'], (string)$value);
                }
            });
        }

        return $contactRow;
    }

    /**
     * Find contact by ID
     *
     * @param string ID
     * @return Contact
     * @throws Exceptions\BrontoException
     */
    public function findById($id)
    {
        $contactObject = $this->client->getClient()->getContactObject();

        $contactsFilter['id'] = [$id];
        //$contactsFilter['listId'] = [$this->client->getListId()];

        $fields = [];
        $this->mappings->each(function($mapping) use(&$fields){
            $fields[] = $mapping['bronto_id'];
        });

        try {
            $contacts = $contactObject->readAll($contactsFilter, $fields, false);

            if (!$contacts->count()) return null;

            return (new ContactParser)->parse($contacts[0], $this->mappings);
        } catch (\Exception $e) {
            throw new Exceptions\BrontoException((string)$e->getResponse()->getBody(),
                $e->getResponse()->getStatusCode());
        }
    }

    /**
     * Find contact by Email
     *
     * @param string $email
     * @return Contact
     */
    public function findByEmail($email)
    {
        $contactObject = $this->client->getClient()->getContactObject();

        $contactsFilter['email'] = ['value' => $email, 'operator' => 'EqualTo'];
        $contactsFilter['listId'] = [$this->client->getListId()];

        $fields = [];
        $this->mappings->each(function($mapping) use(&$fields){
            $fields[] = $mapping['bronto_id'];
        });

        $contacts = $contactObject->readAll($contactsFilter, $fields, false);

        if (!$contacts->count()) return null;

        return (new ContactParser)->parse($contacts[0], $this->mappings);
    }

    /**
     * Get contacts updated since
     *
     * @param Carbon $date
     * @param int $page
     * @return Collection
     */
    public function getContactsUpdatedSince($date, $page = 1)
    {
        $contactObject = $this->client->getClient()->getContactObject();

        $value = $date->format('Y-m-d\Th:m:s.BP');

        $contactsFilter['modified'] = ['value' => $value, 'operator' => 'After'];
        $contactsFilter['listId'] = [$this->client->getListId()];

        $fields = [];
        $this->mappings->each(function($mapping) use(&$fields){
            $fields[] = $mapping['bronto_id'];
        });

        $contacts = $contactObject->readAll($contactsFilter, $fields, false, $page);

        $parseContacts = collect([]);

        foreach($contacts as $contact) {
            $parseContacts->push(
                (new ContactParser)->parse($contact, $this->mappings)
            );
        }

        return $parseContacts;

    }

    /**
     * Get contacts by status
     *
     * @param string $status
     * @param Carbon $date
     * @param int $page
     * @return Collection
     */
    public function getContactsByStatus($status, $date, $page = 1)
    {
        $contactObject = $this->client->getClient()->getContactObject();

        $value = $date->format('Y-m-d\Th:m:s.BP');

        $contactsFilter['status'] = [$status];
        $contactsFilter['created'] = ['value' => $value, 'operator' => 'After'];
        $contactsFilter['listId'] = [$this->client->getListId()];

        $fields = [];
        $this->mappings->each(function($mapping) use(&$fields){
            $fields[] = $mapping['bronto_id'];
        });

        $contacts = $contactObject->readAll($contactsFilter, $fields, false, $page);

        $parseContacts = collect([]);

        foreach($contacts as $contact) {
            $parseContacts->push(
                (new ContactParser)->parse($contact, $this->mappings)
            );
        }

        return $parseContacts;

    }

    /**
     * Get unsubscribes
     *
     * @param Carbon $date
     * @param int $page
     * @return Collection
     */
    public function getUnsubscribes($date, $page = 1)
    {
        $contactObject = $this->client->getClient()->getContactObject();

        $value = $date->format('Y-m-d\Th:m:s.BP');

        $contactsFilter['status'] = ['unsub'];
        $contactsFilter['modified'] = ['value' => $value, 'operator' => 'After'];

        $fields = [];

        $contacts = $contactObject->readAll($contactsFilter, $fields, false, $page);

        return (new ContactUnsubscribeParser())->parse($contacts);

    }

    /**
     * Get bounces
     *
     * @param Carbon $date
     * @param int $page
     * @return Collection
     */
    public function getBounces($date, $page = 1)
    {
        $contactObject = $this->client->getClient()->getContactObject();

        $value = $date->format('Y-m-d\Th:m:s.BP');

        $contactsFilter['status'] = ['bounce'];
        $contactsFilter['modified'] = ['value' => $value, 'operator' => 'After'];

        $fields = [];

        $contacts = $contactObject->readAll($contactsFilter, $fields, false, $page);

        return (new ContactUnsubscribeParser())->parse($contacts);

    }

    /**
     * Get fields
     *
     * @return Collection
     * @throws Exceptions\BrontoException
     */
    public function getFields()
    {
        $fieldObject = $this->client->getClient()->getFieldObject();

        try {

            $fields = $fieldObject->readAll();
            $result = collect([]);

            foreach($fields as $field){
                $field = $field->toArray();
                $result->push($field);
            }

            return $result;

        } catch (\Exception $e) {
            throw new Exceptions\BrontoException((string)$e->getResponse()->getBody(),
                $e->getResponse()->getStatusCode());
        }
    }

    /**
     * Output fields for bronto config file
     *
     * @return void
     * @throws Exceptions\BrontoException
     */
    public function outputFields()
    {
        $fieldObject = $this->client->getClient()->getFieldObject();

        try {

            $fields = $fieldObject->readAll();

            foreach($fields as $field){
                $field = $field->toArray();
                echo "'" . $field['name'] . "' => " . "'" . $field['id'] . "',\r\n";
            }

        } catch (\Exception $e) {
            throw new Exceptions\BrontoException((string)$e->getResponse()->getBody(),
                $e->getResponse()->getStatusCode());
        }
    }

}
<file_sep><?php

namespace Omneo\Bronto\Serializers;

use Omneo\Bronto\Entities;

class OrderSerializer
{
    /**
     * Serialize.
     *
     * @param  Entities\Order $order
     * @return string
     */
    public function serialize(Entities\Order $order)
    {
        // trigger the entities jsonSerialize method
        $serialized = json_decode(json_encode($order));

        // these can never be set when sending to bronto
        // only populated with a parsed response from bronto
        unset($serialized->orderId);
        unset($serialized->createdDate);
        unset($serialized->updatedDate);

        // tracking cookie params cannot be null
        if(is_null($serialized->trackingCookieName)) unset($serialized->trackingCookieName);
        if(is_null($serialized->trackingCookieValue)) unset($serialized->trackingCookieValue);

        return json_encode($serialized);
    }
}<file_sep><?php

namespace Omneo\Bronto\Entities;

class AbstractEntity implements \JsonSerializable
{

    /**
     * @return Array
     */
    public function jsonSerialize()
    {
        return get_object_vars($this);
    }

}
<file_sep># Bronto PHP SDK

This SDK provides simple access to the Bronto API. It handles most Bronto associated complexities including authentication, entity abstraction, errors and more.
<file_sep><?php

namespace Omneo\Bronto\Parsers;

use Omneo\Bronto\Entities;

class OrderStateParser
{
    /**
     * Parse the given array to a OrderState entity.
     *
     * @param  array $payload
     * @return Entities\OrderState
     */
    public function parse($payload)
    {
        $orderState = (new Entities\OrderState())
            ->setProcessed($payload->processed)
            ->setShipped($payload->shipped);

        return $orderState;
    }
}<file_sep><?php

namespace Arkade\Bronto\Parsers;

use Carbon\Carbon;
use Arkade\Bronto\Entities\Product;
use PHPUnit\Framework\TestCase;
use Illuminate\Support\Collection;

class ProductParserTest extends TestCase
{
    /**
     * @test
     */
    public function returns_populated_product()
    {
        $product = (new ProductParser)->parse(
            json_decode(file_get_contents(__DIR__.'/../Stubs/Products/product.json'))
        );

        $this->assertInstanceOf(Product::class, $product);

        $this->assertEquals(null, $product->getAgeGroup());
        $this->assertEquals(null, $product->getAvailability());
        $this->assertEquals(null, $product->getAvailabilityDate());
        $this->assertEquals(null, $product->getAverageRating());
        $this->assertEquals('TEST', $product->getBrand());
        $this->assertEquals('REBLK001', $product->getColor());
        $this->assertEquals(null, $product->getCondition());
        $this->assertEquals(null, $product->getDescription());
        $this->assertEquals(null, $product->getGender());
        $this->assertEquals(null, $product->getGtin());
        $this->assertEquals(null, $product->getImageUrl());
        $this->assertEquals(null, $product->getInventoryThreshold());
        $this->assertEquals(null, $product->getIsbn());
        $this->assertEquals(null, $product->getMpn());
        $this->assertEquals(null, $product->getMargin());
        $this->assertEquals(null, $product->getMobileUrl());
        $this->assertEquals(null, $product->getParentProductId());
        $this->assertEquals(null, $product->getPrice());
        $this->assertEquals(null, $product->getPrice());
        $this->assertEquals(null, $product->getProductCategory());
        $this->assertEquals('9330947716452', $product->getProductId());
        $this->assertEquals(null, $product->getProductTypeMulti());
        $this->assertEquals(null, $product->getProductUrl());
        $this->assertEquals(null, $product->getQuantity());
        $this->assertEquals(null, $product->getReviewCount());
        $this->assertEquals(null, $product->getSalePrice());
        $this->assertEquals(null, $product->getSalePriceEffectiveStartDate());
        $this->assertEquals(null, $product->getSalePriceEffectiveEndDate());
        $this->assertEquals(null, $product->getSize());
        $this->assertEquals('SPARKLE CARDI CHEESE', $product->getTitle());
        $this->assertEquals('9330947716452', $product->getUpc());
        $this->assertEquals(Carbon::parse('2017-12-05T22:00:42.236Z'), $product->getUpdatedDate());
        $this->assertEquals(Carbon::parse('2017-12-05T00:39:47.618Z'), $product->getCreatedDate());
    }

}
<file_sep><?php

namespace Omneo\Bronto;

use GuzzleHttp;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Log;
use Omneo\Bronto;

class LaravelServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application events.
     *
     * @return void
     */
    public function boot()
    {
        // Publish the config.
        $this->publishes([
            __DIR__ . '/Config/bronto.php' => config_path('bronto.php'),
        ]);
    }

    /**
     * Register bindings in the container.
     *
     * @return void
     */
    public function register()
    {
        // Setup the rest client auth.
        $this->app->singleton(Bronto\RestAuthentication::class, function(){
            return (new Bronto\RestAuthentication)
                ->setAuthUrl(config('services.bronto.auth_url'))
                ->setEndpoint(config('services.bronto.endpoint'))
                ->setClientId(config('services.bronto.client_id'))
                ->setClientSecret(config('services.bronto.client_secret'));
        });

        // Setup the rest client.
        $this->app->singleton(Bronto\RestClient::class, function () {
            $client = (new Bronto\RestClient(resolve(Bronto\RestAuthentication::class)))
                ->setProductsApiId(config('services.bronto.products_api_id'))
                ->setLogging(config('services.bronto.logging'))
                ->setVerifyPeer(config('app.env') === 'production')
                ->setLogger(Log::getMonolog());

            $this->setupRecorder($client);

            return $client;
        });

        // Setup the soap client
        $this->app->singleton(Bronto\SoapClient::class, function () {
            return (new Bronto\SoapClient())
                ->setToken(config('services.bronto.soap_token'))
                ->setListId(config('services.bronto.list_id'));
        });
    }

    /**
     * Setup recorder middleware if the HttpRecorder package is bound.
     *
     * @param  Client $client
     * @return Client
     */
    protected function setupRecorder(RestClient $client)
    {
        if (! $this->app->bound('Omneo\Plugins\HttpRecorder\Recorder')) {
            return $client->setupClient();
        }

        $stack = GuzzleHttp\HandlerStack::create();

        $stack->push(
            $this->app
                ->make('Omneo\Plugins\HttpRecorder\GuzzleIntegration')
                ->getMiddleware(['bronto', 'outgoing'])
        );

        return $client->setupClient($stack);
    }
}
<file_sep><?php

namespace Omneo\Bronto\Serializers;

use Omneo\Bronto\Entities;
use Carbon\Carbon;

class ProductSerializer
{
    /**
     * Serialize.
     *
     * @param  Entities\Product $product
     * @return string
     */
    public function serialize(Entities\Product $product)
    {
        // trigger the entities jsonSerialize method
        $serialized = json_decode(json_encode($product));

        // dates to bronto need to be in ISO 8601
        if(!is_null($serialized->salePriceEffectiveStartDate)) $serialized->salePriceEffectiveStartDate = (new Carbon($serialized->salePriceEffectiveStartDate))->toIso8601String();
        if(!is_null($serialized->salePriceEffectiveEndDate)) $serialized->salePriceEffectiveEndDate = (new Carbon($serialized->salePriceEffectiveEndDate))->toIso8601String();
        if(!is_null($serialized->availabilityDate)) $serialized->availabilityDate = (new Carbon($serialized->availabilityDate))->toIso8601String();

        // bronto product fields are stored in snake case
        $vars = get_object_vars($serialized);
        $serialized = [];
        foreach ($vars as $key => $value){
            $serialized[snake_case($key)] = $value;
        }

        return json_encode($serialized);
    }
}<file_sep><?php

namespace Omneo\Bronto\Parsers;

use Omneo\Bronto\Entities\Contact;
use Carbon\Carbon;
use Omneo\Bronto\Entities;
use Illuminate\Support\Collection;

class ContactParser
{
    /**
     * Parse the given array to a Contact entity.
     *
     * @param  array $payload
     * @param  Collection $mappings
     * @return Contact
     */
    public function parse($payload, $mappings)
    {
        $contact = (new Entities\Contact)
            ->setId($payload->id)
            ->setEmail($payload->email)
            ->setMobileNumber($payload->mobileNumber)
            ->setStatus($payload->status);

        $attributes = [];

        foreach($payload->fields as $field){
            $mappings->each(function($mapping) use(&$attributes, $field){
                if($field['fieldId'] === $mapping['bronto_id']){
                    $attributes[$mapping['bronto_name']] = $field['content'];
                }
            });
        }

        $contact->setAttributes(new Collection($attributes));

        return $contact;
    }
}<file_sep><?php

namespace Omneo\Bronto\Parsers;

use Carbon\Carbon;
use Omneo\Bronto\Entities;

class ProductParser
{
    /**
     * Parse the given array to a Product entity.
     *
     * @param mixed $payload
     * @return Entities\Product
     */
    public function parse($payload)
    {
        $product = new Entities\Product();

        if (!empty($payload->fields)) {
            foreach ($payload->fields as $field) {
                $value      = (null !== $field->value && $field->type === 'date') ? Carbon::parse((string)$field->value) : $field->value;
                $setterName = camel_case('set_' . $field->name);
                if (method_exists($product, $setterName)) {
                    $product->{$setterName}($value);
                }
            }
        }

        return $product;
    }
}<file_sep><?php

namespace Omneo\Bronto\Entities;

use Carbon\Carbon;
use Illuminate\Support\Collection;

class DeliveryRemail extends AbstractEntity
{
    /**
     * @var int
     */
    protected $days;

    /**
     * @var Carbon
     */
    protected $time;

    /**
     * @var string
     */
    protected $subject;

    /**
     * @var string
     */
    protected $messageId;

    /**
     * @var string
     */
    protected $activity;

    /**
     * @return int
     */
    public function getDays()
    {
        return $this->days;
    }

    /**
     * The number of days until the remail will trigger.
     * @param int $days
     * @return DeliveryRemail
     */
    public function setDays($days)
    {
        $this->days = $days;
        return $this;
    }

    /**
     * @return Carbon
     */
    public function getTime()
    {
        return $this->time;
    }

    /**
     * The time at which the remail will trigger. The time should be in 24 hour format: HH:MM:SS
     * Note: Do not add a time zone offset for the remail time.
     * The time for the remail will use the time zone specified for the delivery object.
     * @param Carbon $time
     * @return DeliveryRemail
     */
    public function setTime(Carbon $time = null)
    {
        $this->time = $time;
        return $this;
    }

    /**
     * @return string
     */
    public function getSubject()
    {
        return $this->subject;
    }

    /**
     * @param string $subject
     * @return DeliveryRemail
     */
    public function setSubject($subject)
    {
        $this->subject = $subject;
        return $this;
    }

    /**
     * @return string
     */
    public function getMessageId()
    {
        return $this->messageId;
    }

    /**
     * @param string $messageId
     * @return DeliveryRemail
     */
    public function setMessageId($messageId)
    {
        $this->messageId = $messageId;
        return $this;
    }

    /**
     * The activity that will trigger the remail. Valid values are: noopen, opennoclick, or clicknoconvert
     * @return string
     */
    public function getActivity()
    {
        return $this->activity;
    }

    /**
     * @param string $activity
     * @return DeliveryRemail
     */
    public function setActivity($activity)
    {
        $this->activity = $activity;
        return $this;
    }

    /**
     * @return Array
     */
    public function jsonSerialize()
    {
        $result = get_object_vars($this);

        return $result;
    }

}
<file_sep><?php

namespace Omneo\Bronto\Serializers;

use Omneo\Bronto\Entities;

class ContactSerializer
{
    /**
     * Serialize.
     *
     * @param Entities\Contact $contact
     * @return string
     */
    public function serialize(Entities\Contact $contact)
    {
        // trigger the entities jsonSerialize method
        $serialized = json_decode(json_encode($contact));

        // flatten attributes
        if(isset($serialized->attributes)){
            foreach ($serialized->attributes as $attribute){
                $vars = get_object_vars($attribute);
                foreach($vars as $key=>$value){
                    $serialized->$key = $value;
                }
            }
            unset($serialized->attributes);
        }

        return json_encode($serialized);
    }
}<file_sep><?php

namespace Omneo\Bronto;

use GuzzleHttp;
use Carbon\Carbon;

class RestAuthentication
{
    /**
     * Guzzle client.
     *
     * @var GuzzleHttp\Client
     */
    protected $guzzle;

    /**
     * Auth URL.
     *
     * @var string
     */
    protected $authUrl;

    /**
     * Client ID.
     *
     * @var string
     */
    protected $clientId;

    /**
     * Client Secret.
     *
     * @var string
     */
    protected $clientSecret;

    /**
     * Endpoint.
     *
     * @var string
     */
    protected $endpoint;

    /**
     * Token.
     *
     * @var string
     */
    protected $token;

    /**
     * Token expiry.
     *
     * @var string
     */
    protected $tokenExpiry;

    /**
     * Refresh Token.
     *
     * @var string
     */
    protected $refreshToken;

    /**
     * Authentication constructor.
     *
     * @param GuzzleHttp\HandlerStack $handler
     */
    public function __construct(GuzzleHttp\HandlerStack $handler = null)
    {
        $this->guzzle = new GuzzleHttp\Client([
            'handler' => $handler ? $handler : GuzzleHttp\HandlerStack::create(),
        ]);
    }

    /**
     * Set the auth URL.
     *
     * @param string $authUrl
     * @return $this
     */
    public function setAuthUrl($authUrl)
    {
        $this->authUrl = $authUrl;

        return $this;
    }

    /**
     * Get the auth URL.
     *
     * @return string
     */
    public function getAuthUrl()
    {
        return $this->authUrl;
    }

    /**
     * Set the client ID.
     *
     * @param string $clientId
     * @return $this
     */
    public function setClientId($clientId)
    {
        $this->clientId = $clientId;

        return $this;
    }

    /**
     * Get the client ID.
     *
     * @return string
     */
    public function getClientId()
    {
        return $this->clientId;
    }

    /**
     * Set the client secret.
     *
     * @param string $clientSecret
     * @return $this
     */
    public function setClientSecret($clientSecret)
    {
        $this->clientSecret = $clientSecret;

        return $this;
    }

    /**
     * Get the client secret.
     *
     * @return string
     */
    public function getClientSecret()
    {
        return $this->clientSecret;
    }

    /**
     * Set the endpoint.
     *
     * @param string $url
     * @return $this
     */
    public function setEndpoint($url)
    {
        $this->endpoint = $url;

        return $this;
    }

    /**
     * Get the endpoint.
     *
     * @return string
     */
    public function getEndpoint()
    {
        return $this->endpoint;
    }

    /**
     * Get a token.
     *
     * @return string
     */
    public function getToken()
    {
        if ($this->token) return $this->isTokenExpired() ? $this->refreshOauthToken() : $this->token;

        return $this->createOauthToken();
    }

    /**
     * Set the token.
     *
     * @param $token
     * @return $this
     */
    public function setToken($token)
    {
        $this->token = $token;

        return $this;
    }

    /**
     * Get the token expiry.
     *
     * @return mixed
     */
    public function getTokenExpiry()
    {
        return $this->tokenExpiry;
    }

    /**
     * Set token expiry.
     *
     * @param $tokenExpiry
     * @return $this
     */
    public function setTokenExpiry($tokenExpiry)
    {
        $this->tokenExpiry = $tokenExpiry;

        return $this;
    }

    /**
     * Get the refresh token.
     *
     * @return string
     */
    public function getRefreshToken()
    {
        return $this->refreshToken;
    }

    /**
     * Set the refresh token.
     *
     * @param $refreshToken
     * @return $this
     */
    public function setRefreshToken($refreshToken)
    {
        $this->refreshToken = $refreshToken;

        return $this;
    }

    /**
     * Create oauth token.
     *
     * @return string
     */
    public function createOauthToken()
    {
        $params = [
            'form_params' => [
                'grant_type' => 'client_credentials',
                'client_id' => $this->clientId,
                'client_secret' => $this->clientSecret,
            ],
        ];

        // Make the Request and process the response
        $response = $this->guzzle->request('POST', $this->getAuthUrl(), $params);
        $result = json_decode((string) $response->getBody());

        $this->setToken($result->access_token)
             ->setTokenExpiry(
                 Carbon::now()
                     ->addSeconds($result->expires_in)
             )
             ->setRefreshToken($result->refresh_token);

        return $this->token;
    }

    /**
     * Refresh oauth token.
     *
     * @return string
     */
    public function refreshOauthToken()
    {
        // Setup our auth parameters
        $params = [
            'form_params' => [
                'grant_type' => 'refresh_token',
                'client_id' => $this->clientId,
                'client_secret' => $this->clientSecret,
                'refresh_token' => $this->refreshToken,
            ],
        ];

        // Make the Request and process the response
        $response = $this->guzzle->request('POST', $this->getAuthUrl(), $params);
        $result = json_decode((string) $response->getBody());

        $this->setToken($result->access_token)
             ->setTokenExpiry(
                 Carbon::now()
                     ->addSeconds($result->expires_in)
             )
             ->setRefreshToken($result->refresh_token);

        return $this->token;
    }

    /**
     * Determine if a token has expired.
     *
     * @return bool
     */
    public function isTokenExpired()
    {
        return Carbon::now()->greaterThanOrEqualTo($this->getTokenExpiry()->subMinutes(5));
    }
}
<file_sep><?php

namespace Arkade\Bronto;

use Arkade\Bronto\RestAuthentication;
use Arkade\Bronto\RestClient;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;

trait InteractsWithClient
{
    /**
     * Create a history stack.
     *
     * @param $container
     * @return HandlerStack
     */
    protected function createHistoryMiddleware(&$container)
    {
        return Middleware::history($container);
    }

    /**
     * Create a Responsys mock client.
     *
     * @param array $responses
     * @param $history
     * @return Client
     */
    private function createClient(array $responses, &$history)
    {
        // Add the auth response.
        $responses = array_prepend($responses, new Response(200, [], json_encode([
            'access_token' => '<PASSWORD>',
            'refresh_token' => '<PASSWORD>',
            'expires_in'  => 3600,
        ])));

        $stack = HandlerStack::create(new MockHandler($responses));

        $stack->push($this->createHistoryMiddleware($history));

        $auth = new RestAuthentication($stack);

        $auth->setAuthUrl('https://auth.bronto.com/oauth2/token');
        $auth->setClientId('arkade');
        $auth->setClientSecret('secret');
        $auth->setEndpoint('https://rest.bronto.com');

        $client = new RestClient($auth, $stack);

        return $client;
    }

    /**
     * Get the request body.
     *
     * @param Request $request
     * @return mixed
     */
    protected function getRequestBody(Request $request)
    {
        return json_decode((string) $request->getBody());
    }
}<file_sep><?php

namespace Arkade\Bronto\Modules;

use GuzzleHttp\Psr7\Response;
use Arkade\Bronto\Factories;
use PHPUnit\Framework\TestCase;
use Arkade\Bronto\InteractsWithClient;
use Arkade\Bronto\Entities\Order;
use Illuminate\Support\Collection;

class OrderServiceTest extends TestCase
{
    use InteractsWithClient;

    /**
     * @test
     */
    public function order_find()
    {
        // Create the container.
        $history = [];

        // Create a mock response object.
        $client = $this->createClient([
            new Response(200, ['Content-Type' => 'application/json'],
                file_get_contents(__DIR__.'../../Stubs/Orders/order.json')
            )
        ], $history);

        $response = $client->orderService()->find('52e2ba9d-b339-4859-aeec-43a79cf6bfd7');

        $this->assertInstanceOf(Order::class, $response);

    }

    /**
     * @test
     */
    public function order_find_by_id()
    {
        // Create the container.
        $history = [];

        // Create a mock response object.
        $client = $this->createClient([
            new Response(200, ['Content-Type' => 'application/json'],
                '[' . file_get_contents(__DIR__.'../../Stubs/Orders/order.json') . ']'
            )
        ], $history);

        $response = $client->orderService()->findById('ORDER-123456789');

        $this->assertInstanceOf(Collection::class, $response);

    }

    /**
     * @test
     */
    public function order_add()
    {
        // Create the container.
        $history = [];

        // Create a mock response object.
        $client = $this->createClient([
            new Response(200, ['Content-Type' => 'application/json'],
                file_get_contents(__DIR__.'../../Stubs/Orders/order.json')
            )
        ], $history);

        $order = (new Factories\OrderFactory)->make();
        $response = $client->orderService()->add($order);

        $this->assertInstanceOf(Order::class, $response);

    }

    /**
     * @test
     */
    public function order_update()
    {
        // Create the container.
        $history = [];

        // Create a mock response object.
        $client = $this->createClient([
            new Response(200, ['Content-Type' => 'application/json'],
                file_get_contents(__DIR__.'../../Stubs/Orders/order.json')
            )
        ], $history);

        $order = (new Factories\OrderFactory)->make();
        $response = $client->orderService()->update($order);

        $this->assertInstanceOf(Order::class, $response);

    }

    /**
     * @test
     */
    public function order_update_by_id()
    {
        // Create the container.
        $history = [];

        // Create a mock response object.
        $client = $this->createClient([
            new Response(200, ['Content-Type' => 'application/json'],
                file_get_contents(__DIR__.'../../Stubs/Orders/order.json')
            )
        ], $history);

        $order = (new Factories\OrderFactory)->make();
        $response = $client->orderService()->updateById($order);

        $this->assertInstanceOf(Order::class, $response);

    }

    /**
     * @test
     */
    public function order_delete()
    {
        // Create the container.
        $history = [];

        // Create a mock response object.
        $client = $this->createClient([
            new Response(204, [], null
            )
        ], $history);

        $response = $client->orderService()->delete('52e2ba9d-b339-4859-aeec-43a79cf6bfd7');

        $this->assertNull($response);

    }

    /**
     * @test
     */
    public function order_delete_by_id()
    {
        // Create the container.
        $history = [];

        // Create a mock response object.
        $client = $this->createClient([
            new Response(204, [], null
            )
        ], $history);

        $response = $client->orderService()->deleteById('ORDER-123456789');

        $this->assertNull($response);

    }

}<file_sep><?php

namespace Omneo\Bronto\Entities;

class OrderState extends AbstractEntity
{
    /**
     * @var boolean
     */
    protected $processed = false;

    /**
     * @var boolean
     */
    protected $shipped = false;

    /**
     * @return bool
     */
    public function getProcessed()
    {
        return $this->processed;
    }

    /**
     * @param bool $processed
     * @return OrderState
     */
    public function setProcessed($processed)
    {
        $this->processed = $processed;
        return $this;
    }

    /**
     * @return string
     */
    public function getShipped()
    {
        return $this->shipped;
    }

    /**
     * @param string $shipped
     * @return OrderState
     */
    public function setShipped($shipped)
    {
        $this->shipped = $shipped;
        return $this;
    }



}
<file_sep><?php

namespace Omneo\Bronto\Exceptions;

use Exception;

class BrontoException extends Exception
{
    //
}
<file_sep><?php

namespace Omneo\Bronto\Entities;

use Carbon\Carbon;
use Illuminate\Support\Collection;

class DeliveryProduct extends AbstractEntity
{
    /**
     * @var string
     */
    protected $placeholder;

    /**
     * @var string
     */
    protected $productId;

    /**
     * @return string
     */
    public function getPlaceholder()
    {
        return $this->placeholder;
    }

    /**
     * Placeholder text used in a product tag. Maximum of 50 characters.
     * @param string $placeholder
     * @return DeliveryProduct
     */
    public function setPlaceholder($placeholder)
    {
        $this->placeholder = $placeholder;
        return $this;
    }

    /**
     * @return string
     */
    public function getProductId()
    {
        return $this->productId;
    }

    /**
     * A valid Product ID that will replace the placeholder on message send. Maximum of 50 characters.
     * @param string $productId
     * @return DeliveryProduct
     */
    public function setProductId($productId)
    {
        $this->productId = $productId;
        return $this;
    }

    /**
     * @return Array
     */
    public function jsonSerialize()
    {
        $result = get_object_vars($this);

        return $result;
    }

}
<file_sep><?php

namespace Omneo\Bronto\Entities;

class LineItem extends AbstractEntity
{
    /**
     * @var string
     */
    protected $name;

    /**
     * @var string
     */
    protected $description;

    /**
     * @var string
     */
    protected $sku;

    /**
     * @var string
     */
    protected $other;

    /**
     * @var string
     */
    protected $imageUrl;

    /**
     * @var string
     */
    protected $category;

    /**
     * @var string
     */
    protected $productUrl;

    /**
     * @var integer
     */
    protected $quantity;

    /**
     * @var float
     */
    protected $salePrice;

    /**
     * @var float
     */
    protected $totalPrice;

    /**
     * @var float
     */
    protected $unitPrice;

    /**
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param string $name
     * @return LineItem
     */
    public function setName($name)
    {
        $this->name = $name;
        return $this;
    }

    /**
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * @param string $description
     * @return LineItem
     */
    public function setDescription($description)
    {
        $this->description = $description;
        return $this;
    }

    /**
     * @return string
     */
    public function getSku()
    {
        return $this->sku;
    }

    /**
     * @param string $sku
     * @return LineItem
     */
    public function setSku($sku)
    {
        $this->sku = $sku;
        return $this;
    }

    /**
     * @return string
     */
    public function getOther()
    {
        return $this->other;
    }

    /**
     * @param string $other
     * @return LineItem
     */
    public function setOther($other)
    {
        $this->other = $other;
        return $this;
    }

    /**
     * @return string
     */
    public function getImageUrl()
    {
        return $this->imageUrl;
    }

    /**
     * @param string $imageUrl
     * @return LineItem
     */
    public function setImageUrl($imageUrl)
    {
        $this->imageUrl = $imageUrl;
        return $this;
    }

    /**
     * @return string
     */
    public function getCategory()
    {
        return $this->category;
    }

    /**
     * @param string $category
     * @return LineItem
     */
    public function setCategory($category)
    {
        $this->category = $category;
        return $this;
    }

    /**
     * @return string
     */
    public function getProductUrl()
    {
        return $this->productUrl;
    }

    /**
     * @param string $productUrl
     * @return LineItem
     */
    public function setProductUrl($productUrl)
    {
        $this->productUrl = $productUrl;
        return $this;
    }

    /**
     * @return int
     */
    public function getQuantity()
    {
        return $this->quantity;
    }

    /**
     * @param int $quantity
     * @return LineItem
     */
    public function setQuantity($quantity)
    {
        $this->quantity = $quantity;
        return $this;
    }

    /**
     * @return float
     */
    public function getSalePrice()
    {
        return $this->salePrice;
    }

    /**
     * @param float $salePrice
     * @return LineItem
     */
    public function setSalePrice($salePrice)
    {
        $this->salePrice = $salePrice;
        return $this;
    }

    /**
     * @return float
     */
    public function getTotalPrice()
    {
        return $this->totalPrice;
    }

    /**
     * @param float $totalPrice
     * @return LineItem
     */
    public function setTotalPrice($totalPrice)
    {
        $this->totalPrice = $totalPrice;
        return $this;
    }

    /**
     * @return float
     */
    public function getUnitPrice()
    {
        return $this->unitPrice;
    }

    /**
     * @param float $unitPrice
     * @return LineItem
     */
    public function setUnitPrice($unitPrice)
    {
        $this->unitPrice = $unitPrice;
        return $this;
    }

}
<file_sep><?php

namespace Omneo\Bronto\Parsers;

use Carbon\Carbon;
use Omneo\Bronto\Entities;

class OrderParser
{
    /**
     * Parse the given array to a Order entity.
     *
     * @param  array $payload
     * @return Order
     */
    public function parse($payload)
    {
        $order = (new Entities\Order)
            ->setCartId($payload->cartId)
            ->setCreatedDate(Carbon::parse((string) $payload->createdDate))
            ->setCurrency($payload->currency)
            ->setCustomerOrderId($payload->customerOrderId)
            ->setDiscountAmount($payload->discountAmount)
            ->setEmailAddress($payload->emailAddress)
            ->setGrandTotal($payload->grandTotal)
            ->setOrderId($payload->orderId)
            ->setOriginIp($payload->originIp)
            ->setOriginUserAgent($payload->originUserAgent)
            ->setShippingAmount($payload->shippingAmount)
            ->setShippingDate(null)
            ->setShippingDetails($payload->shippingDetails)
            ->setShippingTrackingUrl($payload->shippingTrackingUrl)
            ->setSubtotal($payload->subtotal)
            ->setTaxAmount($payload->taxAmount)
            ->setTrackingCookieName($payload->trackingCookieName)
            ->setTrackingCookieValue($payload->trackingCookieValue)
            ->setUpdatedDate(Carbon::parse((string) $payload->updatedDate))
            ->setStates(
                (new OrderStateParser)->parse($payload->states)
            );

        if(!is_null($payload->shippingDate)){
            $order->setShippingDate(Carbon::parse((string) $payload->shippingDate));
        }

        if(!is_null($payload->orderDate)){
            $order->setOrderDate(Carbon::parse((string) $payload->orderDate));
        }

        foreach($payload->lineItems as $item){
            $order->getLineItems()->push(
                (new LineItemParser)->parse($item)
            );
        }

        return $order;
    }
}<file_sep><?php

namespace Arkade\Bronto\Parsers;

use Carbon\Carbon;
use Arkade\Bronto\Entities\Order;
use Arkade\Bronto\Entities\LineItem;
use Arkade\Bronto\Entities\OrderState;
use PHPUnit\Framework\TestCase;
use Illuminate\Support\Collection;

class OrderParserTest extends TestCase
{
    /**
     * @test
     */
    public function returns_populated_order()
    {
        $order = (new OrderParser)->parse(
            json_decode(file_get_contents(__DIR__.'/../Stubs/Orders/order.json'))
        );

        $this->assertInstanceOf(Order::class, $order);

        $this->assertEquals(0, $order->getDiscountAmount());
        $this->assertEquals(null, $order->getEmailAddress());
        $this->assertEquals('160.00', $order->getGrandTotal());
        $this->assertEquals(null, $order->getOriginIp());
        $this->assertEquals(0, $order->getShippingAmount());
        $this->assertEquals(null, $order->getShippingDate());
        $this->assertEquals(null, $order->getShippingDetails());
        $this->assertEquals(null, $order->getShippingTrackingUrl());
        $this->assertEquals(0, $order->getSubtotal());
        $this->assertEquals('15.00', $order->getTaxAmount());
        $this->assertEquals(null, $order->getTrackingCookieName());
        $this->assertEquals(null, $order->getTrackingCookieValue());
        $this->assertEquals(null, $order->getTid());
        $this->assertEquals(null, $order->getCartId());
        $this->assertEquals('ORDER-123456789', $order->getCustomerOrderId());
        $this->assertEquals(Carbon::parse('2017-05-12T00:00:00.000Z'), $order->getOrderDate());
        $this->assertEquals('AUD', $order->getCurrency());
        $this->assertEquals('52e2ba9d-b339-4859-aeec-43a79cf6bfd7', $order->getOrderId());
        $this->assertEquals(Carbon::parse('2017-11-28T03:53:14.322Z'), $order->getCreatedDate());
        $this->assertEquals(Carbon::parse('2017-11-28T03:53:14.322Z'), $order->getUpdatedDate());

    }

    /**
     * @test
     */
    public function returns_populated_order_line_items()
    {
        $order = (new OrderParser)->parse(
            json_decode(file_get_contents(__DIR__.'/../Stubs/Orders/order.json'))
        );

        $this->assertInstanceOf(Collection::class, $order->getLineItems());
        $this->assertEquals(2, $order->getLineItems()->count());

        $lineItem = $order->getLineItems()->first();

        $this->assertInstanceOf(LineItem::class, $lineItem);

        $this->assertEquals('someItemName1', $lineItem->getName());
        $this->assertEquals('item description', $lineItem->getDescription());
        $this->assertEquals('AS1210000', $lineItem->getSku());
        $this->assertEquals(null, $lineItem->getOther());
        $this->assertEquals(null, $lineItem->getImageUrl());
        $this->assertEquals(null, $lineItem->getCategory());
        $this->assertEquals(null, $lineItem->getProductUrl());
        $this->assertEquals(1, $lineItem->getQuantity());
        $this->assertEquals('90.00', $lineItem->getSalePrice());
        $this->assertEquals('100.00', $lineItem->getTotalPrice());
        $this->assertEquals(0, $lineItem->getUnitPrice());

    }

    /**
     * @test
     */
    public function returns_populated_order_states()
    {
        $order = (new OrderParser)->parse(
            json_decode(file_get_contents(__DIR__.'/../Stubs/Orders/order.json'))
        );

        $states = $order->getStates();

        $this->assertInstanceOf(OrderState::class, $states);

        $this->assertEquals(true, $states->getProcessed());
        $this->assertEquals(false, $states->getShipped());

    }
}
<file_sep><?php

namespace Omneo\Bronto\Modules;

use Omneo\Bronto;

abstract class AbstractRestModule
{
    /**
     * @var Bronto\RestClient
     */
    protected $client;

    /**
     * Abstract Module constructor.
     *
     * @param Bronto\RestClient|null $client
     */
    public function __construct(Bronto\RestClient $client)
    {
        $this->client = $client;
    }
}
<file_sep><?php

namespace Omneo\Bronto\Entities;

use Carbon\Carbon;
use Illuminate\Support\Collection;

class Contact extends AbstractEntity
{
    /**
     * @var string
     */
    protected $id;

    /**
     * @var string
     */
    protected $email;

    /**
     * @var string
     */
    protected $mobileNumber;

    /**
     * @var string
     */
    protected $status;

    /**
     * @var Collection
     */
    protected $attributes;

    /**
     * @return string
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param string $id
     * @return Contact
     */
    public function setId($id)
    {
        $this->id = $id;
        return $this;
    }

    /**
     * @return string
     */
    public function getEmail()
    {
        return $this->email;
    }

    /**
     * @param string $email
     * @return Contact
     */
    public function setEmail($email)
    {
        $this->email = $email;
        return $this;
    }

    /**
     * @return string
     */
    public function getMobileNumber()
    {
        return $this->mobileNumber;
    }

    /**
     * @param string $mobile
     * @return Contact
     */
    public function setMobileNumber($mobileNumber)
    {
        $this->mobileNumber = $mobileNumber;
        return $this;
    }

    /**
     * @return string
     */
    public function getStatus()
    {
        return $this->status ?: \Bronto_Api_Contact::STATUS_ONBOARDING;
    }

    /**
     * @param string $status
     * @return Contact
     */
    public function setStatus( $status)
    {
        $this->status = $status;
        return $this;
    }

    /**
     * Return collection of attributes.
     *
     * @return Collection
     */
    public function getAttributes()
    {
        return $this->attributes ?: $this->attributes = new Collection;
    }

    /**
     * Set collection of attributes.
     *
     * @param  Collection $attributes
     * @return Contact
     */
    public function setAttributes(Collection $attributes)
    {
        $this->attributes = $attributes;

        return $this;
    }

    /**
     * @return array
     */
    public function jsonSerialize()
    {
        return get_object_vars($this);
    }

}<file_sep><?php

namespace Omneo\Bronto\Entities;

use Carbon\Carbon;
use Illuminate\Support\Collection;

class Order extends AbstractEntity
{
    /**
     * @var float
     */
    protected $discountAmount;

    /**
     * @var string
     */
    protected $emailAddress;

    /**
     * @var float
     */
    protected $grandTotal;

    /**
     * @var Collection
     */
    protected $lineItems;

    /**
     * @var string
     */
    protected $originIp;

    /**
     * @var string
     */
    protected $originUserAgent;

    /**
     * @var float
     */
    protected $shippingAmount;

    /**
     * @var Carbon
     */
    protected $shippingDate;

    /**
     * @var string
     */
    protected $shippingDetails;

    /**
     * @var string
     */
    protected $shippingTrackingUrl;

    /**
     * @var float
     */
    protected $subtotal;

    /**
     * @var float
     */
    protected $taxAmount;

    /**
     * @var string
     */
    protected $trackingCookieName;

    /**
     * @var string
     */
    protected $trackingCookieValue;

    /**
     * @var string
     */
    protected $tid;

    /**
     * @var string
     */
    protected $cartId;

    /**
     * @var string
     */
    protected $customerOrderId;

    /**
     * @var string
     */
    protected $orderDate;

    /**
     * @var string
     */
    protected $currency;

    /**
     * @var OrderState
     */
    protected $states;

    /**
     * @var string
     */
    protected $orderId;

    /**
     * @var Carbon
     */
    protected $createdDate;

    /**
     * @var Carbon
     */
    protected $updatedDate;

    /**
     * @return float
     */
    public function getDiscountAmount()
    {
        return $this->discountAmount;
    }

    /**
     * @param float $discountAmount
     * @return Order
     */
    public function setDiscountAmount($discountAmount)
    {
        $this->discountAmount = $discountAmount;
        return $this;
    }

    /**
     * @return string
     */
    public function getEmailAddress()
    {
        return $this->emailAddress;
    }

    /**
     * @param string $emailAddress
     * @return Order
     */
    public function setEmailAddress($emailAddress)
    {
        $this->emailAddress = $emailAddress;
        return $this;
    }

    /**
     * @return float
     */
    public function getGrandTotal()
    {
        return $this->grandTotal;
    }

    /**
     * @param float $grandTotal
     * @return Order
     */
    public function setGrandTotal($grandTotal)
    {
        $this->grandTotal = $grandTotal;
        return $this;
    }

    /**
     * @return Collection
     */
    public function getLineItems()
    {
        return $this->lineItems ?: $this->lineItems = new Collection;
    }

    /**
     * @param Collection $lineItems
     * @return Order
     */
    public function setLineItems($lineItems)
    {
        $this->lineItems = $lineItems;
        return $this;
    }

    /**
     * @return string
     */
    public function getOriginIp()
    {
        return $this->originIp;
    }

    /**
     * @param string $originIp
     * @return Order
     */
    public function setOriginIp($originIp)
    {
        $this->originIp = $originIp;
        return $this;
    }

    /**
     * @return string
     */
    public function getOriginUserAgent()
    {
        return $this->originUserAgent;
    }

    /**
     * @param string $originUserAgent
     * @return Order
     */
    public function setOriginUserAgent($originUserAgent)
    {
        $this->originUserAgent = $originUserAgent;
        return $this;
    }

    /**
     * @return float
     */
    public function getShippingAmount()
    {
        return $this->shippingAmount;
    }

    /**
     * @param float $shippingAmount
     * @return Order
     */
    public function setShippingAmount($shippingAmount)
    {
        $this->shippingAmount = $shippingAmount;
        return $this;
    }

    /**
     * @return Carbon|null
     */
    public function getShippingDate()
    {
        return $this->shippingDate;
    }

    /**
     * @param Carbon $shippingDate
     * @return Order
     */
    public function setShippingDate(Carbon $shippingDate = null)
    {
        $this->shippingDate = $shippingDate;
        return $this;
    }

    /**
     * @return string
     */
    public function getShippingDetails()
    {
        return $this->shippingDetails;
    }

    /**
     * @param string $shippingDetails
     * @return Order
     */
    public function setShippingDetails($shippingDetails)
    {
        $this->shippingDetails = $shippingDetails;
        return $this;
    }

    /**
     * @return string
     */
    public function getShippingTrackingUrl()
    {
        return $this->shippingTrackingUrl;
    }

    /**
     * @param string $shippingTrackingUrl
     * @return Order
     */
    public function setShippingTrackingUrl($shippingTrackingUrl)
    {
        $this->shippingTrackingUrl = $shippingTrackingUrl;
        return $this;
    }

    /**
     * @return float
     */
    public function getSubtotal()
    {
        return $this->subtotal;
    }

    /**
     * @param float $subtotal
     * @return Order
     */
    public function setSubtotal($subtotal)
    {
        $this->subtotal = $subtotal;
        return $this;
    }

    /**
     * @return float
     */
    public function getTaxAmount()
    {
        return $this->taxAmount;
    }

    /**
     * @param float $taxAmount
     * @return Order
     */
    public function setTaxAmount($taxAmount)
    {
        $this->taxAmount = $taxAmount;
        return $this;
    }

    /**
     * @return string
     */
    public function getTrackingCookieName()
    {
        return $this->trackingCookieName;
    }

    /**
     * @param string $trackingCookieName
     * @return Order
     */
    public function setTrackingCookieName($trackingCookieName)
    {
        $this->trackingCookieName = $trackingCookieName;
        return $this;
    }

    /**
     * @return string
     */
    public function getTrackingCookieValue()
    {
        return $this->trackingCookieValue;
    }

    /**
     * @param string $trackingCookieValue
     * @return Order
     */
    public function setTrackingCookieValue($trackingCookieValue)
    {
        $this->trackingCookieValue = $trackingCookieValue;
        return $this;
    }

    /**
     * @return string
     */
    public function getTid()
    {
        return $this->tid;
    }

    /**
     * @param string $tid
     * @return Order
     */
    public function setTid($tid)
    {
        $this->tid = $tid;
        return $this;
    }

    /**
     * @return string
     */
    public function getCartId()
    {
        return $this->cartId;
    }

    /**
     * @param string $cartId
     * @return Order
     */
    public function setCartId($cartId)
    {
        $this->cartId = $cartId;
        return $this;
    }

    /**
     * @return string
     */
    public function getCustomerOrderId()
    {
        return $this->customerOrderId;
    }

    /**
     * @param string $customerOrderId
     * @return Order
     */
    public function setCustomerOrderId($customerOrderId)
    {
        $this->customerOrderId = $customerOrderId;
        return $this;
    }

    /**
     * @return Carbon|null
     */
    public function getOrderDate()
    {
        return $this->orderDate;
    }

    /**
     * @param Carbon $orderDate
     * @return Order
     */
    public function setOrderDate(Carbon $orderDate = null)
    {
        $this->orderDate = $orderDate;
        return $this;
    }

    /**
     * @return string
     */
    public function getCurrency()
    {
        return $this->currency;
    }

    /**
     * @param string $currency
     * @return Order
     */
    public function setCurrency($currency)
    {
        $this->currency = $currency;
        return $this;
    }

    /**
     * @return OrderState
     */
    public function getStates()
    {
        return $this->states;
    }

    /**
     * @param OrderState $states
     * @return Order
     */
    public function setStates(OrderState $states)
    {
        $this->states = $states;
        return $this;
    }

    /**
     * @return string
     */
    public function getOrderId()
    {
        return $this->orderId;
    }

    /**
     * @param string $orderId
     * @return Order
     */
    public function setOrderId($orderId)
    {
        $this->orderId = $orderId;
        return $this;
    }

    /**
     * @return Carbon
     */
    public function getCreatedDate()
    {
        return $this->createdDate;
    }

    /**
     * @param Carbon $createdDate
     * @return Order
     */
    public function setCreatedDate($createdDate)
    {
        $this->createdDate = $createdDate;
        return $this;
    }

    /**
     * @return Carbon
     */
    public function getUpdatedDate()
    {
        return $this->updatedDate;
    }

    /**
     * @param Carbon $updatedDate
     * @return Order
     */
    public function setUpdatedDate($updatedDate)
    {
        $this->updatedDate = $updatedDate;
        return $this;
    }

    /**
     * @return Array
     */
    public function jsonSerialize()
    {
        $result = get_object_vars($this);
        if(!is_null($result['orderDate'])) $result['orderDate'] = $result['orderDate']->toDateString();
        if(!is_null($result['shippingDate'])) $result['shippingDate'] = $result['shippingDate']->toDateString();
        return $result;
    }

}
<file_sep><?php

namespace Omneo\Bronto\Entities;

use Carbon\Carbon;
use Illuminate\Support\Collection;

class Delivery extends AbstractEntity
{
    /**
     * @var Carbon
     */
    protected $start;

    /**
     * @var string
     */
    protected $messageId;

    /**
     * @var string
     */
    protected $type;

    /**
     * @var string
     */
    protected $fromEmail;

    /**
     * @var string
     */
    protected $fromName;

    /**
     * @var string
     */
    protected $replyEmail;

    /**
     * @var bool
     */
    protected $authentication;

    /**
     * @var string
     */
    protected $messageRuleId;

    /**
     * @var bool
     */
    protected $optin;

    /**
     * @var int
     */
    protected $throttle;

    /**
     * @var int
     */
    protected $fatigueOverride;

    /**
     * @var DeliveryRemail
     */
    protected $remail;

    /**
     * @var DeliveryRecipient
     */
    protected $recipients;

    /**
     * @var DeliveryField
     */
    protected $fields;

    /**
     * @var DeliveryProduct
     */
    protected $products;

    /**
     * @var string
     */
    protected $cartId;

    /**
     * @var string
     */
    protected $orderId;

    /**
     * @return Carbon
     */
    public function getStart()
    {
        return $this->start;
    }

    /**
     * The date the delivery was scheduled to be sent.
     * You can (and should) specify a timezone offset if you do not want the system to assume you are providing a time in
     * UTC (Universal Coordinated Time / Greenwich Mean Time). For the Eastern Time Zone on Daylight Savings Time,
     * this would be YYYY-MM-DDTHH:MM:SS-04:00.
     * @param Carbon $start
     * @return Delivery
     */
    public function setStart(Carbon $start = null)
    {
        $this->start = $start;
        return $this;
    }

    /**
     * @return string
     */
    public function getMessageId()
    {
        return $this->messageId;
    }

    /**
     * @param string $messageId
     * @return Delivery
     */
    public function setMessageId($messageId)
    {
        $this->messageId = $messageId;
        return $this;
    }

    /**
     * @return string
     */
    public function getType()
    {
        return $this->type;
    }

    /**
     * The type of delivery. Valid values are: triggered, test, or transactional.
     * triggered is the default. Only use transactional when adding a delivery which uses a message that has
     * been approved for transactional sending.
     * Note: If you attempt to send a triggered or test delivery to a contact with a status of transactional,
     * the delivery will be set to skipped and the delivery will not be sent.
     * @param string $type
     * @return Delivery
     */
    public function setType($type)
    {
        $this->type = $type;
        return $this;
    }

    /**
     * @return string
     */
    public function getFromEmail()
    {
        return $this->fromEmail;
    }

    /**
     * @param string $fromEmail
     * @return Delivery
     */
    public function setFromEmail($fromEmail)
    {
        $this->fromEmail = $fromEmail;
        return $this;
    }

    /**
     * @return string
     */
    public function getFromName()
    {
        return $this->fromName;
    }

    /**
     * @param string $fromName
     * @return Delivery
     */
    public function setFromName($fromName)
    {
        $this->fromName = $fromName;
        return $this;
    }

    /**
     * @return string
     */
    public function getReplyEmail()
    {
        return $this->replyEmail;
    }

    /**
     * @param string $replyEmail
     * @return Delivery
     */
    public function setReplyEmail($replyEmail)
    {
        $this->replyEmail = $replyEmail;
        return $this;
    }

    /**
     * @return bool
     */
    public function getAuthentication()
    {
        return $this->authentication;
    }

    /**
     * Enables sender authentication for the delivery if set to true.
     * Sender authentication will sign your message with DomainKeys/DKIM
     * (an authentication method that can optimize your message delivery to Hotmail, MSN, and Yahoo! email addresses).
     * If you are associating this delivery with an automated message rule,
     * these parameters will only be accepted if you clicked the Allow API to select sending options
     * checkbox via the application UI on step 2 of creating an API triggered automated message rule.
     * @param bool $authentication
     * @return Delivery
     */
    public function setAuthentication($authentication)
    {
        $this->authentication = $authentication;
        return $this;
    }

    /**
     * @return string
     */
    public function getMessageRuleId()
    {
        return $this->messageRuleId;
    }

    /**
     * The ID of an automated message rule to associate with this delivery.
     * Used to include this delivery in the reporting for the automator you specify.
     * @param string $messageRuleId
     * @return Delivery
     */
    public function setMessageRuleId($messageRuleId)
    {
        $this->messageRuleId = $messageRuleId;
        return $this;
    }

    /**
     * @return bool
     */
    public function getOptin()
    {
        return $this->optin;
    }

    /**
     * Whether or not this delivery is an opt-in confirmation email. If set to true, contacts who have not yet confirmed
     * their opt-in status with the account will still receive the message.
     * @param bool $optin
     * @return Delivery
     */
    public function setOptin($optin)
    {
        $this->optin = $optin;
        return $this;
    }

    /**
     * @return int
     */
    public function getThrottle()
    {
        return $this->throttle;
    }

    /**
     * Allows you to specify a throttle rate for the delivery.
     * Throttle rate must be in range [0, 720] (minutes).
     * For example you could specify 60 for the throttle range.
     * @param int $throttle
     * @return Delivery
     */
    public function setThrottle($throttle)
    {
        $this->throttle = $throttle;
        return $this;
    }

    /**
     * @return int
     */
    public function getFatigueOverride()
    {
        return $this->fatigueOverride;
    }

    /**
     * If set to true, the delivery can be sent even if it exceeds frequency cap settings for a contact.
     * @param int $fatigueOverride
     * @return Delivery
     */
    public function setFatigueOverride($fatigueOverride)
    {
        $this->fatigueOverride = $fatigueOverride;
        return $this;
    }

    /**
     * @return DeliveryRemail
     */
    public function getRemail()
    {
        return $this->remail;
    }

    /**
     * A remail object. Remails allow you to send another email to contacts based on actions they did not take.
     * The goal is to persuade them to continue along the conversion process.
     * @param DeliveryRemail $remail
     * @return Delivery
     */
    public function setRemail($remail)
    {
        $this->remail = $remail;
        return $this;
    }

    /**
     * @return DeliveryRecipient[]|Collection
     */
    public function getRecipients()
    {
        return $this->recipients ?: $this->recipients = new Collection;
    }

    /**
     * A collection of the recipients who were or are scheduled to receive the delivery.
     * Recipients can include lists, segments, or individual contacts.
     * @param DeliveryRecipient[]|Collection $recipients
     * @return Delivery
     */
    public function setRecipients($recipients)
    {
        $this->recipients = $recipients;
        return $this;
    }

    /**
     * @return DeliveryField[]|Collection
     */
    public function getFields()
    {
        return $this->fields ?: $this->fields = new Collection;
    }

    /**
     * An array of the API fields and data to substitute into the message being sent by this delivery.
     * @param DeliveryField[]|Collection $fields
     * @return Delivery
     */
    public function setFields($fields)
    {
        $this->fields = $fields;
        return $this;
    }

    /**
     * @return Product[]|Collection
     */
    public function getProducts()
    {
        return $this->products ?: $this->products = new Collection;
    }

    /**
     * Specifies Product IDs to substitute for placeholders in product tags upon message send. Limit: 100 products
     * @param Product[]|Collection $products
     * @return Delivery
     */
    public function setProducts($products)
    {
        $this->products = $products;
        return $this;
    }

    /**
     * @return string
     */
    public function getCartId()
    {
        return $this->cartId;
    }

    /**
     * @param string $cartId
     * @return Delivery
     */
    public function setCartId($cartId)
    {
        $this->cartId = $cartId;
        return $this;
    }

    /**
     * @return string
     */
    public function getOrderId()
    {
        return $this->orderId;
    }

    /**
     * @param string $orderId
     * @return Delivery
     */
    public function setOrderId($orderId)
    {
        $this->orderId = $orderId;
        return $this;
    }

    /**
     * @return Array
     */
    public function jsonSerialize()
    {
        $result = get_object_vars($this);

        return $result;
    }

}
<file_sep><?php

namespace Omneo\Responsys\Exceptions;

use Exception;

class UnexpectedException extends Exception
{
    //
}
<file_sep><?php

namespace Omneo\Bronto;

use Psr\Http;
use GuzzleHttp;
use GuzzleHttp\Middleware;
use GuzzleHttp\MessageFormatter;
use Omneo\Bronto;
use Psr\Log\LoggerInterface;

class RestClient
{
    /**
     * @var GuzzleHttp\Client
     */
    protected $client;

    /**
     * @var Bronto\RestAuthentication
     */
    protected $auth;

    /**
     * Products API ID
     * This ID can be found on the Products Overview page in the BMP,
     * located on the bottom-right part of the page. It is titled 'Products API ID'
     *
     * @var string
     */
    protected $productsApiId;

    /**
     * Enable logging of guzzle requests / responses
     *
     * @var bool
     */
    protected $logging = false;

    /**
     * PSR-3 logger
     *
     * @var LoggerInterface
     */
    protected $logger;

    /**
     * Verify peer SSL
     *
     * @var bool
     */
    protected $verifyPeer = true;

    /**
     * Set connection timeout
     *
     * @var int
     */
    protected $timeout = 900;

    /**
     * Client constructor.
     *
     * @param RestAuthentication $auth
     * @param GuzzleHttp\HandlerStack|null $handler
     */
    public function __construct(Bronto\RestAuthentication $auth, GuzzleHttp\HandlerStack $handler = null)
    {
        $this->auth = $auth;

        $this->setupClient($handler);
    }

    /**
     * Set the product API ID.
     *
     * @param string $id
     * @return $this
     */
    public function setProductsApiId($id)
    {
        $this->productsApiId = $id;

        return $this;
    }

    /**
     * Get the product API ID.
     *
     * @return string
     */
    public function getProductsApiId()
    {
        return $this->productsApiId;
    }

    /**
     * @return bool
     */
    public function getLogging()
    {
        return $this->logging;
    }

    /**
     * @param bool $logging
     * @return Client
     */
    public function setLogging($logging)
    {
        $this->logging = $logging;
        return $this;
    }

    /**
     * @return LoggerInterface
     */
    public function getLogger()
    {
        return $this->logger;
    }

    /**
     * @param LoggerInterface $logger
     * @return Client
     */
    public function setLogger($logger)
    {
        $this->logger = $logger;
        return $this;
    }

    /**
     * @return bool
     */
    public function getVerifyPeer()
    {
        return $this->verifyPeer;
    }

    /**
     * @param bool $verifyPeer
     * @return RestClient
     */
    public function setVerifyPeer($verifyPeer)
    {
        $this->verifyPeer = $verifyPeer;
        return $this;
    }

    /**
     * @return int
     */
    public function getTimeout()
    {
        return $this->timeout;
    }

    /**
     * @param int $timeout
     * @return RestClient
     */
    public function setTimeout($timeout)
    {
        $this->timeout = $timeout;
        return $this;
    }

    /**
     * Setup Guzzle client with optional provided handler stack.
     *
     * @param  GuzzleHttp\HandlerStack|null $stack
     * @param  array                        $options
     * @return Client
     */
    public function setupClient(GuzzleHttp\HandlerStack $stack = null, $options = [])
    {
        $stack = $stack ?: GuzzleHttp\HandlerStack::create();

        if($this->logging) $this->bindLoggingMiddleware($stack);

        $this->client = new GuzzleHttp\Client(array_merge([
            'handler'  => $stack,
            'verify' => $this->getVerifyPeer(),
            'timeout'  => $this->getTimeout(),
        ], $options));

        return $this;
    }

    /**
     * Make a request.
     *
     * @param $method
     * @param $endpoint
     * @param array $params
     * @return Http\Message\ResponseInterface
     * @throws Exceptions\BrontoException
     * @throws Exceptions\NotFoundException
     */
    public function request($method, $endpoint, array $params = [])
    {
        $clientHandler = $this->client->getConfig('handler');
        $oauthMiddleware = Middleware::mapRequest(function ($request) {
            return $request->withHeader('Authorization','Bearer ' . $this->auth->getToken());
        });
        $params['handler'] = $oauthMiddleware($clientHandler);

        try {
            $response = $this->client->request(
                $method,
                $this->auth->getEndpoint() . '/' . $endpoint,
                $params
            );
        } catch (\Exception $e) {
            throw $this->convertException($e);
        }

        return json_decode((string) $response->getBody());
    }

    /**
     * Convert the provided exception.
     *
     * @param  Exception $e
     * @return Exceptions\NotFoundException|Exceptions\BrontoException|Exception
     */
    protected function convertException(\Exception $e)
    {
        if ($e instanceof GuzzleHttp\Exception\ClientException && $e->getResponse()->getStatusCode() == 404) {
            return new Exceptions\NotFoundException('not found');
        }

        if ($e instanceof GuzzleHttp\Exception\BadResponseException) {
            $message = (string) $e->getResponse()->getBody();
            if(count($e->getResponse()->getHeader('X-Reason'))){
                $message = (string) $e->getResponse()->getHeader('X-Reason')[0];
            }
            return new Exceptions\BrontoException($message, $e->getResponse()->getStatusCode());
        }

        return $e;
    }

    /**
     * Perform a GET request.
     *
     * @param $endpoint
     * @param array $params
     * @return Http\Message\ResponseInterface
     */
    public function get($endpoint, array $params = [])
    {
        return $this->request('GET', $endpoint, $params);
    }

    /**
     * Perform a POST request.
     *
     * @param $endpoint
     * @param array $params
     * @return Http\Message\ResponseInterface
     */
    public function post($endpoint, array $params = [])
    {
        return $this->request('POST', $endpoint, $params);
    }

    /**
     * Perform a PUT request.
     *
     * @param $endpoint
     * @param array $params
     * @return Http\Message\ResponseInterface
     */
    public function put($endpoint, array $params = [])
    {
        return $this->request('PUT', $endpoint, $params);
    }

    /**
     * Perform a DELETE request.
     *
     * @param $endpoint
     * @param array $params
     * @return Http\Message\ResponseInterface
     */
    public function delete($endpoint, array $params = [])
    {
        return $this->request('DELETE', $endpoint, $params);
    }

    /**
     * Order service module.
     *
     * @return Modules\OrderService
     */
    public function orderService()
    {
        return new Modules\OrderService($this);
    }

    /**
     * Product service module.
     *
     * @return Modules\ProductService
     */
    public function productService()
    {
        return new Modules\ProductService($this);
    }

    /**
     * Bind logging middleware.
     *
     * @param  GuzzleHttp\HandlerStack $stack
     * @return void
     */
    protected function bindLoggingMiddleware(GuzzleHttp\HandlerStack $stack)
    {
        $stack->push(Middleware::log(
            $this->logger,
            new MessageFormatter('{request} - {response}')
        ));
    }

}
<file_sep><?php

namespace Arkade\Bronto\Serializers;

use PHPUnit\Framework\TestCase;
use Arkade\Bronto\Factories;

class OrderSerializerTest extends TestCase
{
    /**
     * @test
     */
    public function returns_populated_json()
    {
        $json = (new OrderSerializer)->serialize(
            (new Factories\OrderFactory)->make()
        );

        $this->assertEquals(file_get_contents(__DIR__.'/../Stubs/Orders/create_order_request.json'), $json);
    }
}<file_sep><?php

namespace Omneo\Bronto\Entities;

use Carbon\Carbon;
use Illuminate\Support\Collection;

class DeliveryRecipient extends AbstractEntity
{
    /**
     * @var string
     */
    protected $deliveryType;

    /**
     * @var string
     */
    protected $id;

    /**
     * @var string
     */
    protected $type;

    /**
     * @return string
     */
    public function getDeliveryType()
    {
        return $this->deliveryType;
    }

    /**
     * Valid values are:
     * eligible - Indicates that the contact, list, keyword, or segment specified in this object are eligible to receive the message being sent to it.
     * ineligible - Indicates that the contact, list, keyword, or segment specified in this object are not eligible to receive the message being sent to it.
     * uselected - (Default)
     * @param string $deliveryType
     * @return DeliveryRecipient
     */
    public function setDeliveryType($deliveryType)
    {
        $this->deliveryType = $deliveryType;
        return $this;
    }

    /**
     * @return string
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * The unique id of the recipient receiving the delivery. Depending on the type specified,
     * the id will be for a contact, a list, an smsKeyword, or a segment.
     * @param string $id
     * @return DeliveryRecipient
     */
    public function setId($id)
    {
        $this->id = $id;
        return $this;
    }

    /**
     * @return string
     */
    public function getType()
    {
        return $this->type;
    }

    /**
     * Whether the contact is receiving the message as part of a list, segment, SMS keyword, or as an individual contact.
     * Valid values are: contact, list, segment or keyword (SMS Only – Use with addSMSDeliveries)
     * @param string $type
     * @return DeliveryRecipient
     */
    public function setType($type)
    {
        $this->type = $type;
        return $this;
    }

    /**
     * @return Array
     */
    public function jsonSerialize()
    {
        $result = get_object_vars($this);

        return $result;
    }

}
<file_sep><?php

namespace Omneo\Bronto\Entities;

use Carbon\Carbon;

/*
 * @see https://helpdocs.bronto.com/bmp/reference/r_bmp_product_fields_descriptions.html
 */

class Product extends AbstractEntity
{
    /**
     * @var string
     */
    protected $ageGroup;

    /**
     * @var string
     */
    protected $availability;

    /**
     * @var Carbon
     */
    protected $availabilityDate;

    /**
     * @var float
     */
    protected $averageRating;

    /**
     * @var string
     */
    protected $brand;

    /**
     * @var string
     */
    protected $color;

    /**
     * @var string
     */
    protected $condition;

    /**
     * @var string
     */
    protected $description;

    /**
     * @var string
     */
    protected $gender;

    /**
     * @var string
     */
    protected $gtin;

    /**
     * @var string
     */
    protected $imageUrl;

    /**
     * @var int
     */
    protected $inventoryThreshold;

    /**
     * @var string
     */
    protected $isbn;

    /**
     * @var string
     */
    protected $mpn;

    /**
     * @var float
     */
    protected $margin;

    /**
     * @var string
     */
    protected $mobileUrl;

    /**
     * @var string
     */
    protected $parentProductId;

    /**
     * @var string
     */
    protected $price;

    /**
     * @var string
     */
    protected $productCategory;

    /**
     * @var string
     */
    protected $productId;

    /**
     * @var string
     */
    protected $productTypeMulti;

    /**
     * @var string
     */
    protected $productUrl;

    /**
     * @var int
     */
    protected $quantity;

    /**
     * @var int
     */
    protected $reviewCount;

    /**
     * @var string
     */
    protected $salePrice;

    /**
     * @var Carbon
     */
    protected $salePriceEffectiveStartDate;

    /**
     * @var Carbon
     */
    protected $salePriceEffectiveEndDate;

    /**
     * @var string
     */
    protected $size;

    /**
     * @var string
     */
    protected $title;

    /**
     * @var string
     */
    protected $upc;

    /**
     * @var Carbon
     */
    protected $createdDate;

    /**
     * @var Carbon
     */
    protected $updatedDate;

    /**
     * @return string
     */
    public function getAgeGroup()
    {
        return $this->ageGroup;
    }

    /**
     * @param string $ageGroup
     * @return Product
     */
    public function setAgeGroup($ageGroup)
    {
        $this->ageGroup = $ageGroup;
        return $this;
    }

    /**
     * @return string
     */
    public function getAvailability()
    {
        return $this->availability;
    }

    /**
     * @param string $availability
     * @return Product
     */
    public function setAvailability($availability)
    {
        $this->availability = $availability;
        return $this;
    }

    /**
     * @return Carbon|null
     */
    public function getAvailabilityDate()
    {
        return $this->availabilityDate;
    }

    /**
     * @param Carbon $availabilityDate
     * @return Product
     */
    public function setAvailabilityDate(Carbon $availabilityDate = null)
    {
        $this->availabilityDate = $availabilityDate;
        return $this;
    }

    /**
     * @return float
     */
    public function getAverageRating()
    {
        return $this->averageRating;
    }

    /**
     * @param float $averageRating
     * @return Product
     */
    public function setAverageRating($averageRating)
    {
        $this->averageRating = $averageRating;
        return $this;
    }

    /**
     * @return string
     */
    public function getBrand()
    {
        return $this->brand;
    }

    /**
     * @param string $brand
     * @return Product
     */
    public function setBrand($brand)
    {
        $this->brand = $brand;
        return $this;
    }

    /**
     * @return string
     */
    public function getColor()
    {
        return $this->color;
    }

    /**
     * @param string $color
     * @return Product
     */
    public function setColor($color)
    {
        $this->color = $color;
        return $this;
    }

    /**
     * @return string
     */
    public function getCondition()
    {
        return $this->condition;
    }

    /**
     * @param string $condition
     * @return Product
     */
    public function setCondition($condition)
    {
        $this->condition = $condition;
        return $this;
    }

    /**
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * @param string $description
     * @return Product
     */
    public function setDescription($description)
    {
        $this->description = $description;
        return $this;
    }

    /**
     * @return string
     */
    public function getGender()
    {
        return $this->gender;
    }

    /**
     * @param string $gender
     * @return Product
     */
    public function setGender($gender)
    {
        $this->gender = $gender;
        return $this;
    }

    /**
     * @return string
     */
    public function getGtin()
    {
        return $this->gtin;
    }

    /**
     * @param string $gtin
     * @return Product
     */
    public function setGtin($gtin)
    {
        $this->gtin = $gtin;
        return $this;
    }

    /**
     * @return string
     */
    public function getImageUrl()
    {
        return $this->imageUrl;
    }

    /**
     * @param string $imageUrl
     * @return Product
     */
    public function setImageUrl($imageUrl)
    {
        $this->imageUrl = $imageUrl;
        return $this;
    }

    /**
     * @return int
     */
    public function getInventoryThreshold()
    {
        return $this->inventoryThreshold;
    }

    /**
     * @param int $inventoryThreshold
     * @return Product
     */
    public function setInventoryThreshold($inventoryThreshold)
    {
        $this->inventoryThreshold = $inventoryThreshold;
        return $this;
    }

    /**
     * @return string
     */
    public function getIsbn()
    {
        return $this->isbn;
    }

    /**
     * @param string $isbn
     * @return Product
     */
    public function setIsbn($isbn)
    {
        $this->isbn = $isbn;
        return $this;
    }

    /**
     * @return string
     */
    public function getMpn()
    {
        return $this->mpn;
    }

    /**
     * @param string $mpn
     * @return Product
     */
    public function setMpn($mpn)
    {
        $this->mpn = $mpn;
        return $this;
    }

    /**
     * @return float
     */
    public function getMargin()
    {
        return $this->margin;
    }

    /**
     * @param float $margin
     * @return Product
     */
    public function setMargin($margin)
    {
        $this->margin = $margin;
        return $this;
    }

    /**
     * @return string
     */
    public function getMobileUrl()
    {
        return $this->mobileUrl;
    }

    /**
     * @param string $mobileUrl
     * @return Product
     */
    public function setMobileUrl($mobileUrl)
    {
        $this->mobileUrl = $mobileUrl;
        return $this;
    }

    /**
     * @return string
     */
    public function getParentProductId()
    {
        return $this->parentProductId;
    }

    /**
     * @param string $parentProductId
     * @return Product
     */
    public function setParentProductId($parentProductId)
    {
        $this->parentProductId = $parentProductId;
        return $this;
    }

    /**
     * @return string
     */
    public function getPrice()
    {
        return $this->price;
    }

    /**
     * @param string $price
     * @return Product
     */
    public function setPrice($price)
    {
        $this->price = $price;
        return $this;
    }

    /**
     * @return string
     */
    public function getProductCategory()
    {
        return $this->productCategory;
    }

    /**
     * @param string $productCategory
     * @return Product
     */
    public function setProductCategory($productCategory)
    {
        $this->productCategory = $productCategory;
        return $this;
    }

    /**
     * @return string
     */
    public function getProductId()
    {
        return $this->productId;
    }

    /**
     * @param string $productId
     * @return Product
     */
    public function setProductId($productId)
    {
        $this->productId = $productId;
        return $this;
    }

    /**
     * @return string
     */
    public function getProductTypeMulti()
    {
        return $this->productTypeMulti;
    }

    /**
     * @param string $productTypeMulti
     * @return Product
     */
    public function setProductTypeMulti($productTypeMulti)
    {
        $this->productTypeMulti = $productTypeMulti;
        return $this;
    }

    /**
     * @return string
     */
    public function getProductUrl()
    {
        return $this->productUrl;
    }

    /**
     * @param string $productUrl
     * @return Product
     */
    public function setProductUrl($productUrl)
    {
        $this->productUrl = $productUrl;
        return $this;
    }

    /**
     * @return int
     */
    public function getQuantity()
    {
        return $this->quantity;
    }

    /**
     * @param int $quantity
     * @return Product
     */
    public function setQuantity($quantity)
    {
        $this->quantity = $quantity;
        return $this;
    }

    /**
     * @return int
     */
    public function getReviewCount()
    {
        return $this->reviewCount;
    }

    /**
     * @param int $reviewCount
     * @return Product
     */
    public function setReviewCount($reviewCount)
    {
        $this->reviewCount = $reviewCount;
        return $this;
    }

    /**
     * @return string
     */
    public function getSalePrice()
    {
        return $this->salePrice;
    }

    /**
     * @param string $salePrice
     * @return Product
     */
    public function setSalePrice($salePrice)
    {
        $this->salePrice = $salePrice;
        return $this;
    }

    /**
     * @return Carbon|null
     */
    public function getSalePriceEffectiveStartDate()
    {
        return $this->salePriceEffectiveStartDate;
    }

    /**
     * @param Carbon $salePriceEffectiveStartDate
     * @return Product
     */
    public function setSalePriceEffectiveStartDate(Carbon $salePriceEffectiveStartDate = null)
    {
        $this->salePriceEffectiveStartDate = $salePriceEffectiveStartDate;
        return $this;
    }

    /**
     * @return Carbon|null
     */
    public function getSalePriceEffectiveEndDate()
    {
        return $this->salePriceEffectiveEndDate;
    }

    /**
     * @param Carbon $salePriceEffectiveEndDate
     * @return Product
     */
    public function setSalePriceEffectiveEndDate(Carbon $salePriceEffectiveEndDate = null)
    {
        $this->salePriceEffectiveEndDate = $salePriceEffectiveEndDate;
        return $this;
    }

    /**
     * @return string
     */
    public function getSize()
    {
        return $this->size;
    }

    /**
     * @param string $size
     * @return Product
     */
    public function setSize($size)
    {
        $this->size = $size;
        return $this;
    }

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     * @return Product
     */
    public function setTitle($title)
    {
        $this->title = $title;
        return $this;
    }

    /**
     * @return string
     */
    public function getUpc()
    {
        return $this->upc;
    }

    /**
     * @param string $upc
     * @return Product
     */
    public function setUpc($upc)
    {
        $this->upc = $upc;
        return $this;
    }

    /**
     * @return Carbon
     */
    public function getCreatedDate()
    {
        return $this->createdDate;
    }

    /**
     * @param Carbon $createdDate
     * @return Order
     */
    public function setCreatedDate(Carbon $createdDate = null)
    {
        $this->createdDate = $createdDate;
        return $this;
    }

    /**
     * @return Carbon
     */
    public function getUpdatedDate()
    {
        return $this->updatedDate;
    }

    /**
     * @param Carbon $updatedDate
     * @return Order
     */
    public function setUpdatedDate(Carbon $updatedDate = null)
    {
        $this->updatedDate = $updatedDate;
        return $this;
    }

    /**
     * @return Array
     */
    public function jsonSerialize()
    {
        $result = get_object_vars($this);
        if(!is_null($result['salePriceEffectiveStartDate'])) $result['salePriceEffectiveStartDate'] = $result['salePriceEffectiveStartDate']->toDateString();
        if(!is_null($result['salePriceEffectiveEndDate'])) $result['salePriceEffectiveEndDate'] = $result['salePriceEffectiveEndDate']->toDateString();
        if(!is_null($result['availabilityDate'])) $result['availabilityDate'] = $result['availabilityDate']->toDateString();
        return $result;
    }

}
<file_sep><?php

namespace Omneo\Bronto\Modules;

use Omneo\Bronto\Entities\Delivery;
use Omneo\Bronto\Serializers\DeliverySerializer;
use Omneo\Bronto\Exceptions;
use Carbon\Carbon;

class DeliveryService extends AbstractSoapModule
{
    /**
     * Send an email delivery
     *
     * @param Delivery
     * @return Delivery
     */
    public function send(Delivery $delivery)
    {
        $deliveryObject = $this->client->getClient()->getDeliveryObject();

        $deliveryRow = $deliveryObject->createRow();

        $deliveryArray = array_filter(json_decode((new DeliverySerializer())->serialize($delivery),true));

        if(isset($deliveryArray['start'])) $deliveryRow->start = $deliveryArray['start'];
        if(isset($deliveryArray['type'])) $deliveryRow->type = $deliveryArray['type'];
        if(isset($deliveryArray['messageId'])) $deliveryRow->messageId = $deliveryArray['messageId'];
        if(isset($deliveryArray['fromEmail'])) $deliveryRow->fromEmail = $deliveryArray['fromEmail'];
        if(isset($deliveryArray['fromName'])) $deliveryRow->fromName = $deliveryArray['fromName'];
        if(isset($deliveryArray['recipients'])) $deliveryRow->recipients = $deliveryArray['recipients'];
        if(isset($deliveryArray['optin'])) $deliveryRow->optin = $deliveryArray['optin'];
        if(isset($deliveryArray['throttle'])) $deliveryRow->throttle = $deliveryArray['throttle'];
        if(isset($deliveryArray['replyEmail'])) $deliveryRow->replyEmail = $deliveryArray['replyEmail'];
        if(isset($deliveryArray['authentication'])) $deliveryRow->authentication = $deliveryArray['authentication'];
        if(isset($deliveryArray['messageRuleId'])) $deliveryRow->messageRuleId = $deliveryArray['messageRuleId'];

        $delivery->getFields()->each(function($field) use($deliveryRow){
            $deliveryRow->setField($field->getName(), $field->getContent(), $field->getType());
        });

        // Save
        try {
            $deliveryRow->save();
            return $delivery;
        } catch (Exception $e) {
            throw new Exceptions\BrontoException((string)$e->getResponse()->getBody(),
                $e->getResponse()->getStatusCode());
        }
    }

}<file_sep><?php

return [

    /*
    |--------------------------------------------------------------------------
    | Bronto Contact Field Mappings
    |--------------------------------------------------------------------------
    |
    | Because Bronto uses a custom identifier for accessing and updating fields,
    | you need to run the contact service's outputFields method first and past the output in here.
    | Example below.
    |
    */

    'field_mappings' => [
        'firstName' => '0bce03e9000000000000000000<KEY>',
        'lastName' => '0bce03e9000000000000000000<KEY>'
    ],

    /*
    |--------------------------------------------------------------------------
    | Bronto Contact Field to Bronto Contact Object Mappings
    |--------------------------------------------------------------------------
    |
    | Now we map the properties of the SDK's Contact object to the field mappings
    | above. The values on the right should match the mapping names above. The values
    | here are from the MJ Bale Bronto contact fields, and are just an example.
    |
    */

    'contact_mappings' => [
        'id' => 'id',
        'firstName' => 'firstname',
        'lastName' => 'lastname',
        'gender' => 'gender',
        'birthday' => 'birthday',
        'companyName' => 'Company',
        'jobTitle' => 'Job_Title',
        'phoneHome' => 'Phone_number',
        'phoneMobile' => 'phone_mobile',
        'salutation' => 'salutation',
        'address1' => 'address1',
        'address2' => 'address2',
        'city' => 'city',
        'suburb' => 'suburb',
        'state' => 'state_province',
        'postCode' => 'postal_code',
        'creationDate' => 'Person_created_date',
    ],

];
