[
  {
    "path": ".gitignore",
    "content": "/vendor\ncomposer.lock"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 Amsgames, LLC\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "ITwrx fork of LARAVEL SHOP (minor changes for Laravel 5.2 Compatibility)\n--------------------------------\n\n[![Latest Stable Version](https://poser.pugx.org/amsgames/laravel-shop/v/stable)](https://packagist.org/packages/amsgames/laravel-shop)\n[![Total Downloads](https://poser.pugx.org/amsgames/laravel-shop/downloads)](https://packagist.org/packages/amsgames/laravel-shop)\n[![Latest Unstable Version](https://poser.pugx.org/amsgames/laravel-shop/v/unstable)](https://packagist.org/packages/amsgames/laravel-shop)\n[![License](https://poser.pugx.org/amsgames/laravel-shop/license)](https://packagist.org/packages/amsgames/laravel-shop)\n\nLaravel Shop is flexible way to add shop functionality to **Laravel 5.2**. Aimed to be the e-commerce solution for artisans.\n\nLaravel shop adds shopping cart, orders and payments to your new or existing project; letting you transform any model into a shoppable item.\n\n**Supports**\n\n![PayPal](http://kamleshyadav.com/demo_ky/eventmanagementsystem/assets/front/images/paypal.png) ![Omnipay](http://s18.postimg.org/g68f3fs09/omnipay.jpg)\n\n## Contents\n\n- [Scope](#scope)\n- [Installation](#installation)\n- [Configuration](#configuration)\n    - [Database Setup](#database-setup)\n    - [Models Setup](#models)\n        - [Item](#item)\n        - [Cart](#cart)\n        - [Order](#order)\n        - [Transaction](#transaction)\n        - [User](#user)\n        - [Existing Model Conversion](#existing-model-conversion)\n    - [Dump Autoload](#dump-autoload)\n    - [Payment Gateways](#payment-gateways)\n        - [PayPal](#paypal)\n        - [Omnipay](#omnipay)\n- [Usage](#usage)\n    - [Shop](#shop)\n        - [Purchase Flow](#purchase-flow)\n        - [Payment Gateway](#payment-gateway)\n        - [Checkout](#checkout)\n        - [Order placement](#exceptions)\n        - [Payments](#payments)\n        - [Exceptions](#order-placement)\n    - [Shopping Cart](#shopping-cart)\n        - [Adding Items](#adding-items)\n        - [Removing Items](#removing-items)\n        - [Placing Order](#placing-order)\n        - [Cart Methods](#cart-methods)\n        - [Displaying](#removing-items)\n    - [Item](#item-1)\n    - [Order](#order-1)\n        - [Placing Transactions](#placing-transactions)\n        - [Order Methods](#order-methods)\n    - [Events](#events)\n        - [Handler Example](#event-handler-example)\n- [Payment Gateway Development](#payment-gateway-development)\n  - [Transaction](#transaction-1)\n  - [Callbacks](#callbacks)\n  - [Exceptions](#exception)\n- [License](#license)\n- [Additional Information](#additional-information)\n- [Change Log](#change-log)\n\n## Scope\n\nCurrent version includes:\n\n- Shop Items (transforms existing models into shoppable items that can be added to cart and orders)\n- Cart\n- Orders\n- Transactions\n- Payment gateways support\n- PayPal\n- Events\n\nOn the horizon:\n\n- Guest user cart\n- Shipping orders\n- Coupons\n- Product and variations solution\n- Backend dashboard\n- Frontend templates\n\n## Installation\n\nWith composer\n\n```bash\ncomposer require amsgames/laravel-shop\n```\n\nOr add\n\n```json\n\"amsgames/laravel-shop\": \"0.2.*\"\n```\n\nto your composer.json. Then run `composer install` or `composer update`.\n\nThen in your `config/app.php` add \n\n```php\nAmsgames\\LaravelShop\\LaravelShopProvider::class,\n```\n    \nin the `providers` array.\n\nThen add\n\n```php\n'Shop'      => Amsgames\\LaravelShop\\LaravelShopFacade::class,\n```\n    \nin the `aliases` array.\n\n## Configuration\n\nSet the configuration values in the `config/auth.php` file. This package will use them to refer to the user table and model.\n\nPublish the configuration for this package to further customize table names, model namespaces, currencies and other values. Run the following command:\n\n```bash\nphp artisan vendor:publish\n```\n\nA `shop.php` file will be created in your app/config directory.\n\n### Database Setup\n\nGenerate package migration file:\n\n```bash\nphp artisan laravel-shop:migration\n```\n\nThe command below will generate a new migration file with database commands to create the cart and item tables. The file will be located in `database/migrations`. Add additional fields if needed to fill your software needs.\n\nThe command will also create a database seeder to fill shop catalog of status and types.\n\nCreate schema in database: \n\n```bash\nphp artisan migrate\n```\n\nAdd the seeder to `database/seeds/DatabaseSeeder.php`:\n\n```php\nclass DatabaseSeeder extends Seeder\n{\n\n  public function run()\n  {\n    Model::unguard();\n\n    $this->call('LaravelShopSeeder');\n\n    Model::reguard();\n  }\n\n}\n```\n\nRun seeder (do `composer dump-autoload first`): \n\n```bash\nphp artisan db:seed\n```\n\n### Models\n\nThe following models must be created for the shop to function, these models can be customizable to fir your needs.\n\n#### Item\n\nCreate a Item model:\n\n```bash\nphp artisan make:model Item\n```\n\nThis will create the model file `app/Item.php`, edit it and make it look like (take in consideration your app's namespace):\n\n```php\n<?php\n\nnamespace App;\n\nuse Amsgames\\LaravelShop\\Models\\ShopItemModel;\n\nclass Item extends ShopItemModel\n{\n}\n```\n\nThe `Item` model has the following main attributes:\n- `id` &mdash; Item id.\n- `sku` &mdash; Stock Keeping Unit, aka your unique product identification within your store.\n- `price` &mdash; Item price.\n- `tax` &mdash; Item tax. Defaulted to 0.\n- `shipping` &mdash; Item shipping. Defaulted to 0.\n- `currency` &mdash; Current version of package will use USD as default.\n- `quantity` &mdash; Item quantity.\n- `class` &mdash; Class reference of the model being used as shoppable item. Optional when using array data.\n- `reference_id` &mdash; Id reference of the model being used as shoppable item. Optional when using array data.\n- `user_id` &mdash; Owner.\n- `displayPrice` &mdash; Price value formatted for shop display. i.e. \"$9.99\" instead of just \"9.99\".\n- `displayTax` &mdash; Tax value formatted for shop display. i.e. \"$9.99\" instead of just \"9.99\".\n- `displayShipping` &mdash; Tax value formatted for shop display. i.e. \"$9.99\" instead of just \"9.99\".\n- `displayName` &mdash; Based on the model's item name property.\n- `shopUrl` &mdash; Based on the model's item route property.\n- `wasPurchased` &mdash; Flag that indicates if item was purchased. This base on the status set in config file.\n- `created_at` &mdash; When the item record was created in the database.\n- `updated_at` &mdash; Last time when the item was updated.\n\nBusiness definition: Item used as a **cart item** or an **order item**.\n\n#### Cart\n\nCreate a Cart model:\n\n```bash\nphp artisan make:model Cart\n```\n\nThis will create the model file `app/Cart.php`, edit it and make it look like (take in consideration your app's namespace):\n\n```php\n<?php\n\nnamespace App;\n\nuse Amsgames\\LaravelShop\\Models\\ShopCartModel;\n\nclass Cart extends ShopCartModel \n{\n}\n```\n\nThe `Item` model has the following main attributes:\n- `id` &mdash; Cart id.\n- `user_id` &mdash; Owner.\n- `items` &mdash; Items in cart.\n- `count` &mdash; Total amount of items in cart.\n- `totalPrice` &mdash; Total price from all items in cart.\n- `totalTax` &mdash; Total tax from all items in cart, plus global tax set in config.\n- `totalShipping` &mdash; Total shipping from all items in cart.\n- `total` &mdash; Total amount to be charged, sums total price, total tax and total shipping.\n- `displayTotalPrice` &mdash; Total price value formatted for shop display. i.e. \"$9.99\" instead of just \"9.99\".\n- `displayTotalTax` &mdash; Total tax value formatted for shop display. i.e. \"$9.99\" instead of just \"9.99\".\n- `displayTotalShipping` &mdash; Total shipping value formatted for shop display. i.e. \"$9.99\" instead of just \"9.99\".\n- `displayTotal` &mdash; Total amount value formatted for shop display. i.e. \"$9.99\" instead of just \"9.99\".\n- `created_at` &mdash; When the cart record was created in the database.\n- `updated_at` &mdash; Last time when the cart was updated.\n\n#### Order\n\nCreate a Order model:\n\n```bash\nphp artisan make:model Order\n```\n\nThis will create the model file `app/Order.php`, edit it and make it look like (take in consideration your app's namespace):\n\n```php\n<?php\n\nnamespace App;\n\nuse Amsgames\\LaravelShop\\Models\\ShopOrderModel;\n\nclass Order extends ShopOrderModel \n{\n}\n```\n\nThe `Order` model has the following main attributes:\n- `id` &mdash; Order id or order number.\n- `user_id` &mdash; Owner.\n- `items` &mdash; Items in order.\n- `transactions` &mdash; Transactions made on order.\n- `statusCode` &mdash; Status code.\n- `count` &mdash; Total amount of items in order.\n- `totalPrice` &mdash; Total price from all items in order.\n- `totalTax` &mdash; Total tax from all items in order, plus global tax set in config.\n- `totalShipping` &mdash; Total shipping from all items in order.\n- `total` &mdash; Total amount to be charged, sums total price, total tax and total shipping.\n- `displayTotalPrice` &mdash; Total price value formatted for shop display. i.e. \"$9.99\" instead of just \"9.99\".\n- `displayTotalTax` &mdash; Total tax value formatted for shop display. i.e. \"$9.99\" instead of just \"9.99\".\n- `displayTotalShipping` &mdash; Total shipping value formatted for shop display. i.e. \"$9.99\" instead of just \"9.99\".\n- `displayTotal` &mdash; Total amount value formatted for shop display. i.e. \"$9.99\" instead of just \"9.99\".\n- `created_at` &mdash; When the order record was created in the database.\n- `updated_at` &mdash; Last time when the order was updated.\n\n#### Transaction\n\nCreate a Transaction model:\n\n```bash\nphp artisan make:model Transaction\n```\n\nThis will create the model file `app/Transaction.php`, edit it and make it look like (take in consideration your app's namespace):\n\n```php\n<?php\n\nnamespace App;\n\nuse Amsgames\\LaravelShop\\Models\\ShopTransactionModel;\n\nclass Transaction extends ShopTransactionModel \n{\n}\n```\n\nThe `Order` model has the following main attributes:\n- `id` &mdash; Order id or order number.\n- `order` &mdash; Items in order.\n- `gateway` &mdash; Gateway used.\n- `transaction_id` &mdash; Transaction id returned by gateway.\n- `detail` &mdash; Detail returned by gateway.\n- `token` &mdash; Token for gateway callbacks.\n- `created_at` &mdash; When the order record was created in the database.\n- `updated_at` &mdash; Last time when the order was updated.\n\n#### User\n\nUse the `ShopUserTrait` trait in your existing `User` model. By adding `use Amsgames\\LaravelShop\\Traits\\ShopUserTrait` and `use ShopUserTrait` like in the following example:\n\n```php\n<?php\n\nuse Amsgames\\LaravelShop\\Traits\\ShopUserTrait;\n\nclass User extends Model {\n\n\tuse Authenticatable, CanResetPassword, ShopUserTrait;\n\n}\n```\n\nThis will enable the relation with `Cart` and shop needed methods and attributes.\n- `cart` &mdash; User's cart.\n- `items` &mdash; Items (either order or cart).\n- `orders` &mdash; User's orders.\n\n#### Existing Model Conversion\n\nLaravel Shop package lets you convert any existing `Eloquent` model to a shoppable item that can be used within the shop without sacrificing any existing functionality. This feature will let the model be added to carts or orders. The will require two small steps:\n\nUse the `ShopItemTrait` in your existing model. By adding `use Amsgames\\LaravelShop\\Traits\\ShopItemTrait` and `use ShopItemTrait` like in the following example:\n\n```php\n<?php\n\nuse Amsgames\\LaravelShop\\Traits\\ShopItemTrait;\n\nclass MyCustomProduct extends Model {\n\n\tuse ShopItemTrait;\n\n\t// MY METHODS AND MODEL DEFINITIONS........\n\n}\n```\n\nAdd `sku` (string) and `price` (decimal, 20, 2) fields to your model's table. You can also include `name` (string), `tax` (decimal, 20, 2) and `shipping` (decimal, 20, 2), although these are optional. You can do this by creating a new migration:\n\n```bash\nphp artisan make:migration alter_my_table\n```\n\nDefine migration to look like the following example:\n\n```php\n<?php\n\nclass AlterMyTable extends Migration {\n\n\tpublic function up()\n\t{\n\t\tSchema::table('MyCustomProduct', function($table)\n\t\t{\n\t\t\t$table->string('sku')->after('id');\n\t\t\t$table->decimal('price', 20, 2)->after('sku');\n\t\t\t$table->index('sku');\n\t\t\t$table->index('price');\n\t\t});\n\t}\n\n\tpublic function down()\n\t{\n\t\t// Restore type field\n\t\tSchema::table('MyCustomProduct', function($table)\n\t\t{\n\t\t\t$table->dropColumn('sku');\n\t\t\t$table->dropColumn('price');\n\t\t});\n\t}\n\n}\n```\n\nRun the migration:\n\n```bash\nphp artisan migrate\n```\n\n##### Item name\nBy default, Laravel Shop will look for the `name` attribute to define the item's name. If your exisintg model has a different attribute assigned for the name, simply define it in a property within your model:\n\n```php\n<?php\n\nuse Amsgames\\LaravelShop\\Traits\\ShopItemTrait;\n\nclass MyCustomProduct extends Model {\n\n\tuse ShopItemTrait;\n\n\t/**\n\t * Custom field name to define the item's name.\n\t * @var string\n\t */\n\tprotected $itemName = 'product_name';\n\n\t// MY METHODS AND MODEL DEFINITIONS........\n\n}\n```\n\n##### Item url\nYou can define the URL attribute of the item by setting `itemRouteName` and `itemRouteParams` class properties. In the following example the url defined to show the product's profile is `product/{slug}`, the following changes must be applied to the model:\n\n```php\n<?php\n\nuse Amsgames\\LaravelShop\\Traits\\ShopItemTrait;\n\nclass MyCustomProduct extends Model {\n\n\tuse ShopItemTrait;\n\n    /**\n     * Name of the route to generate the item url.\n     *\n     * @var string\n     */\n    protected $itemRouteName = 'product';\n\n    /**\n     * Name of the attributes to be included in the route params.\n     *\n     * @var string\n     */\n    protected $itemRouteParams = ['slug'];\n\n\t// MY METHODS AND MODEL DEFINITIONS........\n\n}\n```\n\n### Dump Autoload\nDump composer autoload\n\n```bash\ncomposer dump-autoload\n```\n\n### Payment Gateways\n\nInstalled payment gateways can be configured and added in the `gateways` array in the `shop.php` config file, like:\n\n```php\n'gateways' => [\n    'paypal'            =>  Amsgames\\LaravelShopGatewayPaypal\\GatewayPayPal::class,\n    'paypalExpress'     =>  Amsgames\\LaravelShopGatewayPaypal\\GatewayPayPalExpress::class,\n],\n```\n\n#### PayPal\n\nLaravel Shop comes with PayPal support out of the box. You can use PayPal's `Direct Credit Card` or `PayPal Express` payments.\n\nTo configure PayPal and know how to use the gateways, please visit the [PayPal Gateway Package](https://github.com/amsgames/laravel-shop-gateway-paypal) page. \n\n#### Omnipay\n\nInstall [Omnipay Gateway](https://github.com/amostajo/laravel-shop-gateway-omnipay) to enable other payment services like 2Checkout, Authorize.net, Stripe and to name a few.\n\nYou might need to get some extra understanding about how [Omnipay](https://github.com/thephpleague/omnipay) works.\n\n## Usage\n\n### Shop\nShop methods to consider:\n\nFormat prices or other values to the price format specified in config:\n```php\n$formatted = Shop::format(9.99);\n// i.e. this will return $9.99 or the format set in the config file.\n```\n\n#### Purchase Flow\n\nWith Laravel Shop you can customize things to work your way, although we recommend standarize your purchase or checkout flow as following (will explain how to use the shop methods below):\n\n![Purchase Flow](http://s12.postimg.org/zfmsz6krh/laravelshop_New_Page.png)\n\n* (Step 1) - User views his cart.\n* (Step 2) - Continues into selecting the gateway to use.\n* (Step 3) - Continues into feeding the gateway selected with required information.\n* (Step 4) - Checkouts cart and reviews cart before placing order.\n* (Step 5) - Places order.\n\n#### Payment Gateway\n\nBefore any shop method is called, a payment gateway must be set:\n\n```php\n// Select the gateway to use\nShop::setGateway('paypal');\n\necho Shop::getGateway(); // echos: paypal\n```\n\nYou can access the gateway class object as well:\n\n```php\n$gateway = Shop::gateway();\n\necho $gateway; // echos: [{\"id\":\"paypal\"}] \n```\n\n#### Checkout\n\nOnce a payment gateway has been selected, you can call cart to checkout like this:\n\n```php\n// Checkout current users' cart\n$success = Shop::checkout();\n\n// Checkout q specific cart\n$success = Shop::checkout($cart);\n```\n\nThis will call the `onCheckout` function in the payment gateway and perform validations. This method will return a bool flag indication if operation was successful.\n\n#### Order Placement\n\nOnce a payment gateway has been selected and user has checkout, you can call order placement like:\n\n```php\n// Places order based on current users' cart\n$order = Shop::placeOrder();\n\n// Places order based on a specific cart\n$order = Shop::placeOrder($cart);\n```\n\n**NOTE:** `placeOrder()` will create an order, relate all the items in cart to the order and empty the cart. The `Order` model doen't include methods to add or remove items, any modification to the cart must be done before the order is placed. Be aware of this when designing your checkout flow.\n\nThis will call the `onCharge` function in the payment gateway and charge the user with the orders' total amount. `placeOrder()` will return an `Order` model with which you can verify the status and retrieve the transactions generated by the gateway.\n\n#### Payments\n\nPayments are handled gateways, this package comes with PayPal out of the box.\n\nYou can use PayPal's `Direct Credit Card` or `PayPal Express` payments.\n\nTo configure PayPal and know how to use its gateways, please visit the [PayPal Gateway Package](https://github.com/amsgames/laravel-shop-gateway-paypal) page. \n\n#### Exceptions\n\nIf checkout or placeOrder had errores, you can call and see the exception related:\n```php\n// On checkout\nif (!Shop::checkout()) {\n  $exception = Shop::exception();\n  echo $exception->getMessage(); // echos: error\n}\n\n// Placing order\n$order = Shop::placeOrder();\n\nif ($order->hasFailed) {\n  $exception = Shop::exception();\n  echo $exception->getMessage(); // echos: error\n}\n```\n\nCritical exceptions are stored in laravel's log.\n\n### Shopping Cart\nCarts are created per user in the database, this means that a user can have his cart saved when logged out and when he switches to a different device.\n\nLet's start by calling or creating the current user's cart:\n\n```php\n// From cart\n$cart = Cart::current();\n// Once a cart has been created, it can be accessed from user\n$user->cart;\n```\n\nNote: Laravel Shop doen not support guest at the moment.\n\nGet the cart of another user:\n\n```php\n$userId = 1;\n\n$cart = Cart::findByUser($userId);\n```\n\n#### Adding Items\n\nLest add one item of our test and existing model `MyCustomProduct`:\n\n```php\n$cart = Cart::current()->add(MyCustomProduct::find(1));\n```\n\nBy default the add method will set a quantity of 1.\n\nInstead lets add 3 `MyCustomProduct`;\n\n```php\n$cart = Cart::current();\n\n$cart->add(MyCustomProduct::find(1), 3);\n```\n\nOnly one item will be created per sku in the cart. If an item of the same `sku` is added, just on item will remain but its quantity will increase:\n\n```php\n$product = MyCustomProduct::find(1);\n\n// Adds 1\n$cart->add($product);\n\n// Adds 3\n$cart->add($product, 3);\n\n// Adds 2\n$cart->add($product, 2);\n\necho $cart->count; // echos: 6\n\n$second_product = MyCustomProduct::findBySKU('TEST');\n\n// Adds 2 of product 'TEST'\n$cart->add($second_product, 2);\n\n// Count based on quantity\necho $cart->count; // echos: 8\n\n// Count based on products\necho $cart->items->count(); // echos: 2\n```\n\nWe can reset the quantity of an item to a given value:\n\n```php\n// Add 3\n$cart->add($product, 3);\n\necho $cart->count; // echos: 3\n\n// Reset quantity to 4\n$cart->add($product, 4, $forceReset = true);\n\necho $cart->count; // echos: 4\n```\n\n\n#### Adding Unexistent Model Items\nYou can add unexistent items by inserting them as arrays, each array must contain `sku` and `price` keys:\n\n```php\n// Adds unexistent item model PROD0001\n$cart->add(['sku' => 'PROD0001', 'price' => 9.99]);\n\n// Add 4 items of SKU PROD0002\n$cart->add(['sku' => 'PROD0002', 'price' => 29.99], 4);\n```\n\n#### Removing Items\nLest remove our test and existing model `MyCustomProduct` from cart:\n\n```php\n$product = MyCustomProduct::find(1);\n\n// Remove the product from cart\n$cart = Cart::current()->remove($product);\n```\n\nThe example below will remove the item completly, but it is possible to only remove a certain quantity from the cart:\n\n```php\n// Removes only 2 from quantity\n// If the quantity is greater than 2, then 1 item will remain in cart\n$cart->remove($product, 2);\n```\n\nArrays can be used to remove unexistent model items:\n\n```php\n// Removes by sku\n$cart->remove(['sku' => 'PROD0001']);\n```\n\nTo empty cart:\n\n```php\n$cart->clear();\n```\n\nThese methods can be chained:\n\n```php\n$cart->add($product, 5)\n    ->add($product2)\n    ->remove($product3)\n    ->clear();\n```\n\n#### Cart Methods\n\n```php\n// Checks if cart has item with SKU \"PROD0001\"\n$success = $cart->hasItem('PROD0001');\n```\n\n#### Placing Order\n\nYou can place an order directly from the cart without calling the `Shop` class, although this will only create the order record in the database and no payments will be processed. Same ad when using `Shop`, the cart will be empty after the order is placed.\n\n```php\n// This will create the order and set it to the status in configuration\n$order = $cart->placeOrder();\n```\n\nStatus can be forced in creation as well:\n```php\n$order = $cart->placeOrder('completed');\n```\n\n#### Displaying\n\nHew is an example of how to display the cart in a blade template:\n\nItems count in cart:\n\n```html\n<span>Items in cart: {{ $cart->count }}</span>\n```\n\nItems in cart:\n\n```html\n<table>\n\t@foreach ($cart->items as $item) {\n\t\t<tr>\n\t\t\t<td>{{ $item->sku }}</td>\n\t\t\t<td><a href=\"{{ $item->shopUrl }}\">{{ $item->displayName }}</a></td>\n\t\t\t<td>{{ $item->price }}</td>\n\t\t\t<td>{{ $item->displayPrice }}</td>\n\t\t\t<td>{{ $item->tax }}</td>\n\t\t\t<td>{{ $item->quantity }}</td>\n\t\t\t<td>{{ $item->shipping }}</td>\n\t\t</tr>\n\t@endforeach\n</table>\n```\n\nCart amount calculations:\n\n```html\n<table>\n\n\t<tbody>\n\t\t<tr>\n\t\t\t<td>Subtotal:</td>\n\t\t\t<td>{{ $cart->displayTotalPrice }}</td>\n            <td>{{ $cart->totalPrice }}</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>Shipping:</td>\n\t\t\t<td>{{ $cart->displayTotalShipping }}</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td>Tax:</td>\n\t\t\t<td>{{ $cart->displayTotalTax }}</td>\n\t\t</tr>\n\t</tbody>\n\n\t<tfoot>\n\t\t<tr>\n\t\t\t<th>Total:</th>\n\t\t\t<th>{{ $cart->displayTotal }}</th>\n            <th>{{ $cart->total }}</th>\n\t\t</tr>\n\t</tfoot>\n\n</table>\n```\n\n### Item\n\nModels or arrays inserted in a cart or order are converted into SHOP ITEMS, model `Item` is used instead within the shop.\n\nModel objects can be retrieved from a SHOP ITEM:\n\n```php\n// Lets assume that the first Cart item is MyCustomProduct.\n$item = $cart->items[0];\n\n// Check if item has model\nif ($item->hasObject) {\n\t$myproduct = $item->object;\n}\n```\n\n`$item->object` is `MyCustomProduct` model already loaded, we can access its properties and methods directly, like:\n\n```php\n// Assuming MyCustomProduct has a types relationship.\n$item->object->types;\n\n// Assuming MyCustomProduct has myAttribute attribute.\n$item->object->myAttribute;\n```\n\nThe following shop methods apply to model `Item` or exiting models that uses `ShopItemTrait`:\n\n```php\n$item = Item::findBySKU('PROD0001');\n\n$item = MyCustomProduct::findBySKU('PROD0002');\n\n// Quering\n$item = Item::whereSKU('PROD0001')->where('price', '>', 0)->get();\n```\n\n### Order\nFind a specific order number:\n\n```php\n$order = Order::find(1);\n```\n\nFind orders form user:\n\n```php\n// Get orders from specific user ID.\n$orders = Order::findByUser($userId);\n// Get orders from specific user ID and status.\n$canceled_orders = Order::findByUser($userId, 'canceled');\n```\n\n#### Placing Transactions\n\nYou can place a transaction directly from the order without calling the `Shop` class, although this will only create the transaction record in the database and no payments will be processed.\n\n```php\n// This will create the order and set it to the status in configuration\n$transaction = $order->placeTransaction(\n\t\t$gateway \t\t\t\t= 'my_gateway',\n\t\t$transactionId \t= 55555,\n\t\t$detail \t\t\t\t= 'Custom transaction 55555'\n);\n```\n\n#### Order Methods\n\n```php\n$completed = $order->isCompleted\n// Checks if order is in a specific status.\n$success = $order->is('completed');\n\n// Quering\n// Get orders from specific user ID.\n$orders = Order::whereUser($userId)->get();\n// Get orders from specific user ID and status.\n$completed_orders = Order::whereUser($userId)\n\t\t->whereStatus('completed')\n\t\t->get();\n```\n\n#### Order Status Codes\n\nStatus codes out of the box:\n- `in_creation` &mdash; Order status in creation. Or use `$order->isInCreation`.\n- `pending` &mdash; Pending for payment. Or use `$order->isPending`.\n- `in_process` &mdash; In process of shipping. In process of revision. Or use `$order->isInProcess`.\n- `completed` &mdash; When payment has been made and items were delivered to client. Or use `$order->isCompleted`.\n- `failed` &mdash; When payment failed. Or use `$order->hasFailed`.\n- `canceled` &mdash; When an order has been canceled by the user. Or use `$order->isCanceled`.\n\nYou can use your own custom status codes. Simply add them manually to the `order_status` database table or create a custom seeder like this:\n\n```php\nclass MyCustomStatusSeeder extends Seeder\n{\n\n  public function run()\n  {\n\n    DB::table('order_status')->insert([\n\t\t    [\n\t\t    \t\t'code' \t\t\t\t=> 'my_status',\n\t\t    \t\t'name' \t\t\t\t=> 'My Status',\n\t\t    \t\t'description' => 'Custom status used in my shop.',\n\t\t    ],\n\t\t]);\n\n  }\n}\n```\n\nThen use it like:\n\n```php\n$myStatusCode = 'my_status';\n\nif ($order->is($myStatusCode)) {\n\techo 'My custom status work!';\n}\n```\n\n### Events\n\nLaravel Shop follows [Laravel 5 guidelines](http://laravel.com/docs/5.1/events) to fire events, create your handlers and listeners like you would normally do to use them.\n\n| Event  | Description | Data passed |\n| ------------- | ------------- | ------------- |\n| Cart checkout | Event fired after a shop has checkout a cart. | `id` - Cart Id `success` - Checkout result (boolean) |\n| Order placed | Event fired when an order has been placed. | `id` - Order Id |\n| Order completed | Event fired when an order has been completed. | `id` - Order Id |\n| Order status changed | Event fired when an order's status has been changed. | `id` - Order Id `statusCode` - New status `previousStatusCode` - Prev status |\n\nHere are the events references:\n\n| Event  | Reference |\n| ------------- | ------------- |\n| Cart checkout | `Amsgames\\LaravelShop\\Events\\CartCheckout` |\n| Order placed | `Amsgames\\LaravelShop\\Events\\OrderPlaced` |\n| Order completed | `Amsgames\\LaravelShop\\Events\\OrderCompleted` |\n| Order status changed | `Amsgames\\LaravelShop\\Events\\OrderStatusChanged` |\n\n#### Event Handler Example\n\nAn example of how to use an event in a handler:\n\n```php\n<?php\n\nnamespace App\\Handlers\\Events;\n\nuse App\\Order;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\n\nuse Amsgames\\LaravelShop\\Events\\OrderCompleted;\n\nclass NotifyPurchase implements ShouldQueue\n{\n    use InteractsWithQueue;\n\n    /**\n     * Handle the event.\n     *\n     * @param  OrderPurchased $event\n     * @return void\n     */\n    public function handle(OrderCompleted $event)\n    {\n        // The order ID\n        echo $event->id;\n\n        // Get order model object\n        $order = Order::find($event->id);\n\n        // My code here...\n    }\n}\n```\n\nRemember to register your handles and listeners at the Event Provider:\n\n```php\n        'Amsgames\\LaravelShop\\Events\\OrderCompleted' => [\n            'App\\Handlers\\Events\\NotifyPurchase',\n        ],\n```\n\n## Payment Gateway Development\nLaravel Shop has been developed for customization in mind. Allowing the community to expand its capabilities.\n\nMissing payment gateways can be easily developed as external packages and then be configured in the config file. \n\nMake this proyect a required dependency of your package or laravel's setup and simply extend from Laravel Shop core class, here a PayPal example:\n\n```php\n<?php\n\nnamespace Vendor\\Package;\n\nuse Amsgames\\LaravelShop\\Core\\PaymentGateway;\nuse Amsgames\\LaravelShop\\Exceptions\\CheckoutException;\nuse Amsgames\\LaravelShop\\Exceptions\\GatewayException;\n\nclass GatewayPayPal extends PaymentGateway\n{\n    /**\n     * Called on cart checkout.\n     * THIS METHOD IS OPTIONAL, DONE FOR GATEWAY VALIDATIONS BEFORE PLACING AN ORDER\n     *\n     * @param Order $order Order.\n     */\n    public function onCheckout($cart)\n    {\n        throw new CheckoutException('Checkout failed.');\n    }\n\n    /**\n     * Called by shop to charge order's amount.\n     *\n     * @param Order $order Order.\n     *\n     * @return bool\n     */\n    public function onCharge($order)\n    {\n        throw new GatewayException('Payment failed.');\n        return false;\n    }\n}\n```\n\nThe gateway will require `onCharge` method as minimun. You can add more depending your needs.\n\nOnce created, you can add it to the `shop.php` config file, like:\n\n```php\n'gateways' => [\n    'paypal'              =>  Vendor\\Package\\GatewayPaypal::class,\n],\n```\n\nAnd use it like:\n\n```php\nShop::setGateway('paypal');\n```\n\n### Transaction\n\nTo properly generate the transaction there are 3 properties you must consider on setting during `onCharge`:\n\n```php\npublic function onCharge($order)\n{\n    // The transaction id generated by the provider i.e.\n    $this->transactionId = $paypal->transactionId;\n\n    // Custom detail of 1024 chars.\n    $this->detail = 'Paypal: success';\n\n    // Order status after method call.\n    $this->statusCode = 'in_process';\n\n    return true;\n}\n```\n- `transactionId` &mdash; Provider's transaction ID, will help identify a transaction.\n- `detail` &mdash; Custom description for the transaction.\n- `statusCode` &mdash; Order status code with which to update the order after onCharge has executed. By default is 'completed'.\n\n### Callbacks\n\nLaravel Shop supports gateways that require callbacks. For this, you will need to add 2 additional functions to your gateway:\n\n```php\n<?php\n\nnamespace Vendor\\Package;\n\nuse Amsgames\\LaravelShop\\Core\\PaymentGateway;\nuse Amsgames\\LaravelShop\\Exceptions\\CheckoutException;\nuse Amsgames\\LaravelShop\\Exceptions\\GatewayException;\n\nclass GatewayWithCallbacks extends PaymentGateway\n{\n    /**\n     * Called by shop to charge order's amount.\n     *\n     * @param Order $order Order.\n     *\n     * @return bool\n     */\n    public function onCharge($order)\n    {\n\n        // Set the order to pending.\n        $this->statusCode = 'pending';\n\n        // Sets provider with the callback for successful transactions.\n        $provider->setSuccessCallback( $this->callbackSuccess );\n\n        // Sets provider with the callback for failed transactions.\n        $provider->setFailCallback( $this->callbackFail );\n\n        return true;\n    }\n\n    /**\n     * Called on callback.\n     *\n     * @param Order $order Order.\n     * @param mixed $data  Request input from callback.\n     *\n     * @return bool\n     */\n    public function onCallbackSuccess($order, $data = null)\n    {\n        $this->statusCode     = 'completed';\n\n        $this->detail         = 'successful callback';\n\n        $this->transactionId  = $data->transactionId;\n\n        // My code...\n    }\n\n    /**\n     * Called on callback.\n     *\n     * @param Order $order Order.\n     * @param mixed $data  Request input from callback.\n     *\n     * @return bool\n     */\n    public function onCallbackFail($order, $data = null)\n    {\n        $this->detail       = 'failed callback';\n\n        // My code...\n    }\n}\n```\nIn the example above, `onCharge` instead of creating a completed transaction, it is creating a pending transaction and indicating the provider to which urls to call back with the payment results.\n\nThe methods `onCallbackSuccess` and `onCallbackFail` are called by `Shop` when the provider calls back with its reponse, the proper function will be called depending on the callback url used by the provider.\n\nThe method `onCallbackSuccess` will create a new transaction for the order it ends.\n\n- `callbackSuccess` &mdash; Successful url callback to be used by the provider.\n- `callbackFail` &mdash; i.e. Failure url callback to be used by the provider.\n- `token` &mdash; i.e. Validation token.\n\n### Exceptions\n\nLaravel Shop provides several exceptions you can use to report errors.\n\nFor `onCheckout`:\n- `CheckoutException`\n- `GatewayException`\n- `StoreException` &mdash; This exception will be logged in laravel, so use it only for fatal errores.\n\nFor `onChange`, `onCallbackSuccess` and `onCallbackFail`:\n- `GatewayException`\n- `StoreException` &mdash; This exception will be logged in laravel, so use it only for fatal errores.\n\n**NOTE**: Laravel Shop will not catch any other exception. If a normal `Exception` or any other exceptions is thrown, it will break the method as it normally would, this will affect your checkout flow like in example when you want to get the order from `placeOrder()`.\n\n### Examples\n\nYou can see the [PayPal gateways](https://github.com/amsgames/laravel-shop-gateway-paypal/tree/master/src) we made as examples.\n\n- [GatewayPayPal](https://github.com/amsgames/laravel-shop-gateway-paypal/blob/master/src/GatewayPayPal.php) - Processes credit cards, uses `onCheckout` and `onCharge`.\n\n- [GatewayPayPalExpress](https://github.com/amsgames/laravel-shop-gateway-paypal/blob/master/src/GatewayPayPalExpress.php) - Processes callbacks, uses `onCallbackSuccess` and `onCharge`.\n\n## License\n\nLaravel Shop is free software distributed under the terms of the MIT license.\n\n## Additional Information\n\nThis package's architecture and design was inpired by the **Zizaco/entrust** package, we'll like to thank their contributors for their awesome woek.\n\n## Change Log\n* [v0.2.8](https://github.com/amsgames/laravel-shop/releases/tag/v0.2.8)\n"
  },
  {
    "path": "composer.json",
    "content": "{\n    \"name\": \"ITwrx/laravel-shop\",\n    \"description\": \"Package set to provide shop or e-commerce functionality (such as CART, ORDERS, TRANSACTIONS and ITEMS) to Laravel for customizable builds.\",\n    \"license\": \"MIT\",\n    \"keywords\": [\"shop\",\"laravel\",\"cart\",\"orders\",\"transactions\",\"paypal\",\"e-commerce\",\"shopping cart\",\"ecommerce\",\"shopping\"],\n    \"authors\": [\n        {\n            \"name\": \"Amsgames, LLC\",\n            \"email\": \"support@amsgames.com\"\n        },\n        {\n            \"name\": \"Alejandro Mostajo\",\n            \"email\": \"amostajo@gmail.com\"\n        }\n    ],\n    \"require\": {\n        \"php\": \">=5.5.9\",\n        \"illuminate/console\": \"~5.0\",\n        \"illuminate/support\": \"~5.0\",\n        \"ITwrx/laravel-shop-gateway-paypal\": \"1.0.*\"\n    },\n    \"autoload\": {\n        \"classmap\": [\n            \"src/Commands\"\n        ],\n        \"psr-4\": {\n            \"Amsgames\\\\LaravelShop\\\\\": \"src\"\n        }\n    },\n    \"minimum-stability\": \"dev\",\n    \"extra\": {\n    \"laravel\": {\n        \"providers\": [\n            \"ITwrx\\\\LaravelShop\\\\LaravelShopProvider\"\n        ],\n        \"aliases\": {\n            \"Shop\": \"ITwrx\\\\LaravelShop\\\\LaravelShopFacade\"\n        }\n    }\n}\n}\n"
  },
  {
    "path": "composer.lock.bk",
    "content": "{\n    \"_readme\": [\n        \"This file locks the dependencies of your project to a known state\",\n        \"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file\",\n        \"This file is @generated automatically\"\n    ],\n    \"hash\": \"fff0c5ff15d79f87bda8c01f92af4404\",\n    \"packages\": [\n        {\n            \"name\": \"ITwrx/laravel-shop-gateway-paypal\",\n            \"version\": \"1.0.x-dev\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/amsgames/laravel-shop-gateway-paypal.git\",\n                \"reference\": \"c0ba041bda3fdcc696e4a01278647f386e9d8715\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/amsgames/laravel-shop-gateway-paypal/zipball/c0ba041bda3fdcc696e4a01278647f386e9d8715\",\n                \"reference\": \"c0ba041bda3fdcc696e4a01278647f386e9d8715\",\n                \"shasum\": \"\"\n            },\n            \"require\": {\n                \"illuminate/console\": \"~5.0\",\n                \"illuminate/support\": \"~5.0\",\n                \"paypal/rest-api-sdk-php\": \"*\",\n                \"php\": \">=5.4.0\"\n            },\n            \"require-dev\": {\n                \"sami/sami\": \"dev-master\"\n            },\n            \"type\": \"library\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Amsgames\\\\LaravelShopGatewayPaypal\\\\\": \"src\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Amsgames, LLC\",\n                    \"email\": \"support@amsgames.com\"\n                },\n                {\n                    \"name\": \"Alejandro Mostajo\",\n                    \"email\": \"amostajo@gmail.com\"\n                }\n            ],\n            \"description\": \"PayPal gateway for Laravel Shop package.\",\n            \"keywords\": [\n                \"gateway\",\n                \"laravel shop\",\n                \"laravel-shop\",\n                \"paypal\"\n            ],\n            \"time\": \"2015-09-19 04:10:42\"\n        },\n        {\n            \"name\": \"danielstjules/stringy\",\n            \"version\": \"1.x-dev\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/danielstjules/Stringy.git\",\n                \"reference\": \"4749c205db47ee5b32e8d1adf6d9aff8db6caf3b\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/danielstjules/Stringy/zipball/4749c205db47ee5b32e8d1adf6d9aff8db6caf3b\",\n                \"reference\": \"4749c205db47ee5b32e8d1adf6d9aff8db6caf3b\",\n                \"shasum\": \"\"\n            },\n            \"require\": {\n                \"ext-mbstring\": \"*\",\n                \"php\": \">=5.3.0\"\n            },\n            \"require-dev\": {\n                \"phpunit/phpunit\": \"~4.0\"\n            },\n            \"type\": \"library\",\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Stringy\\\\\": \"src/\"\n                },\n                \"files\": [\n                    \"src/Create.php\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Daniel St. Jules\",\n                    \"email\": \"danielst.jules@gmail.com\",\n                    \"homepage\": \"http://www.danielstjules.com\"\n                }\n            ],\n            \"description\": \"A string manipulation library with multibyte support\",\n            \"homepage\": \"https://github.com/danielstjules/Stringy\",\n            \"keywords\": [\n                \"UTF\",\n                \"helpers\",\n                \"manipulation\",\n                \"methods\",\n                \"multibyte\",\n                \"string\",\n                \"utf-8\",\n                \"utility\",\n                \"utils\"\n            ],\n            \"time\": \"2015-07-23 00:54:12\"\n        },\n        {\n            \"name\": \"doctrine/inflector\",\n            \"version\": \"dev-master\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/doctrine/inflector.git\",\n                \"reference\": \"3a422c73f7bc556d39571f436b61fd58ccae0eb0\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/doctrine/inflector/zipball/3a422c73f7bc556d39571f436b61fd58ccae0eb0\",\n                \"reference\": \"3a422c73f7bc556d39571f436b61fd58ccae0eb0\",\n                \"shasum\": \"\"\n            },\n            \"require\": {\n                \"php\": \">=5.3.2\"\n            },\n            \"require-dev\": {\n                \"phpunit/phpunit\": \"4.*\"\n            },\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"1.0.x-dev\"\n                }\n            },\n            \"autoload\": {\n                \"psr-0\": {\n                    \"Doctrine\\\\Common\\\\Inflector\\\\\": \"lib/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Roman Borschel\",\n                    \"email\": \"roman@code-factory.org\"\n                },\n                {\n                    \"name\": \"Benjamin Eberlei\",\n                    \"email\": \"kontakt@beberlei.de\"\n                },\n                {\n                    \"name\": \"Guilherme Blanco\",\n                    \"email\": \"guilhermeblanco@gmail.com\"\n                },\n                {\n                    \"name\": \"Jonathan Wage\",\n                    \"email\": \"jonwage@gmail.com\"\n                },\n                {\n                    \"name\": \"Johannes Schmitt\",\n                    \"email\": \"schmittjoh@gmail.com\"\n                }\n            ],\n            \"description\": \"Common String Manipulations with regard to casing and singular/plural rules.\",\n            \"homepage\": \"http://www.doctrine-project.org\",\n            \"keywords\": [\n                \"inflection\",\n                \"pluralize\",\n                \"singularize\",\n                \"string\"\n            ],\n            \"time\": \"2015-09-17 13:29:15\"\n        },\n        {\n            \"name\": \"illuminate/console\",\n            \"version\": \"dev-master\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/illuminate/console.git\",\n                \"reference\": \"5f532c52100e9aa9c7ee66f4581534093ac44975\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/illuminate/console/zipball/5f532c52100e9aa9c7ee66f4581534093ac44975\",\n                \"reference\": \"5f532c52100e9aa9c7ee66f4581534093ac44975\",\n                \"shasum\": \"\"\n            },\n            \"require\": {\n                \"illuminate/contracts\": \"5.2.*\",\n                \"illuminate/support\": \"5.2.*\",\n                \"nesbot/carbon\": \"~1.20\",\n                \"php\": \">=5.5.9\",\n                \"symfony/console\": \"3.0.*\"\n            },\n            \"suggest\": {\n                \"guzzlehttp/guzzle\": \"Required to use the thenPing method on schedules (~6.0).\",\n                \"mtdowling/cron-expression\": \"Required to use scheduling component (~1.0).\",\n                \"symfony/process\": \"Required to use scheduling component (3.0.*).\"\n            },\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"5.2-dev\"\n                }\n            },\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Illuminate\\\\Console\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Taylor Otwell\",\n                    \"email\": \"taylorotwell@gmail.com\"\n                }\n            ],\n            \"description\": \"The Illuminate Console package.\",\n            \"homepage\": \"http://laravel.com\",\n            \"time\": \"2015-09-17 22:37:41\"\n        },\n        {\n            \"name\": \"illuminate/contracts\",\n            \"version\": \"dev-master\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/illuminate/contracts.git\",\n                \"reference\": \"854d3a6021f3dcda1f5624d0e33ebf2c2ab6e3e5\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/illuminate/contracts/zipball/854d3a6021f3dcda1f5624d0e33ebf2c2ab6e3e5\",\n                \"reference\": \"854d3a6021f3dcda1f5624d0e33ebf2c2ab6e3e5\",\n                \"shasum\": \"\"\n            },\n            \"require\": {\n                \"php\": \">=5.5.9\"\n            },\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"5.2-dev\"\n                }\n            },\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Illuminate\\\\Contracts\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Taylor Otwell\",\n                    \"email\": \"taylorotwell@gmail.com\"\n                }\n            ],\n            \"description\": \"The Illuminate Contracts package.\",\n            \"homepage\": \"http://laravel.com\",\n            \"time\": \"2015-09-17 15:05:48\"\n        },\n        {\n            \"name\": \"illuminate/support\",\n            \"version\": \"dev-master\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/illuminate/support.git\",\n                \"reference\": \"a868dba60dd510d5872bd6b464c2d7e3e5038ba6\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/illuminate/support/zipball/a868dba60dd510d5872bd6b464c2d7e3e5038ba6\",\n                \"reference\": \"a868dba60dd510d5872bd6b464c2d7e3e5038ba6\",\n                \"shasum\": \"\"\n            },\n            \"require\": {\n                \"danielstjules/stringy\": \"~1.8\",\n                \"doctrine/inflector\": \"~1.0\",\n                \"ext-mbstring\": \"*\",\n                \"illuminate/contracts\": \"5.2.*\",\n                \"php\": \">=5.5.9\"\n            },\n            \"suggest\": {\n                \"jeremeamia/superclosure\": \"Required to be able to serialize closures (~2.0).\",\n                \"symfony/var-dumper\": \"Required to use the dd function (3.0.*).\"\n            },\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"5.2-dev\"\n                }\n            },\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Illuminate\\\\Support\\\\\": \"\"\n                },\n                \"files\": [\n                    \"helpers.php\"\n                ]\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Taylor Otwell\",\n                    \"email\": \"taylorotwell@gmail.com\"\n                }\n            ],\n            \"description\": \"The Illuminate Support package.\",\n            \"homepage\": \"http://laravel.com\",\n            \"time\": \"2015-09-15 13:49:17\"\n        },\n        {\n            \"name\": \"nesbot/carbon\",\n            \"version\": \"1.20.0\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/briannesbitt/Carbon.git\",\n                \"reference\": \"bfd3eaba109c9a2405c92174c8e17f20c2b9caf3\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/briannesbitt/Carbon/zipball/bfd3eaba109c9a2405c92174c8e17f20c2b9caf3\",\n                \"reference\": \"bfd3eaba109c9a2405c92174c8e17f20c2b9caf3\",\n                \"shasum\": \"\"\n            },\n            \"require\": {\n                \"php\": \">=5.3.0\",\n                \"symfony/translation\": \"~2.6|~3.0\"\n            },\n            \"require-dev\": {\n                \"phpunit/phpunit\": \"~4.0\"\n            },\n            \"type\": \"library\",\n            \"autoload\": {\n                \"psr-0\": {\n                    \"Carbon\": \"src\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Brian Nesbitt\",\n                    \"email\": \"brian@nesbot.com\",\n                    \"homepage\": \"http://nesbot.com\"\n                }\n            ],\n            \"description\": \"A simple API extension for DateTime.\",\n            \"homepage\": \"http://carbon.nesbot.com\",\n            \"keywords\": [\n                \"date\",\n                \"datetime\",\n                \"time\"\n            ],\n            \"time\": \"2015-06-25 04:19:39\"\n        },\n        {\n            \"name\": \"paypal/rest-api-sdk-php\",\n            \"version\": \"dev-master\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/paypal/PayPal-PHP-SDK.git\",\n                \"reference\": \"fd6801cda18fc1ae29ef913370c1902679410dab\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/paypal/PayPal-PHP-SDK/zipball/fd6801cda18fc1ae29ef913370c1902679410dab\",\n                \"reference\": \"fd6801cda18fc1ae29ef913370c1902679410dab\",\n                \"shasum\": \"\"\n            },\n            \"require\": {\n                \"ext-curl\": \"*\",\n                \"ext-json\": \"*\",\n                \"php\": \">=5.3.0\"\n            },\n            \"require-dev\": {\n                \"phpunit/phpunit\": \"3.7.*\"\n            },\n            \"type\": \"library\",\n            \"autoload\": {\n                \"psr-0\": {\n                    \"PayPal\": \"lib/\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"Apache2\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"PayPal\",\n                    \"homepage\": \"https://github.com/paypal/rest-api-sdk-php/contributors\"\n                }\n            ],\n            \"description\": \"PayPal's PHP SDK for REST APIs\",\n            \"homepage\": \"http://paypal.github.io/PayPal-PHP-SDK/\",\n            \"keywords\": [\n                \"payments\",\n                \"paypal\",\n                \"rest\",\n                \"sdk\"\n            ],\n            \"time\": \"2015-08-17 19:32:36\"\n        },\n        {\n            \"name\": \"symfony/console\",\n            \"version\": \"dev-master\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/Console.git\",\n                \"reference\": \"c32d1e7ffe11b7329d72c94c5970ab4001c9f858\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/Console/zipball/c32d1e7ffe11b7329d72c94c5970ab4001c9f858\",\n                \"reference\": \"c32d1e7ffe11b7329d72c94c5970ab4001c9f858\",\n                \"shasum\": \"\"\n            },\n            \"require\": {\n                \"php\": \">=5.5.9\"\n            },\n            \"require-dev\": {\n                \"psr/log\": \"~1.0\",\n                \"symfony/event-dispatcher\": \"~2.8|~3.0\",\n                \"symfony/phpunit-bridge\": \"~2.8|~3.0\",\n                \"symfony/process\": \"~2.8|~3.0\"\n            },\n            \"suggest\": {\n                \"psr/log\": \"For using the console logger\",\n                \"symfony/event-dispatcher\": \"\",\n                \"symfony/process\": \"\"\n            },\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"3.0-dev\"\n                }\n            },\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Symfony\\\\Component\\\\Console\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Fabien Potencier\",\n                    \"email\": \"fabien@symfony.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Symfony Console Component\",\n            \"homepage\": \"https://symfony.com\",\n            \"time\": \"2015-09-14 14:15:24\"\n        },\n        {\n            \"name\": \"symfony/translation\",\n            \"version\": \"dev-master\",\n            \"source\": {\n                \"type\": \"git\",\n                \"url\": \"https://github.com/symfony/Translation.git\",\n                \"reference\": \"a4aa6e450b1c2a0545fa9724bc943a15ac0e0798\"\n            },\n            \"dist\": {\n                \"type\": \"zip\",\n                \"url\": \"https://api.github.com/repos/symfony/Translation/zipball/a4aa6e450b1c2a0545fa9724bc943a15ac0e0798\",\n                \"reference\": \"a4aa6e450b1c2a0545fa9724bc943a15ac0e0798\",\n                \"shasum\": \"\"\n            },\n            \"require\": {\n                \"php\": \">=5.5.9\"\n            },\n            \"conflict\": {\n                \"symfony/config\": \"<2.8\"\n            },\n            \"require-dev\": {\n                \"psr/log\": \"~1.0\",\n                \"symfony/config\": \"~2.8|~3.0\",\n                \"symfony/intl\": \"~2.8|~3.0\",\n                \"symfony/phpunit-bridge\": \"~2.8|~3.0\",\n                \"symfony/yaml\": \"~2.8|~3.0\"\n            },\n            \"suggest\": {\n                \"psr/log\": \"To use logging capability in translator\",\n                \"symfony/config\": \"\",\n                \"symfony/yaml\": \"\"\n            },\n            \"type\": \"library\",\n            \"extra\": {\n                \"branch-alias\": {\n                    \"dev-master\": \"3.0-dev\"\n                }\n            },\n            \"autoload\": {\n                \"psr-4\": {\n                    \"Symfony\\\\Component\\\\Translation\\\\\": \"\"\n                }\n            },\n            \"notification-url\": \"https://packagist.org/downloads/\",\n            \"license\": [\n                \"MIT\"\n            ],\n            \"authors\": [\n                {\n                    \"name\": \"Fabien Potencier\",\n                    \"email\": \"fabien@symfony.com\"\n                },\n                {\n                    \"name\": \"Symfony Community\",\n                    \"homepage\": \"https://symfony.com/contributors\"\n                }\n            ],\n            \"description\": \"Symfony Translation Component\",\n            \"homepage\": \"https://symfony.com\",\n            \"time\": \"2015-09-18 10:59:20\"\n        }\n    ],\n    \"packages-dev\": [],\n    \"aliases\": [],\n    \"minimum-stability\": \"dev\",\n    \"stability-flags\": [],\n    \"prefer-stable\": false,\n    \"prefer-lowest\": false,\n    \"platform\": {\n        \"php\": \">=5.5.9\"\n    },\n    \"platform-dev\": []\n}\n"
  },
  {
    "path": "src/.gitkeep",
    "content": ""
  },
  {
    "path": "src/Commands/MigrationCommand.php",
    "content": "<?php \n\nnamespace Amsgames\\LaravelShop;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Illuminate\\Console\\Command;\nuse Illuminate\\Support\\Facades\\Config;\n\nclass MigrationCommand extends Command\n{\n    /**\n     * The console command name.\n     *\n     * @var string\n     */\n    protected $name = 'laravel-shop:migration';\n\n    /**\n     * The console command description.\n     *\n     * @var string\n     */\n    protected $description = 'Creates a migration following the LaravelShop specifications.';\n\n    /**\n     * Execute the console command.\n     *\n     * @return void\n     */\n    public function fire()\n    {\n        $this->laravel->view->addNamespace('laravel-shop', substr(__DIR__, 0, -8).'views');\n\n        $cartTable          = Config::get('shop.cart_table');\n        $itemTable          = Config::get('shop.item_table');\n        $couponTable        = Config::get('shop.coupon_table');\n        $orderStatusTable   = Config::get('shop.order_status_table');\n        $orderTable         = Config::get('shop.order_table');\n        $transactionTable   = Config::get('shop.transaction_table');\n\n        // Migrations\n        $this->line('');\n        $this->info( \"Tables: $cartTable, $itemTable\" );\n\n        $message = \"A migration that creates '$cartTable', '$itemTable', '$orderTable'\".\n        \" tables will be created in database/migrations directory\";\n\n        $this->comment($message);\n        $this->line('');\n\n        if ($this->confirm('Proceed with the migration creation? [Yes|no]', 'Yes')) {\n\n            $this->line('');\n\n            $this->info('Creating migration...');\n            if ($this->createMigration(compact(\n                    'cartTable',\n                    'itemTable',\n                    'couponTable',\n                    'orderStatusTable',\n                    'orderTable',\n                    'transactionTable'\n                ))\n            ) {\n\n                $this->info('Migration successfully created!');\n            } else {\n                $this->error(\n                    \"Couldn't create migration.\\n Check the write permissions\".\n                    \" within the database/migrations directory.\"\n                );\n            }\n\n        }\n\n        // Seeder\n\n        $this->line('');\n        $this->info( \"Table seeders: $orderStatusTable\" );\n        $message = \"A seeder that seeds '$orderStatusTable' table(s) with data. Will be created in database/seeds directory\";\n\n        $this->comment($message);\n        $this->line('');\n\n        if ($this->confirm('Proceed with the seeder creation? [Yes|no]', 'Yes')) {\n\n            $this->line('');\n\n            $this->info('Creating seeder...');\n            if ($this->createSeeder(compact(\n                    'cartTable',\n                    'itemTable',\n                    'couponTable',\n                    'orderStatusTable',\n                    'orderTable',\n                    'transactionTable'\n                ))\n            ) {\n                $this->info('Seeder successfully created!');\n            } else {\n                $this->error(\n                    \"Couldn't create seeder.\\n Check the write permissions\".\n                    \" within the database/seeds directory.\"\n                );\n            }\n\n        }\n    }\n\n    /**\n     * Create the migration.\n     *\n     * @param array $data Data with table names.\n     *\n     * @return bool\n     */\n    protected function createMigration($data)\n    {\n        $migrationFile = base_path('/database/migrations') . '/' . date('Y_m_d_His') . '_shop_setup_tables.php';\n\n        $usersTable  = Config::get('auth.table');\n        $userModel   = Config::get('auth.model');\n        $userKeyName = (new $userModel())->getKeyName();\n\n        $data = array_merge($data, compact('usersTable', 'userKeyName'));\n\n        $output = $this->laravel->view->make('laravel-shop::generators.migration')->with($data)->render();\n\n        if (!file_exists($migrationFile) && $fs = fopen($migrationFile, 'x')) {\n            fwrite($fs, $output);\n            fclose($fs);\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Create the seeder.\n     *\n     * @param array $data Data with table names.\n     *\n     * @return bool\n     */\n    protected function createSeeder($data)\n    {\n        $seederFile = base_path('/database/seeds') . '/LaravelShopSeeder.php';\n\n        $output = $this->laravel->view->make('laravel-shop::generators.seeder')->with($data)->render();\n\n        if (!file_exists($seederFile) && $fs = fopen($seederFile, 'x')) {\n            fwrite($fs, $output);\n            fclose($fs);\n            return true;\n        }\n\n        return false;\n    }\n}"
  },
  {
    "path": "src/Config/config.php",
    "content": "<?php\n\n/**\n * This file is part of Amsgames\\LaravelShop,\n * Shop functionality for Laravel.\n *\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Shop name\n    |--------------------------------------------------------------------------\n    |\n    | Shop name.\n    |\n    */\n    'name' => 'Laravel Shop',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cart Model\n    |--------------------------------------------------------------------------\n    |\n    | This is the Cart model used by LaravelShop to create correct relations.\n    | Update the model if it is in a different namespace.\n    |\n    */\n    'cart' => 'App\\Cart',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cart Database Table\n    |--------------------------------------------------------------------------\n    |\n    | This is the table used by LaravelShop to save cart data to the database.\n    |\n    */\n    'cart_table' => 'cart',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Order Model\n    |--------------------------------------------------------------------------\n    |\n    | This is the Order model used by LaravelShop to create correct relations.\n    | Update the model if it is in a different namespace.\n    |\n    */\n    'order' => 'App\\Order',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Order Database Table\n    |--------------------------------------------------------------------------\n    |\n    | This is the table used by LaravelShop to save order data to the database.\n    |\n    */\n    'order_table' => 'orders',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Order Status Database Table\n    |--------------------------------------------------------------------------\n    |\n    | This is the table used by LaravelShop to save order status data to the database.\n    |\n    */\n    'order_status_table' => 'order_status',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Item Model\n    |--------------------------------------------------------------------------\n    |\n    | This is the Item model used by LaravelShop to create correct relations.\n    | Update the model if it is in a different namespace.\n    |\n    */\n    'item' => 'App\\Item',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Item Database Table\n    |--------------------------------------------------------------------------\n    |\n    | This is the table used by LaravelShop to save cart data to the database.\n    |\n    */\n    'item_table' => 'items',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Transaction Model\n    |--------------------------------------------------------------------------\n    |\n    | This is the Transaction model used by LaravelShop to create correct relations.\n    | Update the model if it is in a different namespace.\n    |\n    */\n    'transaction' => 'App\\Transaction',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Transaction Database Table\n    |--------------------------------------------------------------------------\n    |\n    | This is the table used by LaravelShop to save cart data to the database.\n    |\n    */\n    'transaction_table' => 'transactions',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Coupon Model\n    |--------------------------------------------------------------------------\n    |\n    | This is the Coupon model used by LaravelShop to create correct relations.\n    | Update the model if it is in a different namespace.\n    |\n    */\n    'coupon' => 'App\\Coupon',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Coupon Database Table\n    |--------------------------------------------------------------------------\n    |\n    | This is the table used by LaravelShop to save order data to the database.\n    |\n    */\n    'coupon_table' => 'coupons',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Shop currency code\n    |--------------------------------------------------------------------------\n    |\n    | Currency to use within shop.\n    |\n    */\n    'currency' => 'USD',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Shop currency symbol\n    |--------------------------------------------------------------------------\n    |\n    | Currency symbol to use within shop.\n    |\n    */\n    'currency_symbol' => '$',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Shop tax\n    |--------------------------------------------------------------------------\n    |\n    | Tax percentage to apply to all items. Value must be in decimal.\n    |\n    | Tax to apply:            8%\n    | Tax config value:        0.08\n    |\n    */\n    'tax' => 0.0,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Format with which to display prices across the store.\n    |--------------------------------------------------------------------------\n    |\n    | :symbol   = Currency symbol. i.e. \"$\"\n    | :price    = Price. i.e. \"0.99\"\n    | :currency = Currency code. i.e. \"USD\"\n    |\n    | Example format: ':symbol:price (:currency)'\n    | Example result: '$0.99 (USD)'\n    |\n    */\n    'display_price_format' => ':symbol:price',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Allow multiple coupons\n    |--------------------------------------------------------------------------\n    |\n    | Flag that indicates if user can apply more that one coupon to cart or orders.\n    |\n    */\n    'allow_multiple_coupons' => true,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cache shop calculations\n    |--------------------------------------------------------------------------\n    |\n    | Caches shop calculations, such as item count, cart total amount and similar.\n    | Cache is forgotten when adding or removing items.\n    | If not cached, calculations will be done every time their attributes are called.\n    | This configuration option exists if you don't wish to overload your cache.\n    |\n    */\n    'cache_calculations' => true,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cache calculations minutes\n    |--------------------------------------------------------------------------\n    |\n    | Amount of minutes to cache calculations.\n    |\n    */\n    'cache_calculations_minutes' => 15,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Order status lock\n    |--------------------------------------------------------------------------\n    |\n    | Order status where the order will remain locked from modifications.\n    |\n    */\n    'order_status_lock' => [],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Order status placement\n    |--------------------------------------------------------------------------\n    |\n    | Status to set when the order is placed and created by the cart.\n    |\n    */\n    'order_status_placement' => 'pending',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Order status placement\n    |--------------------------------------------------------------------------\n    |\n    | Status that determines if an order has been established and if items were purchased.\n    |\n    */\n    'order_status_purchase' => ['completed', 'in_process'],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Payment Gateways\n    |--------------------------------------------------------------------------\n    |\n    | List of payment gateways.\n    |\n    */\n    'gateways' => [\n        'paypal'            =>  Amsgames\\LaravelShopGatewayPaypal\\GatewayPayPal::class,\n        'paypalExpress'     =>  Amsgames\\LaravelShopGatewayPaypal\\GatewayPayPalExpress::class,\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Gatewall payment callback\n    |--------------------------------------------------------------------------\n    |\n    | Which route to call for gateway callbacks.\n    |\n    */\n    'callback_route' => 'shop.callback',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Redirect route after callback\n    |--------------------------------------------------------------------------\n    |\n    | Which route to call after the callback has been processed.\n    |\n    */\n    'callback_redirect_route' => '/',\n\n];"
  },
  {
    "path": "src/Contracts/PaymentGatewayInterface.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Contracts;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\ninterface PaymentGatewayInterface\n{\n    /**\n     * Constructor.\n     */\n    public function __construct($id = '');\n    \n    /**\n     * Called on cart checkout.\n     *\n     * @param Cart $cart Cart.\n     */\n    public function onCheckout($cart);\n\n    /**\n     * Called by shop to charge order's amount.\n     *\n     * @param Order $order Order.\n     *\n     * @return bool\n     */\n    public function onCharge($order);\n\n    /**\n     * Returns the transaction ID generated by the gateway.\n     * i.e. PayPal's transaction ID.\n     *\n     * @return mixed\n     */\n    public function getTransactionId();\n\n    /**\n     * Returns a 1024 length string with extra detail of transaction.\n     *\n     * @return string\n     */\n    public function getTransactionDetail();\n\n    /**\n     * Returns token.\n     *\n     * @return string\n     */\n    public function getTransactionToken();\n\n    /**\n     * Called by shop when payment gateway calls callback url.\n     * Success result\n     *\n     * @param Order $order Order.\n     * @param mixed $data  Request input from callback.\n     */\n    public function onCallbackSuccess($order, $data = null);\n\n    /**\n     * Called by shop when payment gateway calls callback url.\n     * Failed result\n     *\n     * @param Order $order Order.\n     * @param mixed $data  Request input from callback.\n     */\n    public function onCallbackFail($order, $data = null);\n\n    /**\n     * Sets callback urls\n     *\n     * @param Order $order Order.\n     */\n    public function setCallbacks($order);\n\n    /**\n     * Returns transaction status code.\n     *\n     * @return string\n     */\n    public function getTransactionStatusCode();\n\n}"
  },
  {
    "path": "src/Contracts/ShopCartInterface.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Contracts;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\ninterface ShopCartInterface\n{\n\n    /**\n     * One-to-One relations with the user model.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function user();\n\n    /**\n     * One-to-Many relations with Item.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function items();\n\n    /**\n     * Adds item to cart.\n     *\n     * @param mixed $item     Item to add, can be an Store Item, a Model with ShopItemTrait or an array.\n     * @param int   $quantity Item quantity in cart.\n     */\n    public function add($item, $quantity = 1, $quantityReset = self::QUANTITY_ADDITION);\n\n    /**\n     * Removes an item from the cart or decreases its quantity.\n     * Returns flag indicating if removal was successful.\n     *\n     * @param mixed $item     Item to remove, can be an Store Item, a Model with ShopItemTrait or an array.\n     * @param int   $quantity Item quantity to decrease. 0 if wanted item to be removed completly.\n     *\n     * @return bool\n     */\n    public function remove($item, $quantity = 0);\n\n    /**\n     * Checks if the user has a role by its name.\n     *\n     * @param string|array $name       Role name or array of role names.\n     * @param bool         $requireAll All roles in the array are required.\n     *\n     * @return bool\n     */\n    public function hasItem($sku, $requireAll = false);\n\n    /**\n     * Scope to current user cart and returns class model.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query  Query.\n     *\n     * @return this\n     */\n    public function scopeCurrent($query);\n\n    /**\n     * Returns total amount of items in cart.\n     *\n     * @return int\n     */\n    public function getCountAttribute();\n\n    /**\n     * Returns total price of all the items in cart.\n     *\n     * @return float\n     */\n    public function getTotalPriceAttribute();\n\n    /**\n     * Returns total tax of all the items in cart.\n     *\n     * @return float\n     */\n    public function getTotalTaxAttribute();\n\n    /**\n     * Returns total tax of all the items in cart.\n     *\n     * @return float\n     */\n    public function getTotalShippingAttribute();\n\n    /**\n     * Returns total discount amount based on all coupons applied.\n     *\n     * @return float\n     */\n    public function getTotalDiscountAttribute();\n\n    /**\n     * Returns total amount to be charged base on total price, tax and discount.\n     *\n     * @return float\n     */\n    public function getTotalAttribute();\n\n    /**\n     * Returns formatted total price of all the items in cart.\n     *\n     * @return string\n     */\n    public function getDisplayTotalPriceAttribute();\n\n    /**\n     * Returns formatted total tax of all the items in cart.\n     *\n     * @return string\n     */\n    public function getDisplayTotalTaxAttribute();\n\n    /**\n     * Returns formatted total tax of all the items in cart.\n     *\n     * @return string\n     */\n    public function getDisplayTotalShippingAttribute();\n\n    /**\n     * Returns formatted total discount amount based on all coupons applied.\n     *\n     * @return string\n     */\n    public function getDisplayTotalDiscountAttribute();\n\n    /**\n     * Returns formatted total amount to be charged base on total price, tax and discount.\n     *\n     * @return string\n     */\n    public function getDisplayTotalAttribute();\n\n    /**\n     * Transforms cart into an order.\n     * Returns created order.\n     *\n     * @param mixed $status Order status to create order with.\n     *\n     * @return Order\n     */\n    public function placeOrder($statusCode = null);\n\n    /**\n     * Whipes put cart\n     */\n    public function clear();\n\n}"
  },
  {
    "path": "src/Contracts/ShopCouponInterface.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Contracts;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\ninterface ShopCouponInterface\n{\n\n    /**\n     * Scopes class by coupon code.\n     *\n     * @return QueryBuilder\n     */\n    public function scopeWhereCode($query, $code);\n\n    /**\n     * Scopes class by coupen code and returns object.\n     *\n     * @return this\n     */\n    public function scopeFindByCode($query, $code);\n\n}"
  },
  {
    "path": "src/Contracts/ShopItemInterface.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Contracts;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\ninterface ShopItemInterface\n{\n\n    /**\n     * One-to-One relations with the user model.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function user();\n\n    /**\n     * One-to-One relations with the cart model.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function cart();\n\n    /**\n     * One-to-One relations with Order.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function order();\n\n    /**\n     * Returns flag indicating if item has an object.\n     *\n     * @return bool\n     */\n    public function getHasObjectAttribute();\n\n    /**\n     * Returns attached object.\n     *\n     * @return mixed\n     */\n    public function getObjectAttribute();\n    \n    /**\n     * Returns item name.\n     *\n     * @return string\n     */\n    public function getDisplayNameAttribute();\n\n    /**\n     * Returns shop it.\n     *\n     * @return mixed\n     */\n    public function getShopIdAttribute();\n\n    /**\n     * Returns formatted price for display.\n     *\n     * @return string\n     */\n    public function getDisplayPriceAttribute();\n\n    /**\n     * Returns formatted tax for display.\n     *\n     * @return string\n     */\n    public function getDisplayTaxAttribute();\n\n    /**\n     * Returns formatted tax for display.\n     *\n     * @return string\n     */\n    public function getDisplayShippingAttribute();\n\n    /**\n     * Returns flag indicating if item was purchased by user.\n     *\n     * @return bool\n     */\n    public function getWasPurchasedAttribute();\n\n}"
  },
  {
    "path": "src/Contracts/ShopOrderInterface.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Contracts;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\ninterface ShopOrderInterface\n{\n\n    /**\n     * One-to-One relations with the user model.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToOne\n     */\n    public function user();\n\n    /**\n     * One-to-Many relations with Item.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function items();\n\n    /**\n     * One-to-Many relations with Item.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function transactions();\n\n    /**\n     * Returns flag indicating if order is lock and cant be modified by the user.\n     * An order is locked the moment it enters pending status.\n     *\n     * @return bool\n     */\n    public function getIsLockedAttribute();\n\n    /**\n     * Scopes class by user ID and returns object.\n     * Optionally, scopes by status.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query      Query.\n     * @param mixed                                 $userId     User ID.\n     * @param string                                $statusCode Status.\n     *\n     * @return this\n     */\n    public function scopeFindByUser($query, $userId, $statusCode = null);\n\n    /**\n     * Returns total amount of items in cart.\n     *\n     * @return int\n     */\n    public function getCountAttribute();\n\n    /**\n     * Returns total price of all the items in cart.\n     *\n     * @return float\n     */\n    public function getTotalPriceAttribute();\n\n    /**\n     * Returns total tax of all the items in cart.\n     *\n     * @return float\n     */\n    public function getTotalTaxAttribute();\n\n    /**\n     * Returns total tax of all the items in cart.\n     *\n     * @return float\n     */\n    public function getTotalShippingAttribute();\n\n    /**\n     * Returns total discount amount based on all coupons applied.\n     *\n     * @return float\n     */\n    public function getTotalDiscountAttribute();\n\n    /**\n     * Returns total amount to be charged base on total price, tax and discount.\n     *\n     * @return float\n     */\n    public function getTotalAttribute();\n\n    /**\n     * Returns formatted total price of all the items in cart.\n     *\n     * @return string\n     */\n    public function getDisplayTotalPriceAttribute();\n\n    /**\n     * Returns formatted total tax of all the items in cart.\n     *\n     * @return string\n     */\n    public function getDisplayTotalTaxAttribute();\n\n    /**\n     * Returns formatted total tax of all the items in cart.\n     *\n     * @return string\n     */\n    public function getDisplayTotalShippingAttribute();\n\n    /**\n     * Returns formatted total discount amount based on all coupons applied.\n     *\n     * @return string\n     */\n    public function getDisplayTotalDiscountAttribute();\n\n    /**\n     * Returns formatted total amount to be charged base on total price, tax and discount.\n     *\n     * @return string\n     */\n    public function getDisplayTotalAttribute();\n\n    /**\n     * Returns flag indicating if order is in the status specified.\n     *\n     * @param string $status Status code.\n     *\n     * @return bool\n     */\n    public function is($statusCode);\n\n    /**\n     * Creates the order's transaction.\n     *\n     * @param string $gateway       Gateway.\n     * @param mixed  $transactionId Transaction ID.\n     * @param string $detail        Transaction detail.\n     *\n     * @return object\n     */\n    public function placeTransaction($gateway, $transactionId, $detail = '');\n\n    /**\n     * Scopes class by item sku.\n     * Optionally, scopes by status.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query  Query.\n     * @param mixed                                 $sku    Item SKU.\n     *\n     * @return this\n     */\n    public function scopeWhereSKU($query, $sku);\n\n    /**\n     * Scopes class by status codes.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query       Query.\n     * @param array                                 $statusCodes Status.\n     *\n     * @return this\n     */\n    public function scopeWhereStatusIn($query, array $statusCodes);\n\n}"
  },
  {
    "path": "src/Contracts/ShopTransactionInterface.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Contracts;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\ninterface ShopTransactionInterface\n{\n    /**\n     * One-to-One relations with the order model.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function order();\n\n    /**\n     * Scopes to get transactions from user.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function scopeWhereUser($query, $userId);\n}"
  },
  {
    "path": "src/Core/PaymentGateway.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Core;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse JsonSerializable;\nuse Illuminate\\Contracts\\Support\\Arrayable;\nuse Illuminate\\Contracts\\Support\\Jsonable;\nuse Amsgames\\LaravelShop\\Contracts\\PaymentGatewayInterface;\n\nabstract class PaymentGateway implements PaymentGatewayInterface, Arrayable, Jsonable, JsonSerializable\n{\n    /**\n     * Gateway Id, set by shop.\n     *\n     * @var mixed\n     */\n    protected $id;\n\n    /**\n     * Gateway generated transaction id.\n     *\n     * @var mixed\n     */\n    protected $transactionId;\n\n    /**\n     * Gateway generated transaction id.\n     *\n     * @var string\n     */\n    protected $detail = null;\n\n    /**\n     * Gateway generated token.\n     *\n     * @var mixed\n     */\n    protected $token = null;\n\n    /**\n     * Success call back url.\n     *\n     * @var mixed\n     */\n    protected $callbackSuccess = '';\n\n    /**\n     * Fail call back url.\n     *\n     * @var mixed\n     */\n    protected $callbackFail = '';\n\n    /**\n     * Status code after placing order successfully.\n     *\n     * @var string\n     */\n    protected $statusCode = 'completed';\n\n    /**\n     * Constructor.\n     *\n     * @param mixed $if Gateway id.\n     */\n    public function __construct($id = '')\n    {\n        $this->id            = $id;\n        $this->transactionId = uniqid();\n        $this->token         = uniqid();\n    }\n    \n    /**\n     * Called on cart checkout.\n     *\n     * @param Order $order Order.\n     */\n    public function onCheckout($cart)\n    {\n    }\n\n    /**\n     * Called by shop when payment gateway calls callback url.\n     * Success result\n     *\n     * @param Order $order Order.\n     * @param mixed $data  Callback data.\n     *\n     * @return string\n     */\n    public function onCallbackSuccess($order, $data = null)\n    {\n    }\n\n    /**\n     * Called by shop when payment gateway calls callback url.\n     * Failed result\n     *\n     * @param Order $order Order.\n     * @param mixed $data  Callback data.\n     *\n     * @return string\n     */\n    public function onCallbackFail($order, $data = null)\n    {\n    }\n\n    /**\n     * Sets callback urls\n     *\n     * @param Order $order Order.\n     */\n    public function setCallbacks($order)\n    {\n        $this->callbackSuccess = route(config('shop.callback_route'), [\n            'status'    => 'success',\n            'id'        => $order->id,\n            'token'     => $this->token,\n        ]);\n\n        $this->callbackFail    = route(config('shop.callback_route'), [\n            'status'    => 'fail',\n            'id'        => $order->id,\n            'token'     => $this->token,\n        ]);\n    }\n\n    /**\n     * Returns transaction token.\n     *\n     * @return mixed.\n     */\n    public function getTransactionToken()\n    {\n        return $this->token;\n    }\n\n    /**\n     * Returns the transaction ID generated by the gateway.\n     * i.e. PayPal's transaction ID.\n     *\n     * @return mixed\n     */\n    public function getTransactionId()\n    {\n        return $this->transactionId;\n    }\n\n    /**\n     * Returns a 1024 length string with extra detail of transaction.\n     *\n     * @return string\n     */\n    public function getTransactionDetail()\n    {\n        return $this->detail;\n    }\n\n    /**\n     * Returns transaction status code.\n     *\n     * @return string\n     */\n    public function getTransactionStatusCode()\n    {\n        return $this->statusCode;\n    }\n\n    /**\n     * Convert the model instance to an array.\n     *\n     * @return array\n     */\n    public function toArray()\n    {\n        return ['id' => $this->id];\n    }\n\n    /**\n     * Convert the model instance to JSON.\n     *\n     * @param  int  $options\n     * @return string\n     */\n    public function toJson($options = 0)\n    {\n        return json_encode($this->jsonSerialize(), $options);\n    }\n\n    /**\n     * Convert the object into something JSON serializable.\n     *\n     * @return array\n     */\n    public function jsonSerialize()\n    {\n        return $this->toArray();\n    }\n\n    /**\n     * Convert the model to its string representation.\n     *\n     * @return string\n     */\n    public function __toString()\n    {\n        return $this->toJson();\n    }\n\n\n}"
  },
  {
    "path": "src/Events/CartCheckout.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Events;\n\nuse Illuminate\\Queue\\SerializesModels;\n\n/**\n * Event fired when an order has been completed.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\nclass CartCheckout\n{\n\tuse SerializesModels;\n\n\t/**\n     * Cart ID.\n     * @var int\n     */\n\tpublic $id;\n\n     /**\n     * Flag that indicates if the checkout was successful or not.\n     * @var bool\n     */\n     public $success;\n\n\t/**\n     * Create a new event instance.\n     *\n     * @param int  $id      Order ID.\n     * @param bool $success Checkout flag result.\n     *\n     * @return void\n     */\n\tpublic function __construct($id, $success)\n\t{\n\t\t$this->id = $id;\n          $this->success = $success;\n\t}\n}"
  },
  {
    "path": "src/Events/OrderCompleted.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Events;\n\nuse Illuminate\\Queue\\SerializesModels;\n\n/**\n * Event fired when an order has been completed.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\nclass OrderCompleted\n{\n\tuse SerializesModels;\n\n\t/**\n     * Order ID.\n     * @var int\n     */\n\tpublic $id;\n\n\t/**\n     * Create a new event instance.\n     *\n     * @param int $id Order ID.\n     *\n     * @return void\n     */\n\tpublic function __construct($id)\n\t{\n\t\t$this->id = $id;\n\t}\n}"
  },
  {
    "path": "src/Events/OrderPlaced.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Events;\n\nuse Illuminate\\Queue\\SerializesModels;\n\n/**\n * Event fired when an order is placed.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\nclass OrderPlaced\n{\n\tuse SerializesModels;\n\n\t/**\n     * Order ID.\n     * @var int\n     */\n\tpublic $id;\n\n\t/**\n     * Create a new event instance.\n     *\n     * @param int $id Order ID.\n     *\n     * @return void\n     */\n\tpublic function __construct($id)\n\t{\n\t\t$this->id = $id;\n\t}\n}"
  },
  {
    "path": "src/Events/OrderStatusChanged.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Events;\n\nuse Illuminate\\Queue\\SerializesModels;\n\n/**\n * Event fired when an order has changed status code.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\nclass OrderStatusChanged\n{\n\tuse SerializesModels;\n\n\t/**\n     * Order ID.\n     * @var int\n     */\n\tpublic $id;\n\n     /**\n     * Order status code.\n     * @var string\n     */\n     public $statusCode;\n\n     /**\n     * Previous order status code.\n     * @var string\n     */\n     public $previousStatusCode;\n\n\t/**\n     * Create a new event instance.\n     *\n     * @param int    $id         Order ID.\n     * @param string $statusCode Order status code.\n     *\n     * @return void\n     */\n\tpublic function __construct($id, $statusCode, $previousStatusCode)\n\t{\n\t\t$this->id = $id;\n          $this->statusCode = $statusCode;\n          $this->previousStatusCode = $previousStatusCode;\n\t}\n}"
  },
  {
    "path": "src/Exceptions/CheckoutException.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Exceptions;\n\n/**\n * This class is the main entry point of laravel shop. Usually this the interaction\n * with this class will be done through the LaravelShop Facade\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nclass CheckoutException extends \\Exception\n{\n}"
  },
  {
    "path": "src/Exceptions/GatewayException.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Exceptions;\n\n/**\n * This class is the main entry point of laravel shop. Usually this the interaction\n * with this class will be done through the LaravelShop Facade\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nclass GatewayException extends \\Exception\n{\n}"
  },
  {
    "path": "src/Exceptions/ShopException.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Exceptions;\n\n/**\n * This class is the main entry point of laravel shop. Usually this the interaction\n * with this class will be done through the LaravelShop Facade\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nclass ShopException extends \\Exception\n{\n}"
  },
  {
    "path": "src/Gateways/GatewayCallback.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Gateways;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Amsgames\\LaravelShop\\Gateways\\GatewayPass;\n\nclass GatewayCallback extends GatewayPass\n{\n    /**\n     * For callback uses.\n     */\n    protected $didCallback = false;\n\n    /**\n     * Called by shop to charge order's amount.\n     *\n     * @param Order $order Order.\n     *\n     * @return bool\n     */\n    public function onCharge($order)\n    {\n        $this->statusCode   = 'pending';\n        $this->detail       = 'pending response, token:' .  $this->token;\n        return parent::onCharge($order);\n    }\n\n    /**\n     * Called on callback.\n     *\n     * @param Order $order Order.\n     * @param mixed $data  Request input from callback.\n     *\n     * @return bool\n     */\n    public function onCallbackSuccess($order, $data = null)\n    {\n        $this->statusCode   = 'completed';\n        $this->detail       = 'success callback';\n        $this->didCallback  = true;\n    }\n\n    /**\n     * Called on callback.\n     *\n     * @param Order $order Order.\n     * @param mixed $data  Request input from callback.\n     *\n     * @return bool\n     */\n    public function onCallbackFail($order, $data = null)\n    {\n        $this->statusCode   = 'failed';\n        $this->detail       = 'failed callback';\n        $this->didCallback  = true;\n    }\n\n    /**\n     * Returns successful callback URL\n     * @return false\n     */\n    public function getCallbackSuccess()\n    {\n        return $this->callbackSuccess;\n    }\n\n    /**\n     * Returns fail callback URL\n     * @return false\n     */\n    public function getCallbackFail()\n    {\n        return $this->callbackFail;\n    }\n\n    /**\n     * Returns successful callback URL\n     * @return false\n     */\n    public function getDidCallback()\n    {\n        return $this->didCallback;\n    }\n}"
  },
  {
    "path": "src/Gateways/GatewayFail.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Gateways;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Amsgames\\LaravelShop\\Exceptions\\CheckoutException;\nuse Amsgames\\LaravelShop\\Exceptions\\GatewayException;\nuse Amsgames\\LaravelShop\\Exceptions\\ShopException;\nuse Amsgames\\LaravelShop\\Core\\PaymentGateway;\n\nclass GatewayFail extends PaymentGateway\n{\n    /**\n     * Called on cart checkout.\n     *\n     * @param Order $order Order.\n     */\n    public function onCheckout($cart)\n    {\n        throw new CheckoutException('Checkout failed.');\n    }\n\n    /**\n     * Called by shop to charge order's amount.\n     *\n     * @param Order $order Order.\n     *\n     * @return bool\n     */\n    public function onCharge($order)\n    {\n        throw new GatewayException('Payment failed.');\n    \treturn false;\n    }\n}"
  },
  {
    "path": "src/Gateways/GatewayPass.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Gateways;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Log;\nuse Amsgames\\LaravelShop\\Core\\PaymentGateway;\n\nclass GatewayPass extends PaymentGateway\n{\n    /**\n     * Called by shop to charge order's amount.\n     *\n     * @param Order $order Order.\n     *\n     * @return bool\n     */\n    public function onCharge($order)\n    {\n        $this->transactionId = uniqid();\n    \treturn true;\n    }\n}"
  },
  {
    "path": "src/Http/Controllers/Controller.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Http\\Controllers;\n\nuse Illuminate\\Foundation\\Bus\\DispatchesJobs;\nuse Illuminate\\Routing\\Controller as BaseController;\nuse Illuminate\\Foundation\\Validation\\ValidatesRequests;\n\nabstract class Controller extends BaseController\n{\n    use DispatchesJobs, ValidatesRequests;\n}"
  },
  {
    "path": "src/Http/Controllers/Shop/CallbackController.php",
    "content": "<?php\nnamespace Amsgames\\LaravelShop\\Http\\Controllers\\Shop;\nuse Validator;\nuse Shop;\nuse Illuminate\\Http\\Request;\nuse Amsgames\\LaravelShop\\Http\\Controllers\\Controller;\nclass CallbackController extends Controller\n{\n    /**\n     * Process payment callback.\n     *\n     * @param Request $request   Request.\n     * \n     * @return redirect\n     */\n    protected function process(Request $request)\n    {\n        $validator = Validator::make(\n            [\n                'order_id'  => $request->get('order_id'),\n                'status'    => $request->get('status'),\n                'shoptoken' => $request->get('shoptoken'),\n            ],\n            [\n                'order_id'  => 'required|exists:' . config('shop.order_table') . ',id',\n                'status'    => 'required|in:success,fail',\n                'shoptoken' => 'required|exists:' . config('shop.transaction_table') . ',token,order_id,' . $request->get('order_id'),\n            ]\n        );\n        if ($validator->fails()) {\n            abort(404);\n        }\n        $order = call_user_func(config('shop.order') . '::find', $request->get('order_id'));\n        $transaction = $order->transactions()->where('token', $request->get('shoptoken'))->first();\n        Shop::callback($order, $transaction, $request->get('status'), $request->all());\n        $transaction->token = null;\n        $transaction->save();\n        return redirect()->route(config('shop.callback_redirect_route'), ['orderId' => $order->id]);\n    }\n}\n"
  },
  {
    "path": "src/LaravelShop.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop;\n\n/**\n * This class is the main entry point of laravel shop. Usually this the interaction\n * with this class will be done through the LaravelShop Facade\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Auth;\nuse Amsgames\\LaravelShop\\Gateways;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Facades\\Session;\nuse Illuminate\\Support\\Facades\\Log;\nuse Amsgames\\LaravelShop\\Exceptions\\CheckoutException;\nuse Amsgames\\LaravelShop\\Exceptions\\GatewayException;\nuse Amsgames\\LaravelShop\\Exceptions\\ShopException;\nuse Amsgames\\LaravelShop\\Events\\CartCheckout;\nuse Amsgames\\LaravelShop\\Events\\OrderCompleted;\nuse Amsgames\\LaravelShop\\Events\\OrderPlaced;\nuse Amsgames\\LaravelShop\\Events\\OrderStatusChanged;\n\nclass LaravelShop\n{\n    /**\n     * Forces quantity to reset when adding items to cart.\n     * @var bool\n     */\n    const QUANTITY_RESET                = true;\n\n    /**\n     * Gateway in use.\n     * @var string\n     */\n    protected static $gatewayKey        = null;\n\n    /**\n     * Gateway instance.\n     * @var object\n     */\n    protected static $gateway           = null;\n\n    /**\n     * Gatway in use.\n     * @var string\n     */\n    protected static $exception         = null;\n\n    /**\n     * Laravel application\n     *\n     * @var \\Illuminate\\Foundation\\Application\n     */\n    private $errorMessage;\n\n    /**\n     * Laravel application\n     *\n     * @var \\Illuminate\\Foundation\\Application\n     */\n    public $app;\n\n    /**\n     * Create a new confide instance.\n     *\n     * @param \\Illuminate\\Foundation\\Application $app\n     *\n     * @return void\n     */\n    public function __construct($app)\n    {\n        $this->app              = $app;\n        static::$gatewayKey     = $this->getGateway();\n        static::$exception      = null;\n        static::$gateway        = static::instanceGateway();\n    }\n\n    /**\n     * Get the currently authenticated user or null.\n     *\n     * @return Illuminate\\Auth\\UserInterface|null\n     */\n    public function user()\n    {\n        return $this->app->auth->user();\n    }\n\n    /**\n     * Checkout current user's cart.\n     */\n    public static function setGateway($gatewayKey)\n    {\n        if (!array_key_exists($gatewayKey, Config::get('shop.gateways')))\n            throw new ShopException('Invalid gateway.');\n        static::$gatewayKey = $gatewayKey;\n        static::$gateway    = static::instanceGateway();\n        Session::push('shop.gateway', $gatewayKey);\n    }\n\n    /**\n     * Checkout current user's cart.\n     */\n    public static function getGateway()\n    {\n        $gateways = Session::get('shop.gateway');\n        return $gateways && count($gateways) > 0\n            ? $gateways[count($gateways) - 1]\n            : null;\n    }\n\n    /**\n     * Checkout current user's cart.\n     *\n     * @param object $cart For specific cart.\n     *\n     * @return bool\n     */\n    public static function checkout($cart = null)\n    {\n        $success = true;\n        try {\n            if (empty(static::$gatewayKey)) {\n                throw new ShopException('Payment gateway not selected.');\n            }\n            if (empty($cart)) $cart = Auth::user()->cart;\n            static::$gateway->onCheckout($cart);\n        } catch (ShopException $e) {\n            static::setException($e);\n            $success = false;\n        } catch (CheckoutException $e) {\n            static::$exception = $e;\n            $success = false;\n        } catch (GatewayException $e) {\n            static::$exception = $e;\n            $success = false;\n        }\n        if ($cart)\n            \\event(new CartCheckout($cart->id, $success));\n        return $success;\n    }\n\n    /**\n     * Returns placed order.\n     *\n     * @param object $cart For specific cart.\n     *\n     * @return object\n     */\n    public static function placeOrder($cart = null)\n    {\n        try {\n            if (empty(static::$gatewayKey))\n                throw new ShopException('Payment gateway not selected.');\n            if (empty($cart)) $cart = Auth::user()->cart;\n            $order = $cart->placeOrder();\n            $statusCode = $order->statusCode;\n            \\event(new OrderPlaced($order->id));\n            static::$gateway->setCallbacks($order);\n            if (static::$gateway->onCharge($order)) {\n                $order->statusCode = static::$gateway->getTransactionStatusCode();\n                $order->save();\n                // Create transaction\n                $order->placeTransaction(\n                    static::$gatewayKey,\n                    static::$gateway->getTransactionId(),\n                    static::$gateway->getTransactionDetail(),\n                    static::$gateway->getTransactionToken()\n                );\n                // Fire event\n                if ($order->isCompleted)\n                    \\event(new OrderCompleted($order->id));\n            } else {\n                $order->statusCode = 'failed';\n                $order->save();\n            }\n        } catch (ShopException $e) {\n            static::setException($e);\n            if (isset($order)) {\n                $order->statusCode = 'failed';\n                $order->save();\n                // Create failed transaction\n                $order->placeTransaction(\n                    static::$gatewayKey,\n                    uniqid(),\n                    static::$exception->getMessage(),\n                    $order->statusCode\n                );\n            }\n        } catch (GatewayException $e) {\n            static::$exception = $e;\n            if (isset($order)) {\n                $order->statusCode = 'failed';\n                $order->save();\n                // Create failed transaction\n                $order->placeTransaction(\n                    static::$gatewayKey,\n                    uniqid(),\n                    static::$exception->getMessage(),\n                    $order->statusCode\n                );\n            }\n        }\n        if ($order) {\n            static::checkStatusChange($order, $statusCode);\n            return $order;\n        } else {\n            return;\n        }\n    }\n\n    /**\n     * Handles gateway callbacks.\n     *\n     * @param string $order  Order.\n     * @param string $status Callback status\n     */\n    public static function callback($order, $transaction, $status, $data = null)\n    {\n        $statusCode = $order->statusCode;\n        try {\n            if (in_array($status, ['success', 'fail'])) {\n                static::$gatewayKey = $transaction->gateway;\n                static::$gateway = static::instanceGateway();\n                if ($status == 'success') {\n                    static::$gateway->onCallbackSuccess($order, $data);\n                    $order->statusCode = static::$gateway->getTransactionStatusCode();\n                    // Create transaction\n                    $order->placeTransaction(\n                        static::$gatewayKey,\n                        static::$gateway->getTransactionId(),\n                        static::$gateway->getTransactionDetail(),\n                        static::$gateway->getTransactionToken()\n                    );\n                    // Fire event\n                    if ($order->isCompleted)\n                        \\event(new OrderCompleted($order->id));\n                } else if ($status == 'fail') {\n                    static::$gateway->onCallbackFail($order, $data);\n                    $order->statusCode = 'failed';\n                }\n                $order->save();\n            }\n        } catch (ShopException $e) {\n            static::setException($e);\n            $order->statusCode = 'failed';\n            $order->save();\n        } catch (GatewayException $e) {\n            static::setException($e);\n            $order->statusCode = 'failed';\n            $order->save();\n        }\n        static::checkStatusChange($order, $statusCode);\n    } \n\n    /**\n     * Formats any value to price format set in config.\n     *\n     * @param mixed $value Value to format.\n     *\n     * @return string\n     */\n    public static function format($value)\n    {\n        return preg_replace(\n            [\n                '/:symbol/',\n                '/:price/',\n                '/:currency/'\n            ],\n            [\n                Config::get('shop.currency_symbol'),\n                $value,\n                Config::get('shop.currency')\n            ],\n            Config::get('shop.display_price_format')\n        );\n    }\n\n    /**\n     * Retuns gateway.\n     *\n     * @return object\n     */\n    public static function gateway()\n    {   \n        return static::$gateway;\n    }\n\n    /**\n     * Retuns exception.\n     *\n     * @return Exception\n     */\n    public static function exception()\n    {\n        return static::$exception;\n    }\n\n    /**\n     * Saves exception in class.\n     *\n     * @param mixed $e Exception\n     */\n    protected static function setException($e)\n    {\n        Log::error($e);\n        static::$exception = $e;\n    }\n\n    /**\n     * Retunes gateway object.\n     * @return object \n     */\n    protected static function instanceGateway()\n    {\n        if (empty(static::$gatewayKey)) return;\n        $className = '\\\\' . Config::get('shop.gateways')[static::$gatewayKey];\n        return new $className(static::$gatewayKey);\n    }\n\n    /**\n     * Check on order status differences and fires event.\n     * @param object $order Order.\n     * @param string $prevStatusCode Previous status code.\n     * @return void \n     */\n    protected static function checkStatusChange($order, $prevStatusCode)\n    {\n        if (!empty($prevStatusCode) && $order->statusCode != $prevStatusCode)\n            \\event(new OrderStatusChanged($order->id, $order->statusCode, $prevStatusCode));\n    }\n}\n"
  },
  {
    "path": "src/LaravelShopFacade.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Illuminate\\Support\\Facades\\Facade;\n\nclass LaravelShopFacade extends Facade\n{\n    /**\n     * Get the registered name of the component.\n     *\n     * @return string\n     */\n    protected static function getFacadeAccessor()\n    {\n        return 'shop';\n    }\n}\n"
  },
  {
    "path": "src/LaravelShopProvider.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop;\n\n/**\n * Service provider for laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Illuminate\\Routing\\Router;\nuse Illuminate\\Foundation\\Support\\Providers\\RouteServiceProvider as ServiceProvider;\n\nclass LaravelShopProvider extends ServiceProvider\n{\n\n    /**\n     * Indicates if loading of the provider is deferred.\n     *\n     * @var bool\n     */\n    protected $defer = false;\n\n    /**\n     * Bootstrap the application events.\n     *\n     * @return void\n     */\n    public function boot(Router $router)\n    {\n        parent::boot($router);\n\n        // Publish config files\n        $this->publishes([\n            __DIR__ . '/Config/config.php' => config_path('shop.php'),\n        ]);\n\n        // Register commands\n        $this->commands('command.laravel-shop.migration');\n\n    }\n\n    /**\n     * Register the service provider.\n     *\n     * @return void\n     */\n    public function register()\n    {\n        $this->registerShop();\n\n        $this->registerCommands();\n\n        $this->mergeConfig();\n    }\n\n    /**\n     * Register the application bindings.\n     *\n     * @return void\n     */\n    private function registerShop()\n    {\n        $this->app->singleton('shop', function ($app) {\n            return new LaravelShop($app);\n        });\n    }\n\n    /**\n     * Merges user's and entrust's configs.\n     *\n     * @return void\n     */\n    private function mergeConfig()\n    {\n        $this->mergeConfigFrom(\n            __DIR__ . '/Config/config.php', 'shop'\n        );\n    }\n\n    /**\n     * Register the artisan commands.\n     *\n     * @return void\n     */\n    private function registerCommands()\n    {\n        $this->app->singleton('command.laravel-shop.migration', function ($app) {\n            return new MigrationCommand();\n        });\n    }\n\n    /**\n     * Get the services provided.\n     *\n     * @return array\n     */\n    public function provides()\n    {\n        return [\n            'shop', 'command.laravel-shop.migration'\n        ];\n    }\n\n    /**\n     * Maps router.\n     * Add package special controllers.\n     *\n     * @param Router $route Router.\n     */\n    public function map(Router $router)\n    {\n        $router->group(['namespace' => 'Amsgames\\LaravelShop\\Http\\Controllers'], function($router) {\n\n            $router->group(['prefix' => 'shop'], function ($router) {\n\n                $router->get('callback/payment/{status}/{id}/{shoptoken}', ['as' => 'shop.callback', 'uses' => 'Shop\\CallbackController@process']);\n\n                $router->post('callback/payment/{status}/{id}/{shoptoken}', ['as' => 'shop.callback', 'uses' => 'Shop\\CallbackController@process']);\n\n            });\n\n        });\n    }\n\t\n}\n"
  },
  {
    "path": "src/Models/ShopCartModel.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Models;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Amsgames\\LaravelShop\\Contracts\\ShopCartInterface;\nuse Amsgames\\LaravelShop\\Traits\\ShopCartTrait;\nuse Amsgames\\LaravelShop\\Traits\\ShopCalculationsTrait;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Facades\\Config;\n\nclass ShopCartModel extends Model implements ShopCartInterface\n{\n\n    use ShopCartTrait, ShopCalculationsTrait;\n\n    /**\n     * The database table used by the model.\n     *\n     * @var string\n     */\n    protected $table;\n\n    /**\n     * Fillable attributes for mass assignment.\n     *\n     * @var array\n     */\n    protected $fillable = ['user_id'];\n\n    /**\n     * Creates a new instance of the model.\n     *\n     * @param array $attributes\n     */\n    public function __construct(array $attributes = [])\n    {\n        parent::__construct($attributes);\n        $this->table = Config::get('shop.cart_table');\n    }\n\n}"
  },
  {
    "path": "src/Models/ShopCouponModel.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Models;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Amsgames\\LaravelShop\\Contracts\\ShopCouponInterface;\nuse Amsgames\\LaravelShop\\Traits\\ShopCouponTrait;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Facades\\Config;\n\nclass ShopCouponModel extends Model implements ShopCouponInterface\n{\n\n    use ShopCouponTrait;\n\n    /**\n     * The database table used by the model.\n     *\n     * @var string\n     */\n    protected $table;\n\n    /**\n     * Fillable attributes for mass assignment.\n     *\n     * @var array\n     */\n    protected $fillable = ['code', 'sku', 'value', 'discount', 'name', 'description', 'expires_at'];\n\n    /**\n     * Creates a new instance of the model.\n     *\n     * @param array $attributes\n     */\n    public function __construct(array $attributes = [])\n    {\n        parent::__construct($attributes);\n        $this->table = Config::get('shop.coupon_table');\n    }\n\n}"
  },
  {
    "path": "src/Models/ShopItemModel.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Models;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Amsgames\\LaravelShop\\Contracts\\ShopItemInterface;\nuse Amsgames\\LaravelShop\\Traits\\ShopItemTrait;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Facades\\Config;\n\nclass ShopItemModel extends Model implements ShopItemInterface\n{\n\n    use ShopItemTrait;\n\n    /**\n     * The database table used by the model.\n     *\n     * @var string\n     */\n    protected $table;\n\n    /**\n     * Name of the route to generate the item url.\n     *\n     * @var string\n     */\n    protected $itemRouteName = '';\n\n    /**\n     * Name of the attributes to be included in the route params.\n     *\n     * @var string\n     */\n    protected $itemRouteParams = [];\n\n    /**\n     * Name of the attributes to be included in the route params.\n     *\n     * @var string\n     */\n    protected $fillable = ['user_id', 'cart_id', 'shop_id', 'sku', 'price', 'tax', 'shipping', 'currency', 'quantity', 'class', 'reference_id'];\n\n    /**\n     * Creates a new instance of the model.\n     *\n     * @param array $attributes\n     */\n    public function __construct(array $attributes = [])\n    {\n        parent::__construct($attributes);\n        $this->table = Config::get('shop.item_table');\n    }\n\n    /**\n     * Many-to-Many relations with the user model.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function user()\n    {\n        return $this->belongsTo(config('auth.providers.users.model'), 'user_id');\n    }\n\n    /**\n     * One-to-One relations with the cart model.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function cart()\n    {\n        return $this->belongsTo(Config::get('shop.cart'), 'cart_id');\n    }\n\n    /**\n     * One-to-One relations with the order model.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function order()\n    {\n        return $this->belongsTo(Config::get('shop.order'), 'order_id');\n    }\n\n}\n"
  },
  {
    "path": "src/Models/ShopOrderModel.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Models;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Amsgames\\LaravelShop\\Contracts\\ShopOrderInterface;\nuse Amsgames\\LaravelShop\\Traits\\ShopOrderTrait;\nuse Amsgames\\LaravelShop\\Traits\\ShopCalculationsTrait;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Facades\\Config;\n\nclass ShopOrderModel extends Model implements ShopOrderInterface\n{\n\n    use ShopOrderTrait, ShopCalculationsTrait;\n\n    /**\n     * The database table used by the model.\n     *\n     * @var string\n     */\n    protected $table;\n\n    /**\n     * Fillable attributes for mass assignment.\n     *\n     * @var array\n     */\n    protected $fillable = ['user_id', 'statusCode'];\n\n    /**\n     * Creates a new instance of the model.\n     *\n     * @param array $attributes\n     */\n    public function __construct(array $attributes = [])\n    {\n        parent::__construct($attributes);\n        $this->table = Config::get('shop.order_table');\n    }\n\n}"
  },
  {
    "path": "src/Models/ShopTransactionModel.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Models;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Amsgames\\LaravelShop\\Contracts\\ShopTransactionInterface;\nuse Amsgames\\LaravelShop\\Traits\\ShopTransactionTrait;\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Support\\Facades\\Config;\n\nclass ShopTransactionModel extends Model implements ShopTransactionInterface\n{\n    use ShopTransactionTrait;\n\n    /**\n     * The database table used by the model.\n     *\n     * @var string\n     */\n    protected $table;\n\n    /**\n     * Fillable attributes for mass assignment.\n     *\n     * @var array\n     */\n    protected $fillable = ['order_id', 'gateway', 'transaction_id', 'detail', 'token'];\n\n    /**\n     * Creates a new instance of the model.\n     *\n     * @param array $attributes\n     */\n    public function __construct(array $attributes = [])\n    {\n        parent::__construct($attributes);\n        $this->table = Config::get('shop.transaction_table');\n    }\n}"
  },
  {
    "path": "src/Traits/ShopCalculationsTrait.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Traits;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Shop;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Facades\\DB;\nuse Illuminate\\Support\\Facades\\Cache;\nuse InvalidArgumentException;\n\ntrait ShopCalculationsTrait\n{\n    /**\n     * Property used to stored calculations.\n     * @var array\n     */\n    private $shopCalculations = null;\n\n    /**\n     * Returns total amount of items in cart.\n     *\n     * @return int\n     */\n    public function getCountAttribute()\n    {\n        if (empty($this->shopCalculations)) $this->runCalculations();\n        return round($this->shopCalculations->itemCount, 2);\n    }\n\n    /**\n     * Returns total price of all the items in cart.\n     *\n     * @return float\n     */\n    public function getTotalPriceAttribute()\n    {\n        if (empty($this->shopCalculations)) $this->runCalculations();\n        return round($this->shopCalculations->totalPrice, 2);\n    }\n\n    /**\n     * Returns total tax of all the items in cart.\n     *\n     * @return float\n     */\n    public function getTotalTaxAttribute()\n    {\n        if (empty($this->shopCalculations)) $this->runCalculations();\n        return round($this->shopCalculations->totalTax + ($this->totalPrice * Config::get('shop.tax')), 2);\n    }\n\n    /**\n     * Returns total tax of all the items in cart.\n     *\n     * @return float\n     */\n    public function getTotalShippingAttribute()\n    {\n        if (empty($this->shopCalculations)) $this->runCalculations();\n        return round($this->shopCalculations->totalShipping, 2);\n    }\n\n    /**\n     * Returns total discount amount based on all coupons applied.\n     *\n     * @return float\n     */\n    public function getTotalDiscountAttribute() { /* TODO */ }\n\n    /**\n     * Returns total amount to be charged base on total price, tax and discount.\n     *\n     * @return float\n     */\n    public function getTotalAttribute()\n    {\n        if (empty($this->shopCalculations)) $this->runCalculations();\n        return $this->totalPrice + $this->totalTax + $this->totalShipping;\n    }\n\n    /**\n     * Returns formatted total price of all the items in cart.\n     *\n     * @return string\n     */\n    public function getDisplayTotalPriceAttribute()\n    {\n        return Shop::format($this->totalPrice);\n    }\n\n    /**\n     * Returns formatted total tax of all the items in cart.\n     *\n     * @return string\n     */\n    public function getDisplayTotalTaxAttribute()\n    {\n        return Shop::format($this->totalTax);\n    }\n\n    /**\n     * Returns formatted total tax of all the items in cart.\n     *\n     * @return string\n     */\n    public function getDisplayTotalShippingAttribute()\n    {\n        return Shop::format($this->totalShipping);\n    }\n\n    /**\n     * Returns formatted total discount amount based on all coupons applied.\n     *\n     * @return string\n     */\n    public function getDisplayTotalDiscountAttribute() { /* TODO */ }\n\n    /**\n     * Returns formatted total amount to be charged base on total price, tax and discount.\n     *\n     * @return string\n     */\n    public function getDisplayTotalAttribute()\n    {\n        return Shop::format($this->total);\n    }\n\n    /**\n     * Returns cache key used to store calculations.\n     *\n     * @return string.\n     */\n    public function getCalculationsCacheKeyAttribute()\n    {\n        return 'shop_' . $this->table . '_' . $this->attributes['id'] . '_calculations';\n    }\n\n    /**\n     * Runs calculations.\n     */\n    private function runCalculations()\n    {\n        if (!empty($this->shopCalculations)) return $this->shopCalculations;\n        $cacheKey = $this->calculationsCacheKey;\n        if (Config::get('shop.cache_calculations')\n            && Cache::has($cacheKey)\n        ) {\n            $this->shopCalculations = Cache::get($cacheKey);\n            return $this->shopCalculations;\n        }\n        $this->shopCalculations = DB::table($this->table)\n            ->select([\n                DB::raw('sum(' . Config::get('shop.item_table') . '.quantity) as itemCount'),\n                DB::raw('sum(' . Config::get('shop.item_table') . '.price * ' . Config::get('shop.item_table') . '.quantity) as totalPrice'),\n                DB::raw('sum(' . Config::get('shop.item_table') . '.tax * ' . Config::get('shop.item_table') . '.quantity) as totalTax'),\n                DB::raw('sum(' . Config::get('shop.item_table') . '.shipping * ' . Config::get('shop.item_table') . '.quantity) as totalShipping')\n            ])\n            ->join(\n                Config::get('shop.item_table'),\n                Config::get('shop.item_table') . '.' . ($this->table == Config::get('shop.order_table') ? 'order_id' : $this->table . '_id'),\n                '=',\n                $this->table . '.id'\n            )\n            ->where($this->table . '.id', $this->attributes['id'])\n            ->first();\n        if (Config::get('shop.cache_calculations')) {\n            Cache::put(\n                $cacheKey,\n                $this->shopCalculations,\n                Config::get('shop.cache_calculations_minutes')\n            );\n        }\n        return $this->shopCalculations;\n    }\n\n    /**\n     * Resets cart calculations.\n     */\n    private function resetCalculations ()\n    {\n        $this->shopCalculations = null;\n        if (Config::get('shop.cache_calculations')) {\n            Cache::forget($this->calculationsCacheKey);\n        }\n    }\n\n}"
  },
  {
    "path": "src/Traits/ShopCartTrait.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Traits;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Shop;\nuse Illuminate\\Support\\Facades\\Config;\nuse Illuminate\\Support\\Facades\\Auth;\nuse Illuminate\\Support\\Facades\\DB;\nuse InvalidArgumentException;\n\ntrait ShopCartTrait\n{\n    /**\n     * Property used to stored calculations.\n     * @var array\n     */\n    private $cartCalculations = null;\n\n    /**\n     * Boot the user model\n     * Attach event listener to remove the relationship records when trying to delete\n     * Will NOT delete any records if the user model uses soft deletes.\n     *\n     * @return void|bool\n     */\n    public static function boot()\n    {\n        parent::boot();\n\n        static::deleting(function($user) {\n            if (!method_exists(Config::get('auth.providers.users.model'), 'bootSoftDeletingTrait')) {\n                $user->items()->sync([]);\n            }\n\n            return true;\n        });\n    }\n\n    /**\n     * One-to-One relations with the user model.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function user()\n    {\n        return $this->belongsTo(config('auth.providers.users.model'), 'user_id');\n    }\n\n    /**\n     * One-to-Many relations with Item.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function items()\n    {\n        return $this->hasMany(Config::get('shop.item'), 'cart_id');\n    }\n\n    /**\n     * Adds item to cart.\n     *\n     * @param mixed $item     Item to add, can be an Store Item, a Model with ShopItemTrait or an array.\n     * @param int   $quantity Item quantity in cart.\n     */\n    public function add($item, $quantity = 1, $quantityReset = false)\n    {\n        if (!is_array($item) && !$item->isShoppable) return;\n        // Get item\n        $cartItem = $this->getItem(is_array($item) ? $item['sku'] : $item->sku);\n        // Add new or sum quantity\n        if (empty($cartItem)) {\n            $reflection = null;\n            if (is_object($item)) {\n                $reflection = new \\ReflectionClass($item);\n            }\n            $cartItem = call_user_func( Config::get('shop.item') . '::create', [\n                'user_id'       => $this->user->shopId,\n                'cart_id'       => $this->attributes['id'],\n                'sku'           => is_array($item) ? $item['sku'] : $item->sku,\n                'price'         => is_array($item) ? $item['price'] : $item->price,\n                'tax'           => is_array($item) \n                                    ? (array_key_exists('tax', $item)\n                                        ?   $item['tax']\n                                        :   0\n                                    ) \n                                    : (isset($item->tax) && !empty($item->tax)\n                                        ?   $item->tax\n                                        :   0\n                                    ),\n                'shipping'      => is_array($item) \n                                    ? (array_key_exists('shipping', $item)\n                                        ?   $item['shipping']\n                                        :   0\n                                    ) \n                                    : (isset($item->shipping) && !empty($item->shipping)\n                                        ?   $item->shipping\n                                        :   0\n                                    ),\n                'currency'      => Config::get('shop.currency'),\n                'quantity'      => $quantity,\n                'class'         => is_array($item) ? null : $reflection->getName(),\n                'reference_id'  => is_array($item) ? null : $item->shopId,\n            ]);\n        } else {\n            $cartItem->quantity = $quantityReset \n                ? $quantity \n                : $cartItem->quantity + $quantity;\n            $cartItem->save();\n        }\n        $this->resetCalculations();\n        return $this;\n    }\n\n    /**\n     * Removes an item from the cart or decreases its quantity.\n     * Returns flag indicating if removal was successful.\n     *\n     * @param mixed $item     Item to remove, can be an Store Item, a Model with ShopItemTrait or an array.\n     * @param int   $quantity Item quantity to decrease. 0 if wanted item to be removed completly.\n     *\n     * @return bool\n     */\n    public function remove($item, $quantity = 0)\n    {\n        // Get item\n        $cartItem = $this->getItem(is_array($item) ? $item['sku'] : $item->sku);\n        // Remove or decrease quantity\n        if (!empty($cartItem)) {\n            if (!empty($quantity)) {\n                $cartItem->quantity -= $quantity;\n                $cartItem->save();\n                if ($cartItem->quantity > 0) return true;\n            }\n            $cartItem->delete();\n        }\n        $this->resetCalculations();\n        return $this;\n    }\n\n    /**\n     * Checks if the user has a role by its name.\n     *\n     * @param string|array $name       Role name or array of role names.\n     * @param bool         $requireAll All roles in the array are required.\n     *\n     * @return bool\n     */\n    public function hasItem($sku, $requireAll = false)\n    {\n        if (is_array($sku)) {\n            foreach ($sku as $skuSingle) {\n                $hasItem = $this->hasItem($skuSingle);\n\n                if ($hasItem && !$requireAll) {\n                    return true;\n                } elseif (!$hasItem && $requireAll) {\n                    return false;\n                }\n            }\n\n            // If we've made it this far and $requireAll is FALSE, then NONE of the roles were found\n            // If we've made it this far and $requireAll is TRUE, then ALL of the roles were found.\n            // Return the value of $requireAll;\n            return $requireAll;\n        } else {\n            foreach ($this->items as $item) {\n                if ($item->sku == $sku) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Scope class by a given user ID.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query  Query.\n     * @param mixed                                 $userId User ID.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function scopeWhereUser($query, $userId)\n    {\n        return $query->where('user_id', $userId);\n    }\n\n    /**\n     * Scope to current user cart.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query  Query.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function scopeWhereCurrent($query)\n    {\n        if (Auth::guest()) return $query;\n        return $query->whereUser(Auth::user()->shopId);\n    }\n\n    /**\n     * Scope to current user cart and returns class model.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query  Query.\n     *\n     * @return this\n     */\n    public function scopeCurrent($query)\n    {\n        if (Auth::guest()) return;\n        $cart = $query->whereCurrent()->first();\n        if (empty($cart)) {\n            $cart = call_user_func( Config::get('shop.cart') . '::create', [\n                'user_id' =>  Auth::user()->shopId\n            ]);\n        }\n        return $cart;\n    }\n\n    /**\n     * Scope to current user cart and returns class model.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query  Query.\n     *\n     * @return this\n     */\n    public function scopeFindByUser($query, $userId)\n    {\n        if (empty($userId)) return;\n        $cart = $query->whereUser($userId)->first();\n        if (empty($cart)) {\n            $cart = call_user_func( Config::get('shop.cart') . '::create', [\n                'user_id' =>  $userId\n            ]);\n        }\n        return $cart;\n    }\n\n    /**\n     * Transforms cart into an order.\n     * Returns created order.\n     *\n     * @param string $statusCode Order status to create order with.\n     *\n     * @return Order\n     */\n    public function placeOrder($statusCode = null)\n    {\n        if (empty($statusCode)) $statusCode = Config::get('shop.order_status_placement');\n        // Create order\n        $order = call_user_func( Config::get('shop.order') . '::create', [\n            'user_id'       => $this->user_id,\n            'statusCode'    => $statusCode\n        ]);\n        // Map cart items into order\n        for ($i = count($this->items) - 1; $i >= 0; --$i) {\n            // Attach to order\n            $this->items[$i]->order_id  = $order->id;\n            // Remove from cart\n            $this->items[$i]->cart_id   = null;\n            // Update\n            $this->items[$i]->save();\n        }\n        $this->resetCalculations();\n        return $order;\n    }\n\n    /**\n     * Whipes put cart\n     */\n    public function clear()\n    {\n        DB::table(Config::get('shop.item_table'))\n            ->where('cart_id', $this->attributes['id'])\n            ->delete();\n        $this->resetCalculations();\n        return $this;\n    }\n\n    /**\n     * Retrieves item from cart;\n     *\n     * @param string $sku SKU of item.\n     *\n     * @return mixed\n     */\n    private function getItem($sku)\n    {\n        $className  = Config::get('shop.item');\n        $item       = new $className();\n        return $item->where('sku', $sku)\n            ->where('cart_id', $this->attributes['id'])\n            ->first();\n    }\n\n}\n"
  },
  {
    "path": "src/Traits/ShopCouponTrait.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Traits;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Illuminate\\Support\\Facades\\Config;\nuse InvalidArgumentException;\n\ntrait ShopCouponTrait\n{\n\n    /**\n     * Scopes class by coupon code.\n     *\n     * @return QueryBuilder\n     */\n    public function scopeWhereCode($query, $code)\n    {\n        return $query->where('code', $code);\n    }\n\n    /**\n     * Scopes class by coupen code and returns object.\n     *\n     * @return this\n     */\n    public function scopeFindByCode($query, $code)\n    {\n        return $query->where('code', $code)->first();\n    }\n\n}"
  },
  {
    "path": "src/Traits/ShopItemTrait.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Traits;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Auth;\nuse Shop;\nuse Illuminate\\Support\\Facades\\Config;\nuse InvalidArgumentException;\n\ntrait ShopItemTrait\n{\n\n    /**\n     * Returns flag indicating if item has an object.\n     *\n     * @return bool\n     */\n    public function getHasObjectAttribute() \n    {\n        return array_key_exists('class', $this->attributes) && !empty($this->attributes['class']);\n    }\n\n    /**\n     * Returns flag indicating if the object is shoppable or not.\n     *\n     * @return bool\n     */\n    public function getIsShoppableAttribute()\n    {\n        return true;\n    }\n\n    /**\n     * Returns attached object.\n     *\n     * @return mixed\n     */\n    public function getObjectAttribute()\n    {\n        return $this->hasObject ? call_user_func($this->attributes['class'] . '::find', $this->attributes['reference_id']) : null;\n    }\n\n    /**\n     * Returns item name.\n     *\n     * @return string\n     */\n    public function getDisplayNameAttribute()\n    {\n        if ($this->hasObject) return $this->object->displayName;\n        return isset($this->itemName)\n            ? $this->attributes[$this->itemName]\n            : (array_key_exists('name', $this->attributes)\n                ? $this->attributes['name']\n                : ''\n            );\n    }\n\n    /**\n     * Returns item id.\n     *\n     * @return mixed\n     */\n    public function getShopIdAttribute()\n    {\n        return is_array($this->primaryKey) ? 0 : $this->attributes[$this->primaryKey];\n    }\n\n    /**\n     * Returns item url.\n     *\n     * @return string\n     */\n    public function getShopUrlAttribute()\n    {\n        if ($this->hasObject) return $this->object->shopUrl;\n        if (!property_exists($this, 'itemRouteName') && !property_exists($this, 'itemRouteParams')) return '#';\n        $params = [];\n        foreach (array_keys($this->attributes) as $attribute) {\n            if (in_array($attribute, $this->itemRouteParams)) $params[$attribute] = $this->attributes[$attribute];\n        }\n        return empty($this->itemRouteName) ? '#' : \\route($this->itemRouteName, $params);\n    }\n\n    /**\n     * Returns price formatted for display.\n     *\n     * @return string\n     */\n    public function getDisplayPriceAttribute()\n    {\n        return Shop::format($this->attributes['price']);\n    }\n\n    /**\n     * Scope class by a given sku.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query  Query.\n     * @param mixed                                 $sku    SKU.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function scopeWhereSKU($query, $sku)\n    {\n        return $query->where('sku', $sku);\n    }\n\n    /**\n     * Scope class by a given sku.\n     * Returns item found.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query  Query.\n     * @param mixed                                 $sku    SKU.\n     *\n     * @return this\n     */\n    public function scopeFindBySKU($query, $sku)\n    {\n        return $query->whereSKU($sku)->first();\n    }\n\n    /**\n     * Returns formatted tax for display.\n     *\n     * @return string\n     */\n    public function getDisplayTaxAttribute()\n    {\n        return Shop::format(array_key_exists('tax', $this->attributes) ? $this->attributes['tax'] : 0.00);\n    }\n\n    /**\n     * Returns formatted tax for display.\n     *\n     * @return string\n     */\n    public function getDisplayShippingAttribute()\n    {\n        return Shop::format(array_key_exists('shipping', $this->attributes) ? $this->attributes['shipping'] : 0.00);\n    }\n\n    /**\n     * Returns flag indicating if item was purchased by user.\n     *\n     * @return bool\n     */\n    public function getWasPurchasedAttribute()\n    {\n        if (Auth::guest()) return false;\n        return Auth::user()\n            ->orders()\n            ->whereSKU($this->attributes['sku'])\n            ->whereStatusIn(config('shop.order_status_purchase'))\n            ->count() > 0;\n    }\n\n}"
  },
  {
    "path": "src/Traits/ShopOrderTrait.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Traits;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Illuminate\\Support\\Facades\\Config;\nuse InvalidArgumentException;\n\ntrait ShopOrderTrait\n{\n    /**\n     * Boot the user model\n     * Attach event listener to remove the relationship records when trying to delete\n     * Will NOT delete any records if the user model uses soft deletes.\n     *\n     * @return void|bool\n     */\n    public static function boot()\n    {\n        parent::boot();\n\n        //static::deleting(function($user) {\n           // if (!method_exists(Config::get('auth.model'), 'bootSoftDeletingTrait')) {\n                //$user->items()->sync([]);\n           // }\n\n           // return true;\n        //});\n    }\n\n    /**\n     * One-to-One relations with the user model.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function user()\n    {\n        return $this->belongsTo(config('auth.providers.users.model'), 'user_id');\n    }\n\n    /**\n     * One-to-Many relations with Item.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function items()\n    {\n        return $this->hasMany(Config::get('shop.item'), 'order_id');\n    }\n\n    /**\n     * One-to-Many relations with Item.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function transactions()\n    {\n        return $this->hasMany(Config::get('shop.transaction'), 'order_id');\n    }\n\n    /**\n     * Returns flag indicating if order is lock and cant be modified by the user.\n     * An order is locked the moment it enters pending status.\n     *\n     * @return bool\n     */\n    public function getIsLockedAttribute() {\n        return in_array($this->attributes['statusCode'], Config::get('shop.order_status_lock'));\n    }\n\n    /**\n     * Scopes class by user ID and returns object.\n     * Optionally, scopes by status.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query  Query.\n     * @param mixed                                 $userId User ID.\n     *\n     * @return this\n     */\n    public function scopeWhereUser($query, $userId) {\n        return $query->where('user_id', $userId);\n    }\n\n    /**\n     * Scopes class by item sku.\n     * Optionally, scopes by status.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query  Query.\n     * @param mixed                                 $sku    Item SKU.\n     *\n     * @return this\n     */\n    public function scopeWhereSKU($query, $sku) {\n        return $query->join(\n                config('shop.item_table'), \n                config('shop.item_table') . '.order_id', \n                '=', \n                $this->table . '.id'\n            )\n            ->where(config('shop.item_table') . '.sku', $sku);\n    }\n\n    /**\n     * Scopes class by user ID and returns object.\n     * Optionally, scopes by status.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query      Query.\n     * @param string                                $statusCode Status.\n     *\n     * @return this\n     */\n    public function scopeWhereStatus($query, $statusCode) {\n        return $query = $query->where('statusCode', $statusCode);\n    }\n\n    /**\n     * Scopes class by status codes.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query       Query.\n     * @param array                                 $statusCodes Status.\n     *\n     * @return this\n     */\n    public function scopeWhereStatusIn($query, array $statusCodes) {\n        return $query = $query->whereIn('statusCode', $statusCodes);\n    }\n\n    /**\n     * Scopes class by user ID and returns object.\n     * Optionally, scopes by status.\n     *\n     * @param \\Illuminate\\Database\\Eloquent\\Builder $query      Query.\n     * @param mixed                                 $userId     User ID.\n     * @param string                                $statusCode Status.\n     *\n     * @return this\n     */\n    public function scopeFindByUser($query, $userId, $statusCode = null) {\n        if (!empty($status)) {\n            $query = $query->whereStatus($status);\n        }\n        return $query->whereUser($userId)->get();\n    }\n\n    /**\n     * Returns flag indicating if order is in the status specified.\n     *\n     * @param string $status Status code.\n     *\n     * @return bool\n     */\n    public function is($statusCode)\n    {\n        return $this->attributes['statusCode'] == $statusCode;\n    }\n\n    /**\n     * Returns flag indicating if order is completed.\n     *\n     * @return bool\n     */\n    public function getIsCompletedAttribute()\n    {\n        return $this->attributes['statusCode'] == 'completed';\n    }\n\n    /**\n     * Returns flag indicating if order has failed.\n     *\n     * @return bool\n     */\n    public function getHasFailedAttribute()\n    {\n        return $this->attributes['statusCode'] == 'failed';\n    }\n\n    /**\n     * Returns flag indicating if order is canceled.\n     *\n     * @return bool\n     */\n    public function getIsCanceledAttribute()\n    {\n        return $this->attributes['statusCode'] == 'canceled';\n    }\n\n    /**\n     * Returns flag indicating if order is in process.\n     *\n     * @return bool\n     */\n    public function getIsInProcessAttribute()\n    {\n        return $this->attributes['statusCode'] == 'in_process';\n    }\n\n    /**\n     * Returns flag indicating if order is in creation.\n     *\n     * @return bool\n     */\n    public function getIsInCreationAttribute()\n    {\n        return $this->attributes['statusCode'] == 'in_creation';\n    }\n\n    /**\n     * Returns flag indicating if order is in creation.\n     *\n     * @return bool\n     */\n    public function getIsPendingAttribute()\n    {\n        return $this->attributes['statusCode'] == 'pending';\n    }\n\n    /**\n     * Creates the order's transaction.\n     *\n     * @param string $gateway       Gateway.\n     * @param mixed  $transactionId Transaction ID.\n     * @param string $detail        Transaction detail.\n     *\n     * @return object\n     */\n    public function placeTransaction($gateway, $transactionId, $detail = null, $token = null)\n    {\n        return call_user_func(Config::get('shop.transaction') . '::create', [\n            'order_id'          => $this->attributes['id'],\n            'gateway'           => $gateway,\n            'transaction_id'    => $transactionId,\n            'detail'            => $detail,\n            'token'             => $token,\n        ]);\n    }\n\n    /**\n     * Retrieves item from order;\n     *\n     * @param string $sku SKU of item.\n     *\n     * @return mixed\n     */\n    private function getItem($sku)\n    {\n        $className  = Config::get('shop.item');\n        $item       = new $className();\n        return $item->where('sku', $sku)\n            ->where('order_id', $this->attributes['id'])\n            ->first();\n    }\n}\n"
  },
  {
    "path": "src/Traits/ShopTransactionTrait.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Traits;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Illuminate\\Support\\Facades\\Config;\nuse InvalidArgumentException;\n\ntrait ShopTransactionTrait\n{\n    /**\n     * One-to-One relations with the order model.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function order()\n    {\n        return $this->belongsTo(Config::get('shop.order_table'), 'order_id');\n    }\n\n    /**\n     * Scopes to get transactions from user.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Builder\n     */\n    public function scopeWhereUser($query, $userId)\n    {\n        return $query->join(\n                Config::get('shop.order_table'),\n                Config::get('shop.order_table') . '.id',\n                '=',\n                Config::get('shop.transaction_table') . '.order_id'\n            )\n            ->where(Config::get('shop.order_table') . '.user_id', $userId);\n    }\n}\n"
  },
  {
    "path": "src/Traits/ShopUserTrait.php",
    "content": "<?php\n\nnamespace Amsgames\\LaravelShop\\Traits;\n\n/**\n * This file is part of LaravelShop,\n * A shop solution for Laravel.\n *\n * @author Alejandro Mostajo\n * @copyright Amsgames, LLC\n * @license MIT\n * @package Amsgames\\LaravelShop\n */\n\nuse Illuminate\\Support\\Facades\\Config;\nuse InvalidArgumentException;\n\ntrait ShopUserTrait\n{\n\n    /**\n     * One-to-Many relations with cart.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function cart()\n    {\n        return $this->hasOne(Config::get('shop.cart'), 'user_id');\n    }\n\n    /**\n     * One-to-Many relations with Item.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function items()\n    {\n        return $this->hasMany(Config::get('shop.item'), 'user_id');\n    }\n\n    /**\n     * One-to-Many relations with Order.\n     *\n     * @return \\Illuminate\\Database\\Eloquent\\Relations\\BelongsToMany\n     */\n    public function orders()\n    {\n        return $this->hasMany(Config::get('shop.order'), 'user_id');\n    }\n\n    /**\n     * Returns the user ID value based on the primary key set for the table.\n     *\n     * @param mixed\n     */\n    public function getShopIdAttribute()\n    {\n        return is_array($this->primaryKey) ? 0 : $this->attributes[$this->primaryKey];\n    }\n\n}"
  },
  {
    "path": "src/views/generators/migration.blade.php",
    "content": "<?php echo '<?php' ?>\n\nuse Illuminate\\Database\\Migrations\\Migration;\nuse Illuminate\\Database\\Schema\\Blueprint;\n\nclass ShopSetupTables extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        // Create table for storing carts\n        Schema::create('{{ $cartTable }}', function (Blueprint $table) {\n            $table->bigIncrements('id');\n            $table->integer('user_id')->unsigned();\n            $table->timestamps();\n            $table->foreign('user_id')\n                ->references('{{ $userKeyName }}')\n                ->on('{{ $usersTable }}')\n                ->onUpdate('cascade')\n                ->onDelete('cascade');\n            $table->unique('user_id');\n        });\n        // Create table for storing items\n        Schema::create('{{ $itemTable }}', function (Blueprint $table) {\n            $table->bigIncrements('id');\n            $table->integer('user_id')->unsigned();\n            $table->bigInteger('cart_id')->unsigned()->nullable();\n            $table->bigInteger('order_id')->unsigned()->nullable();\n            $table->string('sku');\n            $table->decimal('price', 20, 2);\n            $table->decimal('tax', 20, 2)->default(0);\n            $table->decimal('shipping', 20, 2)->default(0);\n            $table->string('currency')->nullable();\n            $table->integer('quantity')->unsigned();\n            $table->string('class')->nullable();\n            $table->string('reference_id')->nullable();\n            $table->timestamps();\n            $table->foreign('user_id')\n                ->references('{{ $userKeyName }}')\n                ->on('{{ $usersTable }}')\n                ->onUpdate('cascade')\n                ->onDelete('cascade');\n            $table->foreign('cart_id')\n                ->references('id')\n                ->on('{{ $cartTable }}')\n                ->onUpdate('cascade')\n                ->onDelete('cascade');\n            $table->unique(['sku', 'cart_id']);\n            $table->unique(['sku', 'order_id']);\n            $table->index(['user_id', 'sku']);\n            $table->index(['user_id', 'sku', 'cart_id']);\n            $table->index(['user_id', 'sku', 'order_id']);\n            $table->index(['reference_id']);\n        });\n        // Create table for storing coupons\n        Schema::create('{{ $couponTable }}', function (Blueprint $table) {\n            $table->increments('id');\n            $table->string('code')->unique();\n            $table->string('name');\n            $table->string('description', 1024)->nullable();\n            $table->string('sku');\n            $table->decimal('value', 20, 2)->nullable();\n            $table->decimal('discount', 3, 2)->nullable();\n            $table->integer('active')->default(1);\n            $table->dateTime('expires_at')->nullable();\n            $table->timestamps();\n            $table->index(['code', 'expires_at']);\n            $table->index(['code', 'active']);\n            $table->index(['code', 'active', 'expires_at']);\n            $table->index(['sku']);\n        });\n        // Create table for storing coupons\n        Schema::create('{{ $orderStatusTable }}', function (Blueprint $table) {\n            $table->string('code', 32);\n            $table->string('name');\n            $table->string('description')->nullable();\n            $table->timestamps();\n            $table->primary('code');\n        });\n        // Create table for storing carts\n        Schema::create('{{ $orderTable }}', function (Blueprint $table) {\n            $table->bigIncrements('id');\n            $table->integer('user_id')->unsigned();\n            $table->string('statusCode', 32);\n            $table->timestamps();\n            $table->foreign('user_id')\n                ->references('{{ $userKeyName }}')\n                ->on('{{ $usersTable }}')\n                ->onUpdate('cascade')\n                ->onDelete('cascade');\n            $table->foreign('statusCode')\n                ->references('code')\n                ->on('{{ $orderStatusTable }}')\n                ->onUpdate('cascade');\n            $table->index(['user_id', 'statusCode']);\n            $table->index(['id', 'user_id', 'statusCode']);\n        });\n        // Create table for storing transactions\n        Schema::create('{{ $transactionTable }}', function (Blueprint $table) {\n            $table->bigIncrements('id');\n            $table->bigInteger('order_id')->unsigned();\n            $table->string('gateway', 64);\n            $table->string('transaction_id', 64);\n            $table->string('detail', 1024)->nullable();\n            $table->string('token')->nullable();\n            $table->timestamps();\n            $table->foreign('order_id')\n                ->references('id')\n                ->on('{{ $orderTable }}')\n                ->onUpdate('cascade')\n                ->onDelete('cascade');\n            $table->index(['order_id']);\n            $table->index(['gateway', 'transaction_id']);\n            $table->index(['order_id', 'token']);\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::drop('{{ $transactionTable }}');\n        Schema::drop('{{ $orderTable }}');\n        Schema::drop('{{ $orderStatusTable }}');\n        Schema::drop('{{ $couponTable }}');\n        Schema::drop('{{ $itemTable }}');\n        Schema::drop('{{ $cartTable }}');\n    }\n}"
  },
  {
    "path": "src/views/generators/seeder.blade.php",
    "content": "<?php echo '<?php' ?>\n\nuse Illuminate\\Database\\Seeder;\nuse Illuminate\\Database\\Eloquent\\Model;\n\n/**\n * Seeds database with shop data.\n */\nclass LaravelShopSeeder extends Seeder\n{\n\n  /**\n   * Run the database seeds.\n   *\n   * @return void\n   */\n  public function run()\n  {\n\n    DB::table('{{ $orderStatusTable }}')->delete();\n\n    DB::table('{{ $orderStatusTable }}')->insert([\n\t\t    [\n\t\t    \t\t'code' \t\t\t\t=> 'in_creation',\n\t\t    \t\t'name' \t\t\t\t=> 'In creation',\n\t\t    \t\t'description' => 'Order being created.',\n\t\t    ],\n\t\t    [\n\t\t    \t\t'code' \t\t\t\t=> 'pending',\n\t\t    \t\t'name' \t\t\t\t=> 'Pending',\n\t\t    \t\t'description' => 'Created / placed order pending payment or similar.',\n\t\t    ],\n\t\t    [\n\t\t    \t\t'code' \t\t\t\t=> 'in_process',\n\t\t    \t\t'name' \t\t\t\t=> 'In process',\n\t\t    \t\t'description' => 'Completed order in process of shipping or revision.',\n\t\t    ],\n\t\t    [\n\t\t    \t\t'code' \t\t\t\t=> 'completed',\n\t\t    \t\t'name' \t\t\t\t=> 'Completed',\n\t\t    \t\t'description' => 'Completed order. Payment and other processes have been made.',\n\t\t    ],\n\t\t    [\n\t\t    \t\t'code' \t\t\t\t=> 'failed',\n\t\t    \t\t'name' \t\t\t\t=> 'Failed',\n\t\t    \t\t'description' => 'Failed order. Payment or other process failed.',\n\t\t    ],\n\t\t    [\n\t\t    \t\t'code' \t\t\t\t=> 'canceled',\n\t\t    \t\t'name' \t\t\t\t=> 'Canceled',\n\t\t    \t\t'description' => 'Canceled order.',\n\t\t    ],\n\t\t]);\n\n  }\n}"
  },
  {
    "path": "tests/.gitkeep",
    "content": ""
  },
  {
    "path": "tests/README.md",
    "content": "# Test Case Configuration\n\nIn order to run test cases you must setup your laravel package development environment and create the TestProduct model.\n\n## Create testing environment\n\nThere are multiple solutions to test this package. \n\nOur testing environment uses a new installation of **Laravel** and [studio](https://github.com/franzliedke/studio).\n\nAfter studio is install in composer and created as dependency of the project. Laravel's `composer.json` autoload section must configured to map the paths to package's `src` and `commands` folder:\n\n```json\n\"autoload\": {\n    \"classmap\": [\n        \"database\",\n        \"Amsgames/laravel-shop/src/commands\"\n    ],\n    \"psr-4\": {\n        \"App\\\\\": \"app/\",\n        \"Amsgames\\\\LaravelShop\\\\\": \"Amsgames/laravel-shop/src\"\n    }\n},\n```\n\nThe `tests` directory must be added to the project's `phpunit.xml` file:\n```xml\n<testsuites>\n    <testsuite name=\"Application Test Suite\">\n        <directory>./tests/</directory>\n        <directory>./amsgames/laravel-shop/tests/</directory>\n    </testsuite>\n</testsuites>\n```\n\nThen be sure to setup and configure the package in the laravel's project as stated in the package's readme file.\n\n## Gateways\n\nAdd the following test gateways the array in `shop.php` config file:\n\n```php\n'gateways' => [\n    'testFail'          =>  Amsgames\\LaravelShop\\Gateways\\GatewayFail::class,\n    'testPass'          =>  Amsgames\\LaravelShop\\Gateways\\GatewayPass::class,\n    'testCallback'      =>  Amsgames\\LaravelShop\\Gateways\\GatewayCallback::class,\n],\n```\n\n## Test Product\n\nCreate the TestProduct model and database table used in the test cases:\n\n```bash\nphp artisan make:model TestProduct --migration\n```\n\nThis will create a model file `app\\TestProduct.php` and a new migration in `database\\migrations` folder.\n\nModify the migration to look like:\n\n```php\n<?php\n\nuse Illuminate\\Database\\Schema\\Blueprint;\nuse Illuminate\\Database\\Migrations\\Migration;\n\nclass CreateTestProductsTable extends Migration\n{\n    /**\n     * Run the migrations.\n     *\n     * @return void\n     */\n    public function up()\n    {\n        Schema::create('test_products', function (Blueprint $table) {\n            $table->increments('id');\n            $table->string('sku');\n            $table->string('name');\n            $table->decimal('price', 20, 2)->nullable();\n            $table->string('description', 1024)->nullable();\n            $table->timestamps();\n        });\n    }\n\n    /**\n     * Reverse the migrations.\n     *\n     * @return void\n     */\n    public function down()\n    {\n        Schema::drop('test_products');\n    }\n}\n```\n\nAnd the model file to look like:\n\n```php\n<?php\n\nnamespace App;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Amsgames\\LaravelShop\\Traits\\ShopItemTrait;\n\nclass TestProduct extends Model\n{\n    use ShopItemTrait;\n\n    /**\n     * The database table used by the model.\n     *\n     * @var string\n     */\n    protected $table = 'test_products';\n\n    /**\n     * The attributes that are mass assignable.\n     *\n     * @var array\n     */\n    protected $fillable = ['name', 'sku', 'description', 'price'];\n\n    /**\n    * Name of the route to generate the item url.\n    *\n    * @var string\n    */\n    protected $itemRouteName = 'product';\n\n    /**\n    * Name of the attributes to be included in the route params.\n    *\n    * @var string\n    */\n    protected $itemRouteParams = ['sku'];\n\t\t\n}\n```\n\nAdditionally add the following route in `app\\Http\\routes.php`:\n\n```php\nRoute::get('/product/{sku}', ['as' => 'product', function ($sku) {\n    return view('product', ['product' => App\\TestProduct::findBySKU($sku)]);\n}]);\n```\n\nThen add the following view, called `product.blade.php`, in `resources\\views\\` folder:\n\n```php\n{{ $product->id }}\n```"
  },
  {
    "path": "tests/ShopTest.php",
    "content": "<?php\n\nuse App;\nuse Log;\nuse Shop;\nuse Amsgames\\LaravelShop;\nuse Illuminate\\Foundation\\Testing\\WithoutMiddleware;\nuse Illuminate\\Foundation\\Testing\\DatabaseMigrations;\nuse Illuminate\\Foundation\\Testing\\DatabaseTransactions;\n\nclass ShopTest extends TestCase\n{\n\n\t/**\n\t * Tests shop class static methods.\n\t */\n\tpublic function testStaticMethods()\n\t{\n\t    $this->assertEquals(Shop::format(1.99), '$1.99');\n\t}\n\n\t/**\n\t * Tests shop class constants\n\t */\n\tpublic function testConstants()\n\t{\n\t    $this->assertTrue(Amsgames\\LaravelShop\\LaravelShop::QUANTITY_RESET);\n\t}\n\n}"
  },
  {
    "path": "tests/cart/CartTest.php",
    "content": "<?php\n\nuse App;\nuse Auth;\nuse Hash;\nuse Log;\nuse Shop;\nuse Illuminate\\Foundation\\Testing\\WithoutMiddleware;\nuse Illuminate\\Foundation\\Testing\\DatabaseMigrations;\nuse Illuminate\\Foundation\\Testing\\DatabaseTransactions;\n\nclass CartTest extends TestCase\n{\n\n\t/**\n\t * User set for tests.\n\t */\n  \tprotected $user;\n\n\t/**\n\t * Setups test data.\n\t */\n\tpublic function setUp()\n\t{\n\t\tparent::setUp();\n\n\t\t$this->user = factory('App\\User')->create(['password' => Hash::make('laravel-shop')]);\n\n\t\tAuth::attempt(['email' => $this->user->email, 'password' => 'laravel-shop']);\n\t}\n\n\t/**\n\t * Tests if cart is being created correctly.\n\t */\n\tpublic function testCreationBasedOnUser()\n\t{\n\t\t$user = factory('App\\User')->create();\n\n\t\t$cart = App\\Cart::findByUser($user->id);\n\n\t\t$this->assertNotEmpty($cart);\n\n\t\t$user->delete();\n\t}\n\n\t/**\n\t * Tests if cart is being created correctly.\n\t */\n\tpublic function testMultipleCurrentCalls()\n\t{\n\t\t$cart = App\\Cart::current();\n\n\t\t$this->assertNotEmpty($cart);\n\n\t\t$cart = App\\Cart::findByUser($this->user->id);\n\n\t\t$this->assertNotEmpty($cart);\n\n\t\t$this->assertEquals($cart->user->id, $this->user->id);\n\n\t\t$cart = App\\Cart::current();\n\n\t\t$this->assertNotEmpty($cart);\n\n\t\t$this->assertEquals($cart->user->id, $this->user->id);\n\t}\n\n\t/**\n\t * Tests if cart is being created correctly.\n\t */\n\tpublic function testCreationBasedOnNull()\n\t{\n\t\t$cart = App\\Cart::findByUser(null);\n\n\t\t$this->assertNotEmpty($cart);\n\t}\n\n\t/**\n\t * Tests if cart is being created correctly.\n\t */\n\tpublic function testCreationBasedOnAuthUser()\n\t{\n\t\t$cart = App\\Cart::current();\n\n\t\t$this->assertNotEmpty($cart);\n\t}\n\n\n\t/**\n\t * Tests cart item addition and removal.\n\t */\n\tpublic function testAddingRemovingItems()\n\t{\n\n\t\t$products = [];\n\n\t\twhile (count($products) < 3) {\n\t\t\t$products[] = App\\TestProduct::create([\n\t\t\t\t'price' \t\t\t=> count($products) + 0.99,\n\t\t\t\t'sku'\t\t\t\t=> str_random(15),\n\t\t\t\t'name'\t\t\t\t=> str_random(64),\n\t\t\t\t'description'\t\t=> str_random(500),\n\t\t\t]);\n\t\t}\n\n\t\t$cart = App\\Cart::current()\n\t\t\t->add($products[0])\n\t\t\t->add($products[1], 2)\n\t\t\t->add($products[2], 3);\n\n\t\t$this->assertEquals($cart->count, 6);\n\n\t\t$cart->add($products[2], 1, true);\n\n\t\t$this->assertEquals($cart->count, 4);\n\n\t\t$cart->remove($products[0], 1);\n\n\t\t$this->assertEquals($cart->count, 3);\n\n\t\t$cart->remove($products[2], 1);\n\n\t\t$this->assertEquals($cart->count, 2);\n\n\t\t$cart->clear();\n\n\t\t$this->assertEquals($cart->items->count(), 0);\n\n\t\tforeach ($products as $product) {\n\t\t\t$product->delete();\n\t\t}\n\t}\n\n\t/**\n\t * Tests cart additional methods, such as item find and calculations.\n\t */\n\tpublic function testCartMethods()\n\t{\n\t\t$product = App\\TestProduct::create([\n\t\t\t'price' \t\t\t=> 1.29,\n\t\t\t'sku'\t\t\t\t=> str_random(15),\n\t\t\t'name'\t\t\t\t=> str_random(64),\n\t\t\t'description'\t\t=> str_random(500),\n\t\t]);\n\n\t\t$cart = App\\Cart::current()\n\t\t\t->add($product)\n\t\t\t->add(['sku' => 'TEST001', 'price' => 6.99]);\n\n\t\t$this->assertTrue($cart->hasItem('TEST001'));\n\n\t\t$this->assertFalse($cart->hasItem('XXX'));\n\n\t\t$this->assertEquals($cart->totalPrice, 8.28);\n\n\t\t$this->assertEquals($cart->totalTax, 0);\n\n\t\t$this->assertEquals($cart->totalShipping, 0);\n\n\t\t$this->assertEquals($cart->total, 8.28);\n\n\t\t$product->delete();\n\t}\n\n\t/**\n\t * Tests cart order placement.\n\t */\n\tpublic function testOrderPlacement()\n\t{\n\t\t$cart = App\\Cart::current()\n\t\t\t->add(['sku' => str_random(15), 'price' => 1.99])\n\t\t\t->add(['sku' => str_random(15), 'price' => 1.99]);\n\n\t\t$order = $cart->placeOrder();\n\n\t\t$this->assertNotEmpty($order);\n\n\t\t$this->assertEquals($order->totalPrice, 3.98);\n\n\t\t$this->assertEquals($cart->count, 0);\n\n\t\t$this->assertEquals($order->count, 2);\n\n\t\t$this->assertTrue($order->isPending);\n\t}\n\n\t/**\n\t * Removes test data.\n\t */\n\tpublic function tearDown() \n\t{\n\t\t$this->user->delete();\n\n\t\tparent::tearDown();\n\t}\n\n}"
  },
  {
    "path": "tests/cart/ItemTest.php",
    "content": "<?php\n\nuse App;\nuse Auth;\nuse Hash;\nuse Shop;\nuse Log;\nuse Illuminate\\Foundation\\Testing\\WithoutMiddleware;\nuse Illuminate\\Foundation\\Testing\\DatabaseMigrations;\nuse Illuminate\\Foundation\\Testing\\DatabaseTransactions;\n\nclass ItemTest extends TestCase\n{\n\t/**\n\t * Tests item trait methods on external model.\n\t */\n\tpublic function testItemMethodsAndAttributes()\n\t{\n\t\t$product = App\\TestProduct::create([\n\t\t\t'price' \t\t\t=> 9.99,\n\t\t\t'sku'\t\t\t\t=> str_random(15),\n\t\t\t'name'\t\t\t\t=> str_random(64),\n\t\t\t'description'\t\t=> str_random(500),\n\t\t]);\n\n\t\t$this->assertTrue($product->isShoppable);\n\n\t\t$this->assertEquals($product->displayName, $product->name);\n\n\t\t$this->assertEquals($product->shopId, $product->id);\n\n\t\t$this->assertEquals($product->displayPrice, Shop::format(9.99));\n\n\t\t$this->assertEquals($product->displayTax, Shop::format(0.00));\n\n\t\t$this->assertEquals($product->displayShipping, Shop::format(0.00));\n\n\t\t$response = $this->call('GET', $product->shopUrl);\n\n\t\t$this->assertResponseOk();\n\n\t\t$this->assertEquals($product->id, $response->getContent());\n\n\t\t$product->delete();\n\t}\n\n\t/**\n\t * Tests item in cart functionality.\n\t */\n\tpublic function testItemInCart()\n\t{\n\t\t$product = App\\TestProduct::create([\n\t\t\t'price' \t\t\t=> 9.99,\n\t\t\t'sku'\t\t\t\t=> str_random(15),\n\t\t\t'name'\t\t\t\t=> str_random(64),\n\t\t\t'description'\t\t=> str_random(500),\n\t\t]);\n\n\t\t$user = factory('App\\User')->create();\n\n\t\t$cart = App\\Cart::findByUser($user->id)\n\t\t\t->add($product)\n\t\t\t->add(['sku' => 'TEST0001', 'price' => 1.99]);\n\n\t\tforeach ($cart->items as $item) {\n\t\t\t\n\t\t\tif ($item->sku == 'TEST0001') {\n\n\t\t\t\t$this->assertFalse($item->hasObject);\n\n\t\t\t\t$this->assertNull($item->object);\n\n\t    \t\t$this->assertEquals($item->shopUrl, '#');\n\n\t\t\t} else {\n\n\t\t\t\t$this->assertTrue($item->hasObject);\n\n\t\t\t\t$this->assertNotEmpty($item->object);\n\n\t    \t\t$this->assertNotEquals($item->shopUrl, '#');\n\n\t    \t}\n\n\t\t}\n\n\t\t$user->delete();\n\n\t    $product->delete();\n\t}\n\n\t/**\n\t * Tests item in cart functionality.\n\t */\n\tpublic function testPurchasedItemAttribute()\n\t{\n\t\t$user = factory('App\\User')->create(['password' => Hash::make('laravel-shop')]);\n\n\t\tAuth::attempt(['email' => $user->email, 'password' => 'laravel-shop']);\n\n\t\t$product = App\\TestProduct::create([\n\t\t\t'price' \t\t\t=> 9.99,\n\t\t\t'sku'\t\t\t\t=> str_random(15),\n\t\t\t'name'\t\t\t\t=> str_random(64),\n\t\t\t'description'\t\t=> str_random(500),\n\t\t]);\n\n\t\t$cart = App\\Cart::current()\n\t\t\t->add($product);\n\n\t\tShop::setGateway('testPass');\n\n\t\t$order = Shop::placeOrder();\n\n\t\t$this->assertTrue($order->isCompleted);\n\n\t\t$this->assertTrue($product->wasPurchased);\n\n\t\t$user->delete();\n\n\t    $product->delete();\n\t}\n}"
  },
  {
    "path": "tests/gateway/CallbackTest.php",
    "content": "<?php\n\nuse App;\nuse Shop;\nuse Log;\nuse Illuminate\\Foundation\\Testing\\WithoutMiddleware;\nuse Illuminate\\Foundation\\Testing\\DatabaseMigrations;\nuse Illuminate\\Foundation\\Testing\\DatabaseTransactions;\n\nclass CallbackTest extends TestCase\n{\n\n\t/**\n\t * User set for tests.\n\t */\n  \tprotected $user;\n\n\t/**\n\t * Cart set for tests.\n\t */\n  \tprotected $cart;\n\n\t/**\n\t * Product set for tests.\n\t */\n  \tprotected $product;\n\n\t/**\n\t * Setups test data.\n\t */\n\tpublic function setUp()\n\t{\n\t\tparent::setUp();\n\n\t\t$this->user = factory('App\\User')->create(['password' => Hash::make('laravel-shop')]);\n\n\t\tAuth::attempt(['email' => $this->user->email, 'password' => 'laravel-shop']);\n\n\t\t$this->product = App\\TestProduct::create([\n\t\t\t'price' \t\t\t=> 9.99,\n\t\t\t'sku'\t\t\t\t=> str_random(15),\n\t\t\t'name'\t\t\t\t=> str_random(64),\n\t\t\t'description'\t\t=> str_random(500),\n\t\t]);\n\n\t\t$this->cart = App\\Cart::current()->add($this->product);\n\t}\n\n\t/**\n\t * Removes test data.\n\t */\n\tpublic function tearDown() \n\t{\n\t\t$this->user->delete();\n\n\t\t$this->product->delete();\n\n\t\tparent::tearDown();\n\t}\n\n\t/**\n\t * Tests success callback.\n\t */\n\tpublic function testSuccessCallback()\n\t{\n\t\tShop::setGateway('testCallback');\n\n\t\tShop::checkout();\n\n\t\t$order = Shop::placeOrder();\n\n\t\t$callback = Shop::gateway()->getCallbackSuccess();\n\n\t\t$this->assertTrue($order->isPending);\n\n\t    $response = $this->call('GET', $callback);\n\n\t\t$this->assertTrue(Shop::gateway()->getDidCallback());\n\t}\n\n\t/**\n\t * Tests success callback.\n\t */\n\tpublic function testFailCallback()\n\t{\n\t\tShop::setGateway('testCallback');\n\n\t\tShop::checkout();\n\n\t\t$order = Shop::placeOrder();\n\n\t\t$callback = Shop::gateway()->getCallbackFail();\n\n\t\t$this->assertTrue($order->isPending);\n\n\t\t$response = $this->call('GET', $callback);\n\n\t\t$this->assertTrue(Shop::gateway()->getDidCallback());\n\t}\n}"
  },
  {
    "path": "tests/order/PurchaseTest.php",
    "content": "<?php\n\nuse App;\nuse Auth;\nuse Hash;\nuse Log;\nuse Shop;\nuse Illuminate\\Foundation\\Testing\\WithoutMiddleware;\nuse Illuminate\\Foundation\\Testing\\DatabaseMigrations;\nuse Illuminate\\Foundation\\Testing\\DatabaseTransactions;\n\nclass PurchaseTest extends TestCase\n{\n\t/**\n\t * Tests if gateway is being selected and created correctly.\n\t */\n\tpublic function testGateway()\n\t{\n\t\tShop::setGateway('testPass');\n\n\t\t$this->assertEquals(Shop::getGateway(), 'testPass');\n\n\t\t$gateway = Shop::gateway();\n\n\t\t$this->assertNotNull($gateway);\n\n\t\t$this->assertNotEmpty($gateway->toJson());\n\t}\n\t/**\n\t * Tests if gateway is being selected and created correctly.\n\t */\n\tpublic function testUnselectedGateway()\n\t{\n\t\t$this->assertFalse(Shop::checkout());\n\n\t\t$this->assertEquals(Shop::exception()->getMessage(), 'Payment gateway not selected.');\n\t}\n\n\t/**\n\t * Tests a purchase and shop flow.\n\t */\n\tpublic function testPurchaseFlow()\n\t{\n\t\t// Prepare\n\n\t\t$user = factory('App\\User')->create(['password' => Hash::make('laravel-shop')]);\n\n\t\t$bool = Auth::attempt(['email' => $user->email, 'password' => 'laravel-shop']);\n\n\t\t$cart = App\\Cart::current()\n\t\t\t->add(['sku' => '0001', 'price' => 1.99])\n\t\t\t->add(['sku' => '0002', 'price' => 2.99]);\n\n\t\tShop::setGateway('testPass');\n\n\t\tShop::checkout();\n\n\t\t$order = Shop::placeOrder();\n\n\t\t$this->assertNotNull($order);\n\n\t\t$this->assertNotEmpty($order->id);\n\n\t\t$this->assertTrue($order->isCompleted);\n\n\t\t$user->delete();\n\t}\n\n\t/**\n\t * Tests a purchase and shop flow.\n\t */\n\tpublic function testFailPurchase()\n\t{\n\t\t// Prepare\n\n\t\t$user = factory('App\\User')->create(['password' => Hash::make('laravel-shop')]);\n\n\t\t$bool = Auth::attempt(['email' => $user->email, 'password' => 'laravel-shop']);\n\n\t\t$cart = App\\Cart::current()\n\t\t\t->add(['sku' => '0001', 'price' => 1.99])\n\t\t\t->add(['sku' => '0002', 'price' => 2.99]);\n\n\t\tShop::setGateway('testFail');\n\n\t\t$this->assertFalse(Shop::checkout());\n\n\t\t$this->assertEquals(Shop::exception()->getMessage(), 'Checkout failed.');\n\n\t\t$order = Shop::placeOrder();\n\n\t\t$this->assertNotNull($order);\n\n\t\t$this->assertNotEmpty($order->id);\n\n\t\t$this->assertTrue($order->hasFailed);\n\n\t\t$this->assertEquals(Shop::exception()->getMessage(), 'Payment failed.');\n\n\t\t$user->delete();\n\t}\n\t/**\n\t * Tests if failed transactions are being created.\n\t */\n\tpublic function testFailedTransactions()\n\t{\n\t\t// Prepare\n\n\t\t$user = factory('App\\User')->create(['password' => Hash::make('laravel-shop')]);\n\n\t\t$bool = Auth::attempt(['email' => $user->email, 'password' => 'laravel-shop']);\n\n\t\t$cart = App\\Cart::current()\n\t\t\t->add(['sku' => '0001', 'price' => 1.99])\n\t\t\t->add(['sku' => '0002', 'price' => 2.99]);\n\n\t\tShop::setGateway('testFail');\n\n\t\t// Beging test\n\n\t\t$order = Shop::placeOrder();\n\n\t\t$this->assertNotNull($order);\n\n\t\t$this->assertNotEmpty($order->id);\n\n\t\t$this->assertTrue($order->hasFailed);\n\n\t\t$this->assertEquals(count($order->transactions), 1);\n\n\t\t$user->delete();\n\t}\n}"
  }
]