diff --git a/README.md b/README.md index 1761b74a8..bf9c1a56f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,12 @@ -                       ![Bagisto Logo](https://bagisto.com/wp-content/themes/bagisto/images/logo.png) +

+Total Downloads +

+

+Total Downloads +Latest Stable Version +License +

# Topics 1. ### Introduction diff --git a/packages/Webkul/Admin/src/DataGrids/OrderShipmentsDataGrid.php b/packages/Webkul/Admin/src/DataGrids/OrderShipmentsDataGrid.php index 9c2feae0a..c6e6f3e54 100644 --- a/packages/Webkul/Admin/src/DataGrids/OrderShipmentsDataGrid.php +++ b/packages/Webkul/Admin/src/DataGrids/OrderShipmentsDataGrid.php @@ -53,6 +53,12 @@ class OrderShipmentsDataGrid 'primaryKey' => 'ship.order_id', 'condition' => '=', 'secondaryKey' => 'ors.id', + ], [ + 'join' => 'leftjoin', + 'table' => 'inventory_sources as is', + 'primaryKey' => 'ship.inventory_source_id', + 'condition' => '=', + 'secondaryKey' => 'is.id', ] ], @@ -82,6 +88,12 @@ class OrderShipmentsDataGrid 'type' => 'string', 'label' => 'Customer Name', 'sortable' => false, + ], [ + 'name' => 'is.name', + 'alias' => 'inventorySourceName', + 'type' => 'string', + 'label' => 'Inventory Source', + 'sortable' => true ], [ 'name' => 'ors.created_at', 'alias' => 'orscreated', diff --git a/packages/Webkul/Admin/src/Http/Controllers/Sales/ShipmentController.php b/packages/Webkul/Admin/src/Http/Controllers/Sales/ShipmentController.php index 69e8cda8d..7f2aede94 100644 --- a/packages/Webkul/Admin/src/Http/Controllers/Sales/ShipmentController.php +++ b/packages/Webkul/Admin/src/Http/Controllers/Sales/ShipmentController.php @@ -5,8 +5,9 @@ namespace Webkul\Admin\Http\Controllers\Sales; use Illuminate\Http\Request; use Illuminate\Http\Response; use Webkul\Admin\Http\Controllers\Controller; -use Webkul\Sales\Repositories\OrderRepository as Order; use Webkul\Sales\Repositories\ShipmentRepository as Shipment; +use Webkul\Sales\Repositories\OrderRepository as Order; +use Webkul\Sales\Repositories\OrderItemRepository as OrderItem; /** * Sales Shipment controller @@ -23,28 +24,40 @@ class ShipmentController extends Controller */ protected $_config; - /** - * OrderRepository object - * - * @var array - */ - protected $order; - /** * ShipmentRepository object * - * @var array + * @var mixed */ protected $shipment; + /** + * OrderRepository object + * + * @var mixed + */ + protected $order; + + /** + * OrderItemRepository object + * + * @var mixed + */ + protected $orderItem; + /** * Create a new controller instance. * - * @param Webkul\Sales\Repositories\OrderRepository $order * @param Webkul\Sales\Repositories\ShipmentRepository $shipment + * @param Webkul\Sales\Repositories\OrderRepository $order + * @param Webkul\Sales\Repositories\OrderitemRepository $orderItem * @return void */ - public function __construct(Shipment $shipment, Order $order) + public function __construct( + Shipment $shipment, + Order $order, + OrderItem $orderItem + ) { $this->middleware('admin'); @@ -52,6 +65,8 @@ class ShipmentController extends Controller $this->order = $order; + $this->orderItem = $orderItem; + $this->shipment = $shipment; } @@ -76,6 +91,12 @@ class ShipmentController extends Controller { $order = $this->order->find($orderId); + if(!$order->channel || !$order->canShip()) { + session()->flash('error', 'Shipment can not be created for this order.'); + + return redirect()->back(); + } + return view($this->_config['view'], compact('order')); } @@ -99,21 +120,14 @@ class ShipmentController extends Controller $this->validate(request(), [ 'shipment.carrier_title' => 'required', 'shipment.track_number' => 'required', - 'shipment.items.*' => 'required|numeric|min:0', + 'shipment.source' => 'required', + 'shipment.items.*.*' => 'required|numeric|min:0', ]); $data = request()->all(); - - $haveProductToShip = false; - foreach ($data['shipment']['items'] as $itemId => $qty) { - if($qty) { - $haveProductToShip = true; - break; - } - } - if(!$haveProductToShip) { - session()->flash('error', 'Shipment can not be created without products.'); + if(!$this->isInventoryValidate($data)) { + session()->flash('error', 'Requested quantity is invalid or not available.'); return redirect()->back(); } @@ -125,6 +139,42 @@ class ShipmentController extends Controller return redirect()->route($this->_config['redirect'], $orderId); } + /** + * Checks if requested quantity available or not + * + * @param array $data + * @return boolean + */ + public function isInventoryValidate(&$data) + { + $valid = false; + + foreach ($data['shipment']['items'] as $itemId => $inventorySource) { + if ($qty = $inventorySource[$data['shipment']['source']]) { + $orderItem = $this->orderItem->find($itemId); + + $product = ($orderItem->type == 'configurable') + ? $orderItem->child->product + : $orderItem->product; + + // Check if requested qty is available, if not ship available qty + $inventory = $product->inventories() + ->where('inventory_source_id', $data['shipment']['source']) + ->first(); + + if ($orderItem->qty_to_ship < $qty || $inventory->qty < $qty) { + return false; + } + + $valid = true; + } else { + unset($data['shipment']['items'][$itemId]); + } + } + + return $valid; + } + /** * Show the view for the specified resource. * diff --git a/packages/Webkul/Admin/src/Listeners/Order.php b/packages/Webkul/Admin/src/Listeners/Order.php index 44a433981..377b4fbdd 100644 --- a/packages/Webkul/Admin/src/Listeners/Order.php +++ b/packages/Webkul/Admin/src/Listeners/Order.php @@ -64,10 +64,5 @@ class Order { */ public function updateProductInventory($order) { - $productListener = app(\Webkul\Admin\Listeners\Product::class); - - foreach ($order->items as $item) { - $productListener->afterOrderRecieved($item->product->id, $item->qty_ordered); - } } } \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Listeners/Product.php b/packages/Webkul/Admin/src/Listeners/Product.php index 1f259232f..cbe1b54b9 100644 --- a/packages/Webkul/Admin/src/Listeners/Product.php +++ b/packages/Webkul/Admin/src/Listeners/Product.php @@ -213,20 +213,6 @@ class Product { return true; } - /** - * Updates the product quantity when the order is received - * - * @param $productId - * @param $itemQuantity - */ - public function afterOrderRecieved($productId, $itemQuantity) { - $productGrid = $this->productGrid->findOneByField('product_id', $productId); - - $productGrid->update(['quantity' => $productGrid->quantity - $itemQuantity]); - - return true; - } - /** * Manually invoke this function when you have created the products by importing or seeding or factory. */ diff --git a/packages/Webkul/Admin/src/Resources/assets/sass/app.scss b/packages/Webkul/Admin/src/Resources/assets/sass/app.scss index bcce0777e..efed33611 100644 --- a/packages/Webkul/Admin/src/Resources/assets/sass/app.scss +++ b/packages/Webkul/Admin/src/Resources/assets/sass/app.scss @@ -481,6 +481,10 @@ body { margin-bottom: 0; } } + + .radio { + margin: 0; + } } .sale-summary { diff --git a/packages/Webkul/Admin/src/Resources/lang/en/app.php b/packages/Webkul/Admin/src/Resources/lang/en/app.php index faec0f03c..056e3501f 100644 --- a/packages/Webkul/Admin/src/Resources/lang/en/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/en/app.php @@ -191,9 +191,14 @@ return [ 'save-btn-title' => 'Save Shipment', 'qty-ordered' => 'Qty Ordered', 'qty-to-ship' => 'Qty to Ship', + 'available-sources' => 'Available Sources', + 'source' => 'Source', + 'select-source' => 'Please Select Source', + 'qty-available' => 'Qty Available', + 'inventory-source' => 'Inventory Source', 'carrier-title' => 'Carrier Title', 'tracking-number' => 'Tracking Number', - 'view-title' => 'Shipment #:shipment_id', + 'view-title' => 'Shipment #:shipment_id' ] ], 'catalog' => [ @@ -445,6 +450,7 @@ return [ 'default-locale' => 'Default Locale', 'currencies' => 'Currencies', 'base-currency' => 'Base Currency', + 'inventory_sources' => 'Inventory Sources', 'design' => 'Design', 'theme' => 'Theme', 'home_page_content' => 'Home Page Content', diff --git a/packages/Webkul/Admin/src/Resources/views/sales/orders/view.blade.php b/packages/Webkul/Admin/src/Resources/views/sales/orders/view.blade.php index 7fa327cc3..a2940d97a 100644 --- a/packages/Webkul/Admin/src/Resources/views/sales/orders/view.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/sales/orders/view.blade.php @@ -27,7 +27,7 @@ @endif - @if($order->canShip()) + @if($order->canShip() && $order->channel) {{ __('admin::app.sales.orders.shipment-btn-title') }} @@ -368,6 +368,7 @@ {{ __('admin::app.sales.shipments.order-id') }} {{ __('admin::app.sales.shipments.order-date') }} {{ __('admin::app.sales.shipments.customer-name') }} + {{ __('admin::app.sales.shipments.inventory-source') }} {{ __('admin::app.sales.shipments.total-qty') }} {{ __('admin::app.sales.shipments.action') }} @@ -382,6 +383,9 @@ #{{ $shipment->order->id }} {{ $shipment->order->created_at }} {{ $shipment->address->name }} + @if ($shipment->inventory_source) + {{ $shipment->inventory_source->name }} + @endif {{ $shipment->total_qty }} diff --git a/packages/Webkul/Admin/src/Resources/views/sales/shipments/create.blade.php b/packages/Webkul/Admin/src/Resources/views/sales/shipments/create.blade.php index 8c74de7fb..af2e0b615 100644 --- a/packages/Webkul/Admin/src/Resources/views/sales/shipments/create.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/sales/shipments/create.blade.php @@ -218,49 +218,7 @@
-
- - - - - - - - - - - - - @foreach ($order->items as $item) - @if ($item->qty_to_ship > 0) - - - - - - - @endif - @endforeach - - -
{{ __('admin::app.sales.orders.SKU') }}{{ __('admin::app.sales.orders.product-name') }}{{ __('admin::app.sales.shipments.qty-ordered') }}{{ __('admin::app.sales.shipments.qty-to-ship') }}
{{ $item->type == 'configurable' ? $item->child->sku : $item->sku }} - {{ $item->name }} - - @if ($html = $item->getOptionDetailHtml()) -

{{ $html }}

- @endif -
{{ $item->qty_ordered }} -
- - - - @verbatim - {{ errors.first('shipment[items][id ?>]') }} - @endverbatim - -
-
-
+
@@ -269,4 +227,129 @@ -@stop \ No newline at end of file +@stop + +@push('scripts') + + + + + +@endpush \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/views/sales/shipments/view.blade.php b/packages/Webkul/Admin/src/Resources/views/sales/shipments/view.blade.php index 666ebb18d..9359dfbd6 100644 --- a/packages/Webkul/Admin/src/Resources/views/sales/shipments/view.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/sales/shipments/view.blade.php @@ -191,6 +191,18 @@ + @if ($shipment->inventory_source) +
+ + {{ __('admin::app.sales.shipments.inventory-source') }} + + + + {{ $shipment->inventory_source->name }} + +
+ @endif +
{{ __('admin::app.sales.shipments.carrier-title') }} diff --git a/packages/Webkul/Admin/src/Resources/views/settings/channels/create.blade.php b/packages/Webkul/Admin/src/Resources/views/settings/channels/create.blade.php index 9055ca282..ebf463abb 100644 --- a/packages/Webkul/Admin/src/Resources/views/settings/channels/create.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/settings/channels/create.blade.php @@ -44,6 +44,18 @@
+
+ + + @{{ errors.first('inventory_sources[]') }} +
+
diff --git a/packages/Webkul/Admin/src/Resources/views/settings/channels/edit.blade.php b/packages/Webkul/Admin/src/Resources/views/settings/channels/edit.blade.php index 238074b2c..0802b67a9 100644 --- a/packages/Webkul/Admin/src/Resources/views/settings/channels/edit.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/settings/channels/edit.blade.php @@ -46,6 +46,19 @@
+
+ + inventory_sources->pluck('id')->toArray() ?> + + @{{ errors.first('inventory_sources[]') }} +
+
diff --git a/packages/Webkul/Admin/webpack.mix.js b/packages/Webkul/Admin/webpack.mix.js index 92e3d593b..3f72c18c8 100644 --- a/packages/Webkul/Admin/webpack.mix.js +++ b/packages/Webkul/Admin/webpack.mix.js @@ -1,8 +1,8 @@ const { mix } = require("laravel-mix"); require("laravel-mix-merge-manifest"); -var publicPath = 'publishable/assets'; -// var publicPath = "../../../public/vendor/webkul/admin/assets"; +// var publicPath = 'publishable/assets'; +var publicPath = "../../../public/vendor/webkul/admin/assets"; mix.setPublicPath(publicPath).mergeManifest(); mix.disableNotifications(); diff --git a/packages/Webkul/Core/src/Database/Migrations/2018_12_24_123812_create_channel_inventory_sources_table.php b/packages/Webkul/Core/src/Database/Migrations/2018_12_24_123812_create_channel_inventory_sources_table.php new file mode 100644 index 000000000..8f821264b --- /dev/null +++ b/packages/Webkul/Core/src/Database/Migrations/2018_12_24_123812_create_channel_inventory_sources_table.php @@ -0,0 +1,35 @@ +integer('channel_id')->unsigned(); + $table->integer('inventory_source_id')->unsigned(); + + $table->unique(['channel_id', 'inventory_source_id']); + $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); + $table->foreign('inventory_source_id')->references('id')->on('inventory_sources')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('channel_inventory_sources'); + } +} diff --git a/packages/Webkul/Core/src/Http/Controllers/ChannelController.php b/packages/Webkul/Core/src/Http/Controllers/ChannelController.php index e103e15dc..01336c106 100644 --- a/packages/Webkul/Core/src/Http/Controllers/ChannelController.php +++ b/packages/Webkul/Core/src/Http/Controllers/ChannelController.php @@ -120,6 +120,7 @@ class ChannelController extends Controller 'code' => ['required', 'unique:channels,code,' . $id, new \Webkul\Core\Contracts\Validations\Code], 'name' => 'required', 'locales' => 'required|array|min:1', + 'inventory_sources' => 'required|array|min:1', 'default_locale_id' => 'required', 'currencies' => 'required|array|min:1', 'base_currency_id' => 'required', diff --git a/packages/Webkul/Core/src/Models/Channel.php b/packages/Webkul/Core/src/Models/Channel.php index ba6bbbea9..2290967c6 100644 --- a/packages/Webkul/Core/src/Models/Channel.php +++ b/packages/Webkul/Core/src/Models/Channel.php @@ -3,9 +3,10 @@ namespace Webkul\Core\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\Storage; use Webkul\Core\Models\Locale; use Webkul\Core\Models\Currency; -use Illuminate\Support\Facades\Storage; +use Webkul\Inventory\Models\InventorySource; class Channel extends Model { @@ -35,6 +36,14 @@ class Channel extends Model return $this->belongsToMany(Currency::class, 'channel_currencies'); } + /** + * Get the channel inventory sources. + */ + public function inventory_sources() + { + return $this->belongsToMany(InventorySource::class, 'channel_inventory_sources'); + } + protected $with = ['base_currency']; diff --git a/packages/Webkul/Core/src/Repositories/ChannelRepository.php b/packages/Webkul/Core/src/Repositories/ChannelRepository.php index a3d1f364b..7664b5f4d 100644 --- a/packages/Webkul/Core/src/Repositories/ChannelRepository.php +++ b/packages/Webkul/Core/src/Repositories/ChannelRepository.php @@ -35,6 +35,8 @@ class ChannelRepository extends Repository $channel->currencies()->sync($data['currencies']); + $channel->inventory_sources()->sync($data['inventory_sources']); + $this->uploadImages($data, $channel); $this->uploadImages($data, $channel, 'favicon'); @@ -58,6 +60,8 @@ class ChannelRepository extends Repository $channel->currencies()->sync($data['currencies']); + $channel->inventory_sources()->sync($data['inventory_sources']); + $this->uploadImages($data, $channel); $this->uploadImages($data, $channel, 'favicon'); diff --git a/packages/Webkul/Product/src/Database/Migrations/2018_12_24_125915_create_product_salable_inventories_table.php b/packages/Webkul/Product/src/Database/Migrations/2018_12_24_125915_create_product_salable_inventories_table.php new file mode 100644 index 000000000..349261f2e --- /dev/null +++ b/packages/Webkul/Product/src/Database/Migrations/2018_12_24_125915_create_product_salable_inventories_table.php @@ -0,0 +1,38 @@ +increments('id'); + $table->integer('qty')->default(0); + $table->integer('sold_qty')->default(0); + $table->integer('product_id')->unsigned(); + $table->integer('channel_id')->unsigned(); + + $table->unique(['product_id', 'channel_id']); + $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade'); + $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('product_salable_inventories'); + } +} diff --git a/packages/Webkul/Product/src/Models/Product.php b/packages/Webkul/Product/src/Models/Product.php index 4bf20d078..b96eb751f 100644 --- a/packages/Webkul/Product/src/Models/Product.php +++ b/packages/Webkul/Product/src/Models/Product.php @@ -76,6 +76,14 @@ class Product extends Model return $this->hasMany(ProductInventory::class, 'product_id'); } + /** + * The salable inventories that belong to the product. + */ + public function salable_inventories() + { + return $this->hasMany(ProductSalableInventory::class, 'product_id'); + } + /** * The inventory sources that belong to the product. */ @@ -140,6 +148,16 @@ class Product extends Model return false; } + /** + * @param integer $qty + * + * @return bool + */ + public function inventory_source_qty($inventorySource) + { + return $this->inventories()->where('inventory_source_id', $inventorySource->id)->sum('qty'); + } + /** * @param integer $qty * @@ -147,15 +165,14 @@ class Product extends Model */ public function haveSufficientQuantity($qty) { - $inventories = $this->inventory_sources()->orderBy('priority', 'asc')->get(); + $salableInventories = $this->salable_inventories()->get(); $total = 0; - foreach($inventories as $inventorySource) { - if(!$inventorySource->status) - continue; - - $total += $inventorySource->pivot->qty; + foreach($salableInventories as $inventory) { + if($inventory->channel->id == core()->getCurrentChannel()->id) { + $total += $inventory->qty; + } } return $qty <= $total ? true : false; diff --git a/packages/Webkul/Product/src/Models/ProductSalableInventory.php b/packages/Webkul/Product/src/Models/ProductSalableInventory.php new file mode 100644 index 000000000..3cf72db82 --- /dev/null +++ b/packages/Webkul/Product/src/Models/ProductSalableInventory.php @@ -0,0 +1,38 @@ +belongsTo(Channel::class); + } + + // /** + // * Get the inventory source owns the product. + // */ + // public function inventory_source() + // { + // return $this->belongsTo(InventorySource::class); + // } + + /** + * Get the product that owns the product inventory. + */ + public function product() + { + return $this->belongsTo(Product::class); + } +} \ No newline at end of file diff --git a/packages/Webkul/Product/src/Repositories/ProductInventoryRepository.php b/packages/Webkul/Product/src/Repositories/ProductInventoryRepository.php index 40d8462de..d3cacaf5c 100644 --- a/packages/Webkul/Product/src/Repositories/ProductInventoryRepository.php +++ b/packages/Webkul/Product/src/Repositories/ProductInventoryRepository.php @@ -4,6 +4,7 @@ namespace Webkul\Product\Repositories; use Illuminate\Container\Container as App; use Webkul\Core\Eloquent\Repository; +use Webkul\Product\Repositories\ProductSalableInventoryRepository as SalableInventoryRepository; /** * Product Inventory Reposotory @@ -13,6 +14,30 @@ use Webkul\Core\Eloquent\Repository; */ class ProductInventoryRepository extends Repository { + + /** + * ProductSalableInventoryRepository object + * + * @var mixed + */ + protected $salableInventory; + + /** + * Create a new repository instance. + * + * @param Webkul\Product\Repositories\ProductSalableInventoryRepository $salableInventory + * @return void + */ + public function __construct( + SalableInventoryRepository $salableInventory, + App $app + ) + { + $this->salableInventory = $salableInventory; + + parent::__construct($app); + } + /** * Specify Model class name * @@ -24,7 +49,7 @@ class ProductInventoryRepository extends Repository } /** - * @param array $inventories + * @param array $data * @param mixed $product * @return mixed */ @@ -61,5 +86,7 @@ class ProductInventoryRepository extends Repository if($inventorySourceIds->count()) { $product->inventory_sources()->detach($inventorySourceIds); } + + $this->salableInventory->saveInventories($product); } } \ No newline at end of file diff --git a/packages/Webkul/Product/src/Repositories/ProductSalableInventoryRepository.php b/packages/Webkul/Product/src/Repositories/ProductSalableInventoryRepository.php new file mode 100644 index 000000000..09ace49b3 --- /dev/null +++ b/packages/Webkul/Product/src/Repositories/ProductSalableInventoryRepository.php @@ -0,0 +1,64 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class ProductSalableInventoryRepository extends Repository +{ + /** + * Specify Model class name + * + * @return mixed + */ + function model() + { + return 'Webkul\Product\Models\ProductSalableInventory'; + } + + /** + * @param mixed $product + * @return mixed + */ + public function saveInventories($product) + { + foreach (core()->getAllChannels() as $channel) { + $inventorySourceIds = $channel->inventory_sources()->pluck('inventory_source_id'); + + $salableQty = 0; + + foreach ($product->inventories()->get() as $productInventory) { + if(is_numeric($index = $inventorySourceIds->search($productInventory->inventory_source->id))) { + $salableQty += $productInventory->qty; + } + } + + $salableInventory = $this->findOneWhere([ + 'product_id' => $product->id, + 'channel_id' => $channel->id, + ]); + + if($salableInventory) { + $salableQty -= $salableInventory->sold_qty; + + if ($salableQty < 0) + $salableQty = 0; + + $this->update(['qty' => $salableQty], $salableInventory->id); + } else { + $this->create([ + 'qty' => $salableQty, + 'product_id' => $product->id, + 'channel_id' => $channel->id, + ]); + } + } + } +} \ No newline at end of file diff --git a/packages/Webkul/Sales/src/Contracts/OrderItemInventory.php b/packages/Webkul/Sales/src/Contracts/OrderItemInventory.php deleted file mode 100644 index 7e3fb76cd..000000000 --- a/packages/Webkul/Sales/src/Contracts/OrderItemInventory.php +++ /dev/null @@ -1,7 +0,0 @@ -increments('id'); - $table->integer('qty')->default(0); + Schema::table('shipments', function (Blueprint $table) { $table->integer('inventory_source_id')->unsigned()->nullable(); - $table->integer('order_item_id')->unsigned()->nullable(); - $table->timestamps(); + $table->foreign('inventory_source_id')->references('id')->on('inventory_sources')->onDelete('set null'); }); } @@ -29,6 +26,6 @@ class CreateOrderItemInventories extends Migration */ public function down() { - Schema::dropIfExists('order_item_inventories'); + // } } diff --git a/packages/Webkul/Sales/src/Models/Order.php b/packages/Webkul/Sales/src/Models/Order.php index e9fac2ff7..49d5df70d 100644 --- a/packages/Webkul/Sales/src/Models/Order.php +++ b/packages/Webkul/Sales/src/Models/Order.php @@ -22,7 +22,8 @@ class Order extends Model implements OrderContract /** * Get the order items record associated with the order. */ - public function getCustomerFullNameAttribute() { + public function getCustomerFullNameAttribute() + { return $this->customer_first_name . ' ' . $this->customer_last_name; } @@ -53,21 +54,24 @@ class Order extends Model implements OrderContract /** * Get the order items record associated with the order. */ - public function items() { + public function items() + { return $this->hasMany(OrderItemProxy::modelClass())->whereNull('parent_id'); } /** * Get the order shipments record associated with the order. */ - public function shipments() { + public function shipments() + { return $this->hasMany(ShipmentProxy::modelClass()); } /** * Get the order invoices record associated with the order. */ - public function invoices() { + public function invoices() + { return $this->hasMany(InvoiceProxy::modelClass()); } diff --git a/packages/Webkul/Sales/src/Models/OrderItem.php b/packages/Webkul/Sales/src/Models/OrderItem.php index f07aecd7e..a8d0f0288 100644 --- a/packages/Webkul/Sales/src/Models/OrderItem.php +++ b/packages/Webkul/Sales/src/Models/OrderItem.php @@ -17,21 +17,24 @@ class OrderItem extends Model implements OrderItemContract /** * Get remaining qty for shipping. */ - public function getQtyToShipAttribute() { + public function getQtyToShipAttribute() + { return $this->qty_ordered - $this->qty_shipped - $this->qty_refunded - $this->qty_canceled; } /** * Get remaining qty for invoice. */ - public function getQtyToInvoiceAttribute() { + public function getQtyToInvoiceAttribute() + { return $this->qty_ordered - $this->qty_invoiced - $this->qty_canceled; } /** * Get remaining qty for cancel. */ - public function getQtyToCancelAttribute() { + public function getQtyToCancelAttribute() + { return $this->qty_ordered - $this->qty_canceled - $this->qty_invoiced; } @@ -59,24 +62,19 @@ class OrderItem extends Model implements OrderItemContract return $this->hasOne(OrderItemProxy::modelClass(), 'parent_id'); } - /** - * Get the inventories record associated with the order item. - */ - public function inventories() { - return $this->hasMany(CartItemInventoryProxy::modelClass()); - } - /** * Get the invoice items record associated with the order item. */ - public function invoice_items() { + public function invoice_items() + { return $this->hasMany(InvoiceItemProxy::modelClass()); } /** * Get the shipment items record associated with the order item. */ - public function shipment_items() { + public function shipment_items() + { return $this->hasMany(ShipmentItemProxy::modelClass()); } diff --git a/packages/Webkul/Sales/src/Models/OrderItemInventory.php b/packages/Webkul/Sales/src/Models/OrderItemInventory.php deleted file mode 100644 index 1d6101016..000000000 --- a/packages/Webkul/Sales/src/Models/OrderItemInventory.php +++ /dev/null @@ -1,19 +0,0 @@ -belongsTo(OrderItemProxy::modelClass()); - } -} \ No newline at end of file diff --git a/packages/Webkul/Sales/src/Models/OrderItemInventoryProxy.php b/packages/Webkul/Sales/src/Models/OrderItemInventoryProxy.php deleted file mode 100644 index 75a62abf4..000000000 --- a/packages/Webkul/Sales/src/Models/OrderItemInventoryProxy.php +++ /dev/null @@ -1,10 +0,0 @@ -hasMany(ShipmentItemProxy::modelClass()); } + /** + * Get the inventory source associated with the shipment. + */ + public function inventory_source() + { + return $this->belongsTo(InventorySource::class, 'inventory_source_id'); + } + /** * Get the customer record associated with the shipment. */ diff --git a/packages/Webkul/Sales/src/Providers/ModuleServiceProvider.php b/packages/Webkul/Sales/src/Providers/ModuleServiceProvider.php index 8e6ea19b0..02444c64a 100644 --- a/packages/Webkul/Sales/src/Providers/ModuleServiceProvider.php +++ b/packages/Webkul/Sales/src/Providers/ModuleServiceProvider.php @@ -9,7 +9,6 @@ class ModuleServiceProvider extends BaseModuleServiceProvider protected $models = [ \Webkul\Sales\Models\Order::class, \Webkul\Sales\Models\OrderItem::class, - \Webkul\Sales\Models\OrderItemInventory::class, \Webkul\Sales\Models\OrderAddress::class, \Webkul\Sales\Models\OrderPayment::class, \Webkul\Sales\Models\Invoice::class, diff --git a/packages/Webkul/Sales/src/Repositories/OrderItemInventoryRepository.php b/packages/Webkul/Sales/src/Repositories/OrderItemInventoryRepository.php deleted file mode 100644 index 3731d8b99..000000000 --- a/packages/Webkul/Sales/src/Repositories/OrderItemInventoryRepository.php +++ /dev/null @@ -1,78 +0,0 @@ - - * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) - */ - -class OrderItemInventoryRepository extends Repository -{ - /** - * Specify Model class name - * - * @return Mixed - */ - - function model() - { - return 'Webkul\Sales\Contracts\OrderItemInventory'; - } - - /** - * @param array $data - * @return mixed - */ - public function create(array $data) - { - $orderItem = $data['orderItem']; - - $orderedQuantity = $orderItem->qty_ordered; - - $product = $orderItem->type == 'configurable' ? $orderItem->child->product : $orderItem->product; - - if($product) { - $inventories = $product->inventory_sources()->orderBy('priority', 'asc')->get(); - - foreach($inventories as $inventorySource) { - if(!$orderedQuantity) - break; - - $sourceQuantity = $inventorySource->pivot->qty; - - if(!$inventorySource->status || !$sourceQuantity) - continue; - - if($sourceQuantity >= $orderedQuantity) { - $orderItemQuantity = $orderedQuantity; - - $sourceQuantity -= $orderItemQuantity; - - $orderedQuantity = 0; - } else { - $orderItemQuantity = $sourceQuantity; - - $sourceQuantity = 0; - - $orderedQuantity -= $orderItemQuantity; - } - - $this->model->create([ - 'qty' => $orderItemQuantity, - 'order_item_id' => $orderItem->id, - 'inventory_source_id' => $inventorySource->id, - ]); - - $inventorySource->pivot->update([ - 'qty' => $sourceQuantity - ]); - } - } - } -} \ No newline at end of file diff --git a/packages/Webkul/Sales/src/Repositories/OrderItemRepository.php b/packages/Webkul/Sales/src/Repositories/OrderItemRepository.php index 30f9d5dd1..b203954b5 100644 --- a/packages/Webkul/Sales/src/Repositories/OrderItemRepository.php +++ b/packages/Webkul/Sales/src/Repositories/OrderItemRepository.php @@ -19,7 +19,6 @@ class OrderItemRepository extends Repository * * @return Mixed */ - function model() { return 'Webkul\Sales\Contracts\OrderItem'; @@ -78,4 +77,34 @@ class OrderItemRepository extends Repository return $orderItem; } + + + /** + * @param mixed $orderItem + * @return void + */ + public function manageStock($orderItem) + { + if(!$orderedQuantity = $orderItem->qty_ordered) + return; + + $product = $orderItem->type == 'configurable' ? $orderItem->child->product : $orderItem->product; + + if(!$product) { + return; + } + + $salableInventory = $product->salable_inventories() + ->where('channel_id', $orderItem->order->channel->id) + ->first(); + + if($salableInventory) { + $soldQty = $salableInventory->sold_qty + $orderItem->qty_ordered; + + $salableInventory->update([ + 'qty' => ($salableInventory->qty - $orderItem->qty_ordered), + 'sold_qty' => $soldQty + ]); + } + } } \ No newline at end of file diff --git a/packages/Webkul/Sales/src/Repositories/OrderRepository.php b/packages/Webkul/Sales/src/Repositories/OrderRepository.php index 8d9025ed3..c2a780975 100644 --- a/packages/Webkul/Sales/src/Repositories/OrderRepository.php +++ b/packages/Webkul/Sales/src/Repositories/OrderRepository.php @@ -8,7 +8,6 @@ use Illuminate\Support\Facades\DB; use Illuminate\Database\Eloquent\Model; use Webkul\Core\Eloquent\Repository; use Webkul\Sales\Repositories\OrderItemRepository; -use Webkul\Sales\Repositories\OrderItemInventoryRepository; /** * Order Reposotory @@ -26,30 +25,19 @@ class OrderRepository extends Repository */ protected $orderItem; - /** - * OrderItemInventoryRepository object - * - * @var Object - */ - protected $orderItemInventory; - /** * Create a new repository instance. * - * @param Webkul\Sales\Repositories\OrderItemRepository $orderItem - * @param Webkul\Sales\Repositories\OrderItemInventoryRepository $orderItemInventory + * @param Webkul\Sales\Repositories\OrderItemRepository $orderItem * @return void */ public function __construct( OrderItemRepository $orderItem, - OrderItemInventoryRepository $orderItemInventory, App $app ) { $this->orderItem = $orderItem; - $this->orderItemInventory = $orderItemInventory; - parent::__construct($app); } @@ -107,7 +95,7 @@ class OrderRepository extends Repository $orderItem->child = $this->orderItem->create(array_merge($item['child'], ['order_id' => $order->id, 'parent_id' => $orderItem->id])); } - $this->orderItemInventory->create(['orderItem' => $orderItem]); + $this->orderItem->manageStock($orderItem); } Event::fire('checkout.order.save.after', $order); diff --git a/packages/Webkul/Sales/src/Repositories/ShipmentItemRepository.php b/packages/Webkul/Sales/src/Repositories/ShipmentItemRepository.php new file mode 100644 index 000000000..802513526 --- /dev/null +++ b/packages/Webkul/Sales/src/Repositories/ShipmentItemRepository.php @@ -0,0 +1,56 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class ShipmentItemRepository extends Repository +{ + /** + * Specify Model class name + * + * @return Mixed + */ + function model() + { + return 'Webkul\Sales\Contracts\ShipmentItem'; + } + + /** + * @param array $data + * @return void + */ + public function updateProductInventory($data) + { + $salableInventory = $data['product']->salable_inventories() + ->where('channel_id', $data['shipment']->order->channel->id) + ->first(); + + $inventory = $data['product']->inventories() + ->where('inventory_source_id', $data['shipment']->inventory_source_id) + ->first(); + + if (($salableQty = $salableInventory->sold_qty - $data['qty']) < 0) { + $salableQty = 0; + } + + $salableInventory->update([ + 'sold_qty' => $salableQty + ]); + + if (($qty = $inventory->qty - $data['qty']) < 0) { + $qty = 0; + } + + $inventory->update([ + 'qty' => $data['qty'] + ]); + } +} \ No newline at end of file diff --git a/packages/Webkul/Sales/src/Repositories/ShipmentRepository.php b/packages/Webkul/Sales/src/Repositories/ShipmentRepository.php index de5c5c043..5f494022b 100644 --- a/packages/Webkul/Sales/src/Repositories/ShipmentRepository.php +++ b/packages/Webkul/Sales/src/Repositories/ShipmentRepository.php @@ -88,31 +88,37 @@ class ShipmentRepository extends Repository $order = $this->order->find($data['order_id']); - $totalQty = array_sum($data['shipment']['items']); - $shipment = $this->model->create([ 'order_id' => $order->id, - 'total_qty' => $totalQty, + 'total_qty' => 0, 'carrier_title' => $data['shipment']['carrier_title'], 'track_number' => $data['shipment']['track_number'], 'customer_id' => $order->customer_id, 'customer_type' => $order->customer_type, 'order_address_id' => $order->shipping_address->id, + 'inventory_source_id' => $data['shipment']['source'], ]); - foreach ($data['shipment']['items'] as $itemId => $qty) { - if(!$qty) continue; + $totalQty = 0; + + foreach ($data['shipment']['items'] as $itemId => $inventorySource) { + $qty = $inventorySource[$data['shipment']['source']]; $orderItem = $this->orderItem->find($itemId); - if($qty > $orderItem->qty_to_ship) - $qty = $orderItem->qty_to_ship; + $product = ($orderItem->type == 'configurable') + ? $orderItem->child->product + : $orderItem->product; + + $totalQty += $qty; $shipmentItem = $this->shipmentItem->create([ 'shipment_id' => $shipment->id, 'order_item_id' => $orderItem->id, 'name' => $orderItem->name, - 'sku' => ($orderItem->type == 'configurable' ? $orderItem->child->sku : $orderItem->sku), + 'sku' => ($orderItem->type == 'configurable') + ? $orderItem->child->sku + : $orderItem->sku, 'qty' => $qty, 'weight' => $orderItem->weight * $qty, 'price' => $orderItem->price, @@ -124,9 +130,20 @@ class ShipmentRepository extends Repository 'additional' => $orderItem->additional, ]); + $this->shipmentItem->updateProductInventory([ + 'shipment' => $shipment, + 'shipmentItem' => $shipmentItem, + 'product' => $product, + 'qty' => $qty + ]); + $this->orderItem->update(['qty_shipped' => $orderItem->qty_shipped + $qty], $orderItem->id); } + $shipment->update([ + 'total_qty' => $totalQty + ]); + $this->order->updateOrderStatus($order); Event::fire('sales.shipment.save.after', $shipment); @@ -140,4 +157,19 @@ class ShipmentRepository extends Repository return $shipment; } + + /** + * @param array $data + * @return integer + */ + public function getTotalQty(array $data) + { + $qty = 0; + + foreach ($data['shipment']['items'] as $itemId => $inventorySource) { + $qty += $inventorySource[$data['shipment']['source']]; + } + + return $qty; + } } \ No newline at end of file diff --git a/packages/Webkul/Sales/src/Repositories/ShipmenttemRepository.php b/packages/Webkul/Sales/src/Repositories/ShipmenttemRepository.php deleted file mode 100644 index 2e5428c65..000000000 --- a/packages/Webkul/Sales/src/Repositories/ShipmenttemRepository.php +++ /dev/null @@ -1,27 +0,0 @@ - - * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) - */ - -class ShipmentItemRepository extends Repository -{ - /** - * Specify Model class name - * - * @return Mixed - */ - - function model() - { - return 'Webkul\Sales\Contracts\ShipmentItem'; - } -} \ No newline at end of file