merge with master

This commit is contained in:
rahul shukla 2018-12-31 18:51:42 +05:30
commit 29ab4f1da9
81 changed files with 1018 additions and 353 deletions

20
LICENSE Normal file
View File

@ -0,0 +1,20 @@
MIT License
Copyright 2010-2018, Webkul Software
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,5 +1,12 @@
                       ![Bagisto Logo](https://bagisto.com/wp-content/themes/bagisto/images/logo.png)
<p align="center">
<a href="http://www.bagisto.com"><img src="https://bagisto.com/wp-content/themes/bagisto/images/logo.png" alt="Total Downloads"></a>
</p>
<p align="center">
<a href="https://packagist.org/packages/bagisto/bagisto"><img src="https://poser.pugx.org/bagisto/bagisto/d/total.svg" alt="Total Downloads"></a>
<a href="https://packagist.org/packages/bagisto/bagisto"><img src="https://poser.pugx.org/bagisto/bagisto/v/stable.svg" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/bagisto/bagisto"><img src="https://poser.pugx.org/bagisto/bagisto/license.svg" alt="License"></a>
</p>
# Topics
1. ### Introduction
@ -110,7 +117,7 @@ composer dump-autoload
### 5. License
Bagisto is a truly opensource E-Commerce framework which will always be free under the [MIT License](https://opensource.org/licenses/MIT).
Bagisto is a truly opensource E-Commerce framework which will always be free under the [MIT License](https://github.com/bagisto/bagisto/blob/master/LICENSE).
### Coming Soon:
-> API support for core packages and numerous fixes.

View File

@ -1,6 +1,6 @@
{
"name": "bagisto/bagisto",
"description": "Bagisto Ecommerce",
"description": "Bagisto Laravel ECommerce",
"keywords": [
"framework",
"laravel"

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
{
"/js/admin.js": "/js/admin.js?id=c70dacdf945a32e04b77",
"/css/admin.css": "/css/admin.css?id=ccb086d72702e662082e"
"/css/admin.css": "/css/admin.css?id=d40a640933cbcc121f1d"
}

View File

@ -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',

View File

@ -76,7 +76,9 @@ class OrderController extends Controller
*/
public function cancel($id)
{
if($this->order->cancel($id)) {
$result = $this->order->cancel($id);
if($result) {
session()->flash('success', trans('Order canceled successfully.'));
} else {
session()->flash('error', trans('Order can not be canceled.'));

View File

@ -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,41 @@ 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;
$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.
*

View File

@ -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);
}
}
}

View File

@ -218,20 +218,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.
*/

View File

@ -27,7 +27,5 @@ class EventServiceProvider extends ServiceProvider
Event::listen('catalog.product.create.after', 'Webkul\Admin\Listeners\Product@afterProductCreated');
Event::listen('catalog.product.update.after', 'Webkul\Admin\Listeners\Product@afterProductUpdate');
Event::listen('catalog.product.delete.after', 'Webkul\Admin\Listeners\Product@afterProductDelete');
}
}

View File

@ -481,6 +481,10 @@ body {
margin-bottom: 0;
}
}
.radio {
margin: 0;
}
}
.sale-summary {

View File

@ -205,9 +205,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'
]
],
@ -462,6 +467,8 @@ return [
'default-locale' => 'Default Locale',
'currencies' => 'Currencies',
'base-currency' => 'Base Currency',
'root-category' => 'Root Category',
'inventory_sources' => 'Inventory Sources',
'design' => 'Design',
'theme' => 'Theme',
'home_page_content' => 'Home Page Content',

View File

@ -153,7 +153,7 @@
</span>
<span class="value">
{{ core()->getConfigData('paymentmethods.' . $order->payment->method . '.title') }}
{{ core()->getConfigData('sales.paymentmethods.' . $order->payment->method . '.title') }}
</span>
</div>

View File

@ -142,7 +142,7 @@
<tbody>
<tr>
<td>
{{ core()->getConfigData('paymentmethods.' . $invoice->order->payment->method . '.title') }}
{{ core()->getConfigData('sales.paymentmethods.' . $invoice->order->payment->method . '.title') }}
</td>
<td>
{{ $invoice->order->shipping_title }}

View File

@ -153,7 +153,7 @@
</span>
<span class="value">
{{ core()->getConfigData('paymentmethods.' . $order->payment->method . '.title') }}
{{ core()->getConfigData('sales.paymentmethods.' . $order->payment->method . '.title') }}
</span>
</div>

View File

@ -172,7 +172,7 @@
</span>
<span class="value">
{{ core()->getConfigData('paymentmethods.' . $order->payment->method . '.title') }}
{{ core()->getConfigData('sales.paymentmethods.' . $order->payment->method . '.title') }}
</span>
</div>

View File

@ -153,7 +153,7 @@
</span>
<span class="value">
{{ core()->getConfigData('paymentmethods.' . $order->payment->method . '.title') }}
{{ core()->getConfigData('sales.paymentmethods.' . $order->payment->method . '.title') }}
</span>
</div>
@ -218,49 +218,7 @@
<accordian :title="'{{ __('admin::app.sales.orders.products-ordered') }}'" :active="true">
<div slot="body">
<div class="table">
<table>
<thead>
<tr>
<th>{{ __('admin::app.sales.orders.SKU') }}</th>
<th>{{ __('admin::app.sales.orders.product-name') }}</th>
<th>{{ __('admin::app.sales.shipments.qty-ordered') }}</th>
<th>{{ __('admin::app.sales.shipments.qty-to-ship') }}</th>
</tr>
</thead>
<tbody>
@foreach ($order->items as $item)
@if ($item->qty_to_ship > 0)
<tr>
<td>{{ $item->type == 'configurable' ? $item->child->sku : $item->sku }}</td>
<td>
{{ $item->name }}
@if ($html = $item->getOptionDetailHtml())
<p>{{ $html }}</p>
@endif
</td>
<td>{{ $item->qty_ordered }}</td>
<td>
<div class="control-group" :class="[errors.has('shipment[items][{{ $item->id }}]') ? 'has-error' : '']">
<input type="text" v-validate="'required|numeric|min:0'" class="control" id="shipment[items][{{ $item->id }}]" name="shipment[items][{{ $item->id }}]" value="{{ $item->qty_to_ship }}" data-vv-as="&quot;{{ __('admin::app.sales.shipments.qty-to-ship') }}&quot;"/>
<span class="control-error" v-if="errors.has('shipment[items][{{ $item->id }}]')">
@verbatim
{{ errors.first('shipment[items][<?php echo $item->id ?>]') }}
@endverbatim
</span>
</div>
</td>
</tr>
@endif
@endforeach
</tbody>
</table>
</div>
<order-item-list></order-item-list>
</div>
</accordian>
@ -269,4 +227,129 @@
</div>
</form>
</div>
@stop
@stop
@push('scripts')
<script type="text/x-template" id="order-item-list-template">
<div>
<div class="control-group" :class="[errors.has('shipment[source]') ? 'has-error' : '']">
<label for="shipment[source]" class="required">{{ __('admin::app.sales.shipments.source') }}</label>
<select v-validate="'required'" class="control" name="shipment[source]" id="shipment[source]" data-vv-as="&quot;{{ __('admin::app.sales.shipments.source') }}&quot;" v-model="source">
<option value="">{{ __('admin::app.sales.shipments.select-source') }}</option>
@foreach ($order->channel->inventory_sources as $key => $inventorySource)
<option value="{{ $inventorySource->id }}">{{ $inventorySource->name }}</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('shipment[source]')">
@{{ errors.first('shipment[source]') }}
</span>
</div>
<div class="table">
<table>
<thead>
<tr>
<th>{{ __('admin::app.sales.orders.SKU') }}</th>
<th>{{ __('admin::app.sales.orders.product-name') }}</th>
<th>{{ __('admin::app.sales.shipments.qty-ordered') }}</th>
<th>{{ __('admin::app.sales.shipments.qty-to-ship') }}</th>
<th>{{ __('admin::app.sales.shipments.available-sources') }}</th>
</tr>
</thead>
<tbody>
@foreach ($order->items as $item)
@if ($item->qty_to_ship > 0 && $item->product)
<tr>
<td>{{ $item->type == 'configurable' ? $item->child->sku : $item->sku }}</td>
<td>
{{ $item->name }}
@if ($html = $item->getOptionDetailHtml())
<p>{{ $html }}</p>
@endif
</td>
<td>{{ $item->qty_ordered }}</td>
<td>{{ $item->qty_to_ship }}</td>
<td>
<table>
<thead>
<tr>
<th>{{ __('admin::app.sales.shipments.source') }}</th>
<th>{{ __('admin::app.sales.shipments.qty-available') }}</th>
<th>{{ __('admin::app.sales.shipments.qty-to-ship') }}</th>
</tr>
</thead>
<tbody>
@foreach ($order->channel->inventory_sources as $key => $inventorySource)
<tr>
<td>
{{ $inventorySource->name }}
</td>
<td>
<?php
if($item->type == 'configurable') {
$sourceQty = $item->child->product->inventory_source_qty($inventorySource);
} else {
$sourceQty = $item->product->inventory_source_qty($inventorySource);
}
?>
{{ $sourceQty }}
</td>
<td>
<?php $inputName = "shipment[items][$item->id][$inventorySource->id]"; ?>
<div class="control-group" :class="[errors.has('{{ $inputName }}') ? 'has-error' : '']">
<input type="text" v-validate="'required|numeric|min_value:0|max_value:{{$sourceQty}}'" class="control" id="{{ $inputName }}" name="{{ $inputName }}" value="0" data-vv-as="&quot;{{ __('admin::app.sales.shipments.qty-to-ship') }}&quot;" :disabled="source != '{{ $inventorySource->id }}'"/>
<span class="control-error" v-if="errors.has('{{ $inputName }}')">
@verbatim
{{ errors.first('<?php echo $inputName; ?>') }}
@endverbatim
</span>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
</td>
</tr>
@endif
@endforeach
</tbody>
</table>
</div>
</div>
</script>
<script>
Vue.component('order-item-list', {
template: '#order-item-list-template',
inject: ['$validator'],
data: () => ({
source: ""
})
});
</script>
@endpush

View File

@ -149,7 +149,7 @@
</span>
<span class="value">
{{ core()->getConfigData('paymentmethods.' . $order->payment->method . '.title') }}
{{ core()->getConfigData('sales.paymentmethods.' . $order->payment->method . '.title') }}
</span>
</div>
@ -191,6 +191,18 @@
</span>
</div>
@if ($shipment->inventory_source)
<div class="row">
<span class="title">
{{ __('admin::app.sales.shipments.inventory-source') }}
</span>
<span class="value">
{{ $shipment->inventory_source->name }}
</span>
</div>
@endif
<div class="row">
<span class="title">
{{ __('admin::app.sales.shipments.carrier-title') }}

View File

@ -44,6 +44,30 @@
<textarea class="control" id="description" name="description">{{ old('description') }}</textarea>
</div>
<div class="control-group" :class="[errors.has('inventory_sources[]') ? 'has-error' : '']">
<label for="inventory_sources" class="required">{{ __('admin::app.settings.channels.inventory_sources') }}</label>
<select v-validate="'required'" class="control" id="inventory_sources" name="inventory_sources[]" data-vv-as="&quot;{{ __('admin::app.settings.channels.inventory_sources') }}&quot;" multiple>
@foreach(app('Webkul\Inventory\Repositories\InventorySourceRepository')->all() as $inventorySource)
<option value="{{ $inventorySource->id }}" {{ old('inventory_sources') && in_array($inventorySource->id, old('inventory_sources')) ? 'selected' : '' }}>
{{ $inventorySource->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('inventory_sources[]')">@{{ errors.first('inventory_sources[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('root_category_id') ? 'has-error' : '']">
<label for="root_category_id" class="required">{{ __('admin::app.settings.channels.root-category') }}</label>
<select v-validate="'required'" class="control" id="root_category_id" name="root_category_id" data-vv-as="&quot;{{ __('admin::app.settings.channels.root-category') }}&quot;">
@foreach(app('Webkul\Category\Repositories\CategoryRepository')->getRootCategories() as $category)
<option value="{{ $category->id }}" {{ old('root_category_id') == $category->id ? 'selected' : '' }}>
{{ $category->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('root_category_id')">@{{ errors.first('root_category_id') }}</span>
</div>
<div class="control-group">
<label for="hostname">{{ __('admin::app.settings.channels.hostname') }}</label>
<input class="control" id="hostname" name="hostname" value="{{ old('hostname') }}" placeholder="https://www.example.com"/>

View File

@ -46,6 +46,32 @@
<textarea class="control" id="description" name="description">{{ old('description') ?: $channel->description }}</textarea>
</div>
<div class="control-group" :class="[errors.has('inventory_sources[]') ? 'has-error' : '']">
<label for="inventory_sources" class="required">{{ __('admin::app.settings.channels.inventory_sources') }}</label>
<?php $selectedOptionIds = old('inventory_sources') ?: $channel->inventory_sources->pluck('id')->toArray() ?>
<select v-validate="'required'" class="control" id="inventory_sources" name="inventory_sources[]" data-vv-as="&quot;{{ __('admin::app.settings.channels.inventory_sources') }}&quot;" multiple>
@foreach(app('Webkul\Inventory\Repositories\InventorySourceRepository')->all() as $inventorySource)
<option value="{{ $inventorySource->id }}" {{ in_array($inventorySource->id, $selectedOptionIds) ? 'selected' : '' }}>
{{ $inventorySource->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('inventory_sources[]')">@{{ errors.first('inventory_sources[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('root_category_id') ? 'has-error' : '']">
<label for="root_category_id" class="required">{{ __('admin::app.settings.channels.root-category') }}</label>
<?php $selectedOption = old('root_category_id') ?: $channel->root_category_id ?>
<select v-validate="'required'" class="control" id="root_category_id" name="root_category_id" data-vv-as="&quot;{{ __('admin::app.settings.channels.root-category') }}&quot;">
@foreach(app('Webkul\Category\Repositories\CategoryRepository')->getRootCategories() as $category)
<option value="{{ $category->id }}" {{ $selectedOption == $category->id ? 'selected' : '' }}>
{{ $category->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('root_category_id')">@{{ errors.first('root_category_id') }}</span>
</div>
<div class="control-group">
<label for="hostname">{{ __('admin::app.settings.channels.hostname') }}</label>
<input type="text" class="control" id="hostname" name="hostname" value="{{ $channel->hostname }}" placeholder="https://www.example.com"/>

View File

@ -4,7 +4,6 @@ namespace Webkul\Attribute\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Event;
use Webkul\Attribute\Repositories\AttributeRepository as Attribute;
@ -38,8 +37,6 @@ class AttributeController extends Controller
*/
public function __construct(Attribute $attribute)
{
$this->middleware('admin');
$this->attribute = $attribute;
$this->_config = request('_config');
@ -78,12 +75,8 @@ class AttributeController extends Controller
'type' => 'required'
]);
Event::fire('catalog.attribute.create.before');
$attribute = $this->attribute->create(request()->all());
Event::fire('catalog.attribute.create.after', $attribute);
session()->flash('success', 'Attribute created successfully.');
return redirect()->route($this->_config['redirect']);
@ -117,12 +110,8 @@ class AttributeController extends Controller
'type' => 'required'
]);
Event::fire('catalog.attribute.update.before', $id);
$attribute = $this->attribute->update(request()->all(), $id);
Event::fire('catalog.attribute.update.after', $attribute);
session()->flash('success', 'Attribute updated successfully.');
return redirect()->route($this->_config['redirect']);
@ -142,12 +131,8 @@ class AttributeController extends Controller
session()->flash('error', 'Can not delete system attribute.');
} else {
try {
Event::fire('catalog.attribute.delete.before', $id);
$this->attribute->delete($id);
Event::fire('catalog.attribute.delete.after', $id);
session()->flash('success', 'Attribute deleted successfully.');
} catch(\Exception $e) {
session()->flash('error', 'Attribute is used in configurable products.');
@ -162,33 +147,30 @@ class AttributeController extends Controller
*
* @return response \Illuminate\Http\Response
*/
public function massDestroy() {
public function massDestroy()
{
$suppressFlash = false;
if(request()->isMethod('post')) {
if (request()->isMethod('post')) {
$indexes = explode(',', request()->input('indexes'));
foreach($indexes as $key => $value) {
foreach ($indexes as $key => $value) {
$attribute = $this->attribute->findOrFail($value);
try {
if(!$attribute->is_user_defined) {
if (!$attribute->is_user_defined) {
continue;
} else {
Event::fire('catalog.attribute.delete.before', $value);
$this->attribute->delete($value);
Event::fire('catalog.attribute.delete.after', $value);
}
} catch(\Exception $e) {
} catch (\Exception $e) {
$suppressFlash = true;
continue;
}
}
if(!$suppressFlash)
if (!$suppressFlash)
session()->flash('success', trans('admin::app.datagrid.mass-ops.delete-success', ['resource' => 'attributes']));
else
session()->flash('info', trans('admin::app.datagrid.mass-ops.partial-action', ['resource' => 'attributes']));

View File

@ -4,7 +4,6 @@ namespace Webkul\Attribute\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Event;
use Webkul\Attribute\Repositories\AttributeFamilyRepository as AttributeFamily;
use Webkul\Attribute\Repositories\AttributeRepository as Attribute;
@ -39,8 +38,6 @@ class AttributeFamilyController extends Controller
*/
public function __construct(AttributeFamily $attributeFamily)
{
$this->middleware('admin');
$this->attributeFamily = $attributeFamily;
$this->_config = request('_config');
@ -83,12 +80,8 @@ class AttributeFamilyController extends Controller
'name' => 'required'
]);
Event::fire('catalog.attribute_family.create.before');
$attributeFamily = $this->attributeFamily->create(request()->all());
Event::fire('catalog.attribute_family.create.after', $attributeFamily);
session()->flash('success', 'Family created successfully.');
return redirect()->route($this->_config['redirect']);
@ -124,12 +117,8 @@ class AttributeFamilyController extends Controller
'name' => 'required'
]);
Event::fire('catalog.attribute_family.update.before', $id);
$attributeFamily = $this->attributeFamily->update(request()->all(), $id);
Event::fire('catalog.attribute_family.update.after', $attributeFamily);
session()->flash('success', 'Family updated successfully.');
return redirect()->route($this->_config['redirect']);
@ -145,17 +134,13 @@ class AttributeFamilyController extends Controller
{
$attributeFamily = $this->attributeFamily->find($id);
if($this->attributeFamily->count() == 1) {
if ($this->attributeFamily->count() == 1) {
session()->flash('error', 'At least one family is required.');
} else if ($attributeFamily->products()->count()) {
session()->flash('error', 'Attribute family is used in products.');
} else {
Event::fire('catalog.attribute_family.delete.before', $id);
$this->attributeFamily->delete($id);
Event::fire('catalog.attribute_family.delete.after', $id);
session()->flash('success', 'Family deleted successfully.');
}
@ -170,24 +155,20 @@ class AttributeFamilyController extends Controller
public function massDestroy() {
$suppressFlash = false;
if(request()->isMethod('delete')) {
if (request()->isMethod('delete')) {
$indexes = explode(',', request()->input('indexes'));
foreach($indexes as $key => $value) {
foreach ($indexes as $key => $value) {
try {
Event::fire('catalog.attribute_family.delete.before', $value);
$this->attributeFamily->delete($value);
Event::fire('catalog.attribute_family.delete.after', $value);
} catch(\Exception $e) {
} catch (\Exception $e) {
$suppressFlash = true;
continue;
}
}
if(!$suppressFlash)
if (!$suppressFlash)
session()->flash('success', trans('admin::app.datagrid.mass-ops.delete-success'));
else
session()->flash('info', trans('admin::app.datagrid.mass-ops.partial-action', ['resource' => 'Attribute Family']));

View File

@ -3,6 +3,7 @@
namespace Webkul\Attribute\Repositories;
use Webkul\Core\Eloquent\Repository;
use Illuminate\Support\Facades\Event;
use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Attribute\Repositories\AttributeGroupRepository;
use Illuminate\Container\Container as App;
@ -61,6 +62,8 @@ class AttributeFamilyRepository extends Repository
*/
public function create(array $data)
{
Event::fire('catalog.attribute_family.create.before');
$attributeGroups = isset($data['attribute_groups']) ? $data['attribute_groups'] : [];
unset($data['attribute_groups']);
$family = $this->model->create($data);
@ -81,6 +84,8 @@ class AttributeFamilyRepository extends Repository
}
}
Event::fire('catalog.attribute_family.create.after', $attributeFamily);
return $family;
}
@ -94,6 +99,8 @@ class AttributeFamilyRepository extends Repository
{
$family = $this->find($id);
Event::fire('catalog.attribute_family.update.before', $id);
$family->update($data);
$previousAttributeGroupIds = $family->attribute_groups()->pluck('id');
@ -141,6 +148,21 @@ class AttributeFamilyRepository extends Repository
$this->attributeGroup->delete($attributeGroupId);
}
Event::fire('catalog.attribute_family.update.after', $family);
return $family;
}
/**
* @param $id
* @return void
*/
public function delete($id)
{
Event::fire('catalog.attribute_family.delete.before', $id);
parent::delete($id);
Event::fire('catalog.attribute_family.delete.after', $id);
}
}

View File

@ -3,6 +3,7 @@
namespace Webkul\Attribute\Repositories;
use Webkul\Core\Eloquent\Repository;
use Illuminate\Support\Facades\Event;
use Webkul\Attribute\Repositories\AttributeOptionRepository;
use Illuminate\Container\Container as App;
@ -50,6 +51,8 @@ class AttributeRepository extends Repository
*/
public function create(array $data)
{
Event::fire('catalog.attribute.create.before');
$data = $this->validateUserInput($data);
$options = isset($data['options']) ? $data['options'] : [];
@ -62,6 +65,8 @@ class AttributeRepository extends Repository
}
}
Event::fire('catalog.attribute.create.after', $attribute);
return $attribute;
}
@ -77,6 +82,8 @@ class AttributeRepository extends Repository
$attribute = $this->find($id);
Event::fire('catalog.attribute.update.before', $id);
$attribute->update($data);
$previousOptionIds = $attribute->options()->pluck('id');
@ -101,9 +108,24 @@ class AttributeRepository extends Repository
$this->attributeOption->delete($optionId);
}
Event::fire('catalog.attribute.update.after', $attribute);
return $attribute;
}
/**
* @param $id
* @return void
*/
public function delete($id)
{
Event::fire('catalog.attribute.delete.before', $id);
parent::delete($id);
Event::fire('catalog.attribute.delete.after', $id);
}
/**
* @param array $data
* @return array

View File

@ -4,7 +4,6 @@ namespace Webkul\Category\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Event;
use Webkul\Category\Repositories\CategoryRepository as Category;
/**
@ -37,8 +36,6 @@ class CategoryController extends Controller
*/
public function __construct(Category $category)
{
$this->middleware('admin');
$this->category = $category;
$this->_config = request('_config');
@ -79,12 +76,8 @@ class CategoryController extends Controller
'image.*' => 'mimes:jpeg,jpg,bmp,png'
]);
Event::fire('catalog.category.create.before');
$category = $this->category->create(request()->all());
Event::fire('catalog.category.create.after', $category);
session()->flash('success', 'Category created successfully.');
return redirect()->route($this->_config['redirect']);
@ -126,12 +119,8 @@ class CategoryController extends Controller
'image.*' => 'mimes:jpeg,jpg,bmp,png'
]);
Event::fire('catalog.category.update.before', $id);
$this->category->update(request()->all(), $id);
Event::fire('catalog.category.update.after', $id);
session()->flash('success', 'Category updated successfully.');
return redirect()->route($this->_config['redirect']);

View File

@ -2,10 +2,11 @@
namespace Webkul\Category\Repositories;
use Webkul\Category\Models\Category;
use Webkul\Core\Eloquent\Repository;
use Illuminate\Support\Facades\Storage;
use Illuminate\Container\Container as App;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Event;
use Webkul\Core\Eloquent\Repository;
use Webkul\Category\Models\Category;
use Webkul\Category\Models\CategoryTranslation;
use Illuminate\Database\Eloquent\ModelNotFoundException;
@ -43,6 +44,8 @@ class CategoryRepository extends Repository
*/
public function create(array $data)
{
Event::fire('catalog.category.create.before');
if (isset($data['locale']) && $data['locale'] == 'all') {
$model = app()->make($this->model());
@ -59,6 +62,8 @@ class CategoryRepository extends Repository
$this->uploadImages($data, $category);
Event::fire('catalog.category.create.after', $category);
return $category;
}
@ -75,6 +80,17 @@ class CategoryRepository extends Repository
: Category::orderBy('position', 'ASC')->get()->toTree();
}
/**
* Get root categories
*
* @return mixed
*/
public function getRootCategories()
{
return Category::withDepth()->having('depth', '=', 0)->get();
}
/**
* get visible category tree
*
@ -135,13 +151,30 @@ class CategoryRepository extends Repository
{
$category = $this->find($id);
Event::fire('catalog.category.update.before', $id);
$category->update($data);
$this->uploadImages($data, $category);
Event::fire('catalog.category.update.after', $id);
return $category;
}
/**
* @param $id
* @return void
*/
public function delete($id)
{
Event::fire('catalog.category.delete.before', $id);
parent::delete($id);
Event::fire('catalog.category.delete.after', $id);
}
/**
* @param array $data
* @param mixed $category

View File

@ -229,6 +229,10 @@ class Cart {
$product = $this->product->findOneByField('id', $id);
if($product->type == 'configurable') {
if(!isset($data['selected_configurable_option'])) {
return false;
}
$parentProduct = $this->product->findOneByField('id', $data['selected_configurable_option']);
$canAdd = $parentProduct->haveSufficientQuantity($data['quantity']);
@ -537,16 +541,24 @@ class Cart {
{
$cart = null;
if(auth()->guard('customer')->check()) {
if (auth()->guard('customer')->check()) {
$cart = $this->cart->findOneWhere([
'customer_id' => auth()->guard('customer')->user()->id,
'is_active' => 1
]);
'customer_id' => auth()->guard('customer')->user()->id,
'is_active' => 1
]);
} elseif(session()->has('cart')) {
} elseif (session()->has('cart')) {
$cart = $this->cart->find(session()->get('cart')->id);
}
if($cart != null) {
if($cart->items->count() == 0) {
$this->cart->delete($cart->id);
return false;
}
}
return $cart && $cart->is_active ? $cart : null;
}

View File

@ -537,8 +537,7 @@ class Core
'code' => $field,
'locale_code' => $locale
]);
}
else {
} else {
$coreConfigValue = $this->coreConfigRepository->findOneWhere([
'code' => $field
]);
@ -585,8 +584,8 @@ class Core
{
$collection = [];
foreach ($this->countries() as $country) {
$collection[$country->code] = $this->states($country->code)->toArray();
foreach ($this->countryStateRepository->all() as $state) {
$collection[$state->country_code][] = $state->toArray();
}
return $collection;

View File

@ -0,0 +1,35 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateChannelInventorySourcesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('channel_inventory_sources', function (Blueprint $table) {
$table->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');
}
}

View File

@ -0,0 +1,31 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AlterChannelsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('channels', function (Blueprint $table) {
$table->integer('root_category_id')->nullable()->unsigned();
$table->foreign('root_category_id')->references('id')->on('categories')->onDelete('set null');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}

View File

@ -38,8 +38,6 @@ class ChannelController extends Controller
*/
public function __construct(Channel $channel)
{
$this->middleware('admin');
$this->channel = $channel;
$this->_config = request('_config');
@ -79,6 +77,7 @@ class ChannelController extends Controller
'default_locale_id' => 'required',
'currencies' => 'required|array|min:1',
'base_currency_id' => 'required',
'root_category_id' => 'required',
'logo.*' => 'mimes:jpeg,jpg,bmp,png',
'favicon.*' => 'mimes:jpeg,jpg,bmp,png'
]);
@ -120,9 +119,11 @@ 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',
'root_category_id' => 'required',
'logo.*' => 'mimes:jpeg,jpg,bmp,png',
'favicon.*' => 'mimes:jpeg,jpg,bmp,png'
]);

View File

@ -37,8 +37,6 @@ class CurrencyController extends Controller
*/
public function __construct(Currency $currency)
{
$this->middleware('admin');
$this->currency = $currency;
$this->_config = request('_config');

View File

@ -46,8 +46,6 @@ class ExchangeRateController extends Controller
*/
public function __construct(ExchangeRate $exchangeRate, Currency $currency)
{
$this->middleware('admin');
$this->exchangeRate = $exchangeRate;
$this->currency = $currency;

View File

@ -37,8 +37,6 @@ class LocaleController extends Controller
*/
public function __construct(Locale $locale)
{
$this->middleware('admin');
$this->locale = $locale;
$this->_config = request('_config');

View File

@ -29,8 +29,6 @@ class SubscriptionController extends Controller
public function __construct(Subscribers $subscribers)
{
$this->middleware('admin');
$this->subscribers = $subscribers;
$this->_config = request('_config');

View File

@ -3,13 +3,15 @@
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\Category\Models\Category;
use Webkul\Inventory\Models\InventorySource;
class Channel extends Model
{
protected $fillable = ['code', 'name', 'description', 'theme', 'home_page_content', 'footer_content', 'hostname', 'default_locale_id', 'base_currency_id'];
protected $fillable = ['code', 'name', 'description', 'theme', 'home_page_content', 'footer_content', 'hostname', 'default_locale_id', 'base_currency_id', 'root_category_id'];
/**
* Get the channel locales.
@ -35,6 +37,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'];
@ -46,6 +56,14 @@ class Channel extends Model
return $this->belongsTo(Currency::class);
}
/**
* Get the base currency
*/
public function root_category()
{
return $this->belongsTo(Category::class, 'root_category_id');
}
/**
* Get logo image url.
*/

View File

@ -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');

View File

@ -58,7 +58,7 @@ class RegistrationController extends Controller
'last_name' => 'string|required',
'email' => 'email|required|unique:customers,email',
'password' => 'confirmed|min:6|required',
'agreement' => 'required'
// 'agreement' => 'required'
]);
$data = request()->input();

View File

@ -68,7 +68,7 @@ abstract class Payment
*/
public function getConfigData($field)
{
return core()->getConfigData('paymentmethods.' . $this->getCode() . '.' . $field);
return core()->getConfigData('sales.paymentmethods.' . $this->getCode() . '.' . $field);
}
abstract public function getRedirectUrl();

View File

@ -0,0 +1,37 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProductOrderedInventoriesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('product_ordered_inventories', function (Blueprint $table) {
$table->increments('id');
$table->integer('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_ordered_inventories');
}
}

View File

@ -78,8 +78,6 @@ class ProductController extends Controller
Product $product,
ProductGrid $productGrid)
{
$this->middleware('admin');
$this->attributeFamily = $attributeFamily;
$this->category = $category;
@ -142,14 +140,8 @@ class ProductController extends Controller
'sku' => ['required', 'unique:products,sku', new \Webkul\Core\Contracts\Validations\Slug]
]);
//before store of the product
Event::fire('catalog.product.create.before');
$product = $this->product->create(request()->all());
//after store of the product
Event::fire('catalog.product.create.after', $product);
session()->flash('success', 'Product created successfully.');
return redirect()->route($this->_config['redirect'], ['id' => $product->id]);
@ -181,12 +173,8 @@ class ProductController extends Controller
*/
public function update(ProductForm $request, $id)
{
Event::fire('catalog.product.update.before', $id);
$product = $this->product->update(request()->all(), $id);
Event::fire('catalog.product.update.after', $product);
session()->flash('success', 'Product updated successfully.');
return redirect()->route($this->_config['redirect']);
@ -200,12 +188,8 @@ class ProductController extends Controller
*/
public function destroy($id)
{
Event::fire('catalog.product.delete.before', $id);
$this->product->delete($id);
Event::fire('catalog.product.delete.after', $id);
session()->flash('success', 'Product deleted successfully.');
return redirect()->back();
@ -216,22 +200,12 @@ class ProductController extends Controller
*
* @return response
*/
public function massDestroy() {
$data = request()->all();
$productIds = explode(',', $data['indexes']);
public function massDestroy()
{
$productIds = explode(',', request()->input('indexes'));
if(count($productIds)) {
foreach($productIds as $productId) {
$product = $this->product->find($productId);
if(!is_null($product)) {
Event::fire('catalog.product.delete.before', $productId);
$product->delete();
Event::fire('catalog.product.delete.after', $productId);
}
}
foreach ($productIds as $productId) {
$this->product->delete($productId);
}
session()->flash('success', trans('admin::app.catalog.products.mass-delete-success'));
@ -244,36 +218,22 @@ class ProductController extends Controller
*
* @return response
*/
public function massUpdate() {
public function massUpdate()
{
$data = request()->all();
$attribute = 'status';
$productIds = explode(',', $data['indexes']);
if(!isset($data['massaction-type'])) {
if (!isset($data['massaction-type'])) {
return redirect()->back();
}
if(count($productIds)) {
foreach($productIds as $productId) {
$product = $this->product->find($productId);
$productIds = explode(',', $data['indexes']);
if($data['update-options'] == 0 && $data['selected-option-text'] == 'In Active') {
Event::fire('catelog.product.update.before', $productId);
$result = $this->product->updateAttribute($product, $attribute, $data['update-options']);
if($result)
Event::fire('catelog.product.update.after', $product);
} else if($data['update-options'] == 1 && $data['selected-option-text'] == 'Active') {
Event::fire('catelog.product.update.before', $productId);
$result = $this->product->updateAttribute($product, $attribute, $data['update-options']);
if($result)
Event::fire('product.update.after', $product);
}
}
foreach ($productIds as $productId) {
$this->product->update([
'channel' => null,
'locale' => null,
'status' => $data['update-options']
], $productId);
}
session()->flash('success', trans('admin::app.catalog.products.mass-update-success'));
@ -284,7 +244,8 @@ class ProductController extends Controller
/*
* To be manually invoked when data is seeded into products
*/
public function sync() {
public function sync()
{
Event::fire('products.datagrid.sync', true);
return redirect()->route('admin.catalog.products.index');

View File

@ -76,6 +76,14 @@ class Product extends Model
return $this->hasMany(ProductInventory::class, 'product_id');
}
/**
* The ordered inventories that belong to the product.
*/
public function ordered_inventories()
{
return $this->hasMany(ProductOrderedInventory::class, 'product_id');
}
/**
* The inventory sources that belong to the product.
*/
@ -140,6 +148,18 @@ 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 +167,25 @@ class Product extends Model
*/
public function haveSufficientQuantity($qty)
{
$inventories = $this->inventory_sources()->orderBy('priority', 'asc')->get();
$total = 0;
foreach($inventories as $inventorySource) {
if(!$inventorySource->status)
continue;
$channelInventorySourceIds = core()->getCurrentChannel()
->inventory_sources()
->where('status', 1)
->pluck('id');
$total += $inventorySource->pivot->qty;
foreach ($this->inventories as $inventory) {
if(is_numeric($index = $channelInventorySourceIds->search($inventory->inventory_source_id))) {
$total += $inventory->qty;
}
}
$orderedInventory = $this->ordered_inventories()
->where('channel_id', core()->getCurrentChannel()->id)
->first();
if ($orderedInventory) {
$total -= $orderedInventory->qty;
}
return $qty <= $total ? true : false;

View File

@ -0,0 +1,30 @@
<?php
namespace Webkul\Product\Models;
use Illuminate\Database\Eloquent\Model;
use Webkul\Inventory\Models\InventorySource;
use Webkul\Core\Models\Channel;
class ProductOrderedInventory extends Model
{
public $timestamps = false;
protected $fillable = ['qty', 'product_id', 'channel_id'];
/**
* Get the channel owns the inventory.
*/
public function channel()
{
return $this->belongsTo(Channel::class);
}
/**
* Get the product that owns the product inventory.
*/
public function product()
{
return $this->belongsTo(Product::class);
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace Webkul\Product\Models;
use Illuminate\Database\Eloquent\Model;
use Webkul\Inventory\Models\InventorySource;
use Webkul\Core\Models\Channel;
class ProductSalableInventory extends Model
{
public $timestamps = false;
protected $fillable = ['qty', 'sold_qty', 'product_id', 'channel_id'];
/**
* Get the channel owns the inventory.
*/
public function channel()
{
return $this->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);
}
}

View File

@ -24,12 +24,15 @@ class ProductInventoryRepository extends Repository
}
/**
* @param array $inventories
* @param array $data
* @param mixed $product
* @return mixed
*/
public function saveInventories(array $data, $product)
{
if ($product->type == 'configurable')
return;
$inventorySourceIds = $product->inventory_sources->pluck('id');
if(isset($data['inventories'])) {

View File

@ -3,6 +3,7 @@
namespace Webkul\Product\Repositories;
use Illuminate\Container\Container as App;
use Illuminate\Support\Facades\Event;
use Webkul\Core\Eloquent\Repository;
use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Attribute\Repositories\AttributeOptionRepository;
@ -111,6 +112,9 @@ class ProductRepository extends Repository
*/
public function create(array $data)
{
//before store of the product
Event::fire('catalog.product.create.before');
$product = $this->model->create($data);
$nameAttribute = $this->attribute->findOneByField('code', 'status');
@ -137,6 +141,10 @@ class ProductRepository extends Repository
}
}
//after store of the product
Event::fire('catalog.product.create.after', $product);
return $product;
}
@ -148,6 +156,8 @@ class ProductRepository extends Repository
*/
public function update(array $data, $id, $attribute = "id")
{
Event::fire('catalog.product.update.before', $id);
$product = $this->find($id);
if($product->parent_id && $this->checkVariantOptionAvailabiliy($data, $product)) {
@ -221,9 +231,24 @@ class ProductRepository extends Repository
$this->productImage->uploadImages($data, $product);
Event::fire('catalog.product.update.after', $product);
return $product;
}
/**
* @param $id
* @return mixed
*/
public function delete($id)
{
Event::fire('catalog.product.delete.before', $id);
parent::delete($id);
Event::fire('catalog.product.delete.after', $id);
}
/**
* @param mixed $product
* @param array $permutation
@ -350,29 +375,6 @@ class ProductRepository extends Repository
return $variant;
}
/**
* Change an attribute's value of the product
*
* @return boolean
*/
public function updateAttribute($product, $attribute, $value) {
$attribute = $this->attribute->findOneByField('code', 'status');
$attributeValue = $this->attributeValue->findOneWhere([
'product_id' => $product->id,
'attribute_id' => $attribute->id,
]);
$result = $this->attributeValue->update([
ProductAttributeValue::$attributeTypeFields[$attribute->type] => $value
], $attributeValue->id);
if($result)
return true;
else
return false;
}
/**
* @param array $data
* @param mixed $product

View File

@ -4,7 +4,7 @@ use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateOrderItemInventories extends Migration
class AlterShipmentsTable extends Migration
{
/**
* Run the migrations.
@ -13,12 +13,9 @@ class CreateOrderItemInventories extends Migration
*/
public function up()
{
Schema::create('order_item_inventories', function (Blueprint $table) {
$table->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');
//
}
}

View File

@ -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());
}

View File

@ -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());
}

View File

@ -3,6 +3,7 @@
namespace Webkul\Sales\Models;
use Illuminate\Database\Eloquent\Model;
use Webkul\Inventory\Models\InventorySource;
use Webkul\Sales\Contracts\Shipment as ShipmentContract;
class Shipment extends Model implements ShipmentContract
@ -20,10 +21,19 @@ class Shipment extends Model implements ShipmentContract
/**
* Get the shipment items record associated with the shipment.
*/
public function items() {
public function items()
{
return $this->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.
*/

View File

@ -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,

View File

@ -19,7 +19,6 @@ class OrderItemRepository extends Repository
*
* @return Mixed
*/
function model()
{
return 'Webkul\Sales\Contracts\OrderItem';
@ -78,4 +77,62 @@ class OrderItemRepository extends Repository
return $orderItem;
}
/**
* @param mixed $orderItem
* @return void
*/
public function manageInventory($orderItem)
{
if(!$orderedQuantity = $orderItem->qty_ordered)
return;
$product = $orderItem->type == 'configurable' ? $orderItem->child->product : $orderItem->product;
if(!$product) {
return;
}
$orderedInventory = $product->ordered_inventories()
->where('channel_id', $orderItem->order->channel->id)
->first();
if($orderedInventory) {
$orderedInventory->update([
'qty' => $orderedInventory->qty + $orderItem->qty_ordered
]);
} else {
$product->ordered_inventories()->create([
'qty' => $orderItem->qty_ordered,
'product_id' => $product->id,
'channel_id' => $orderItem->order->channel->id,
]);
}
}
/**
* Returns qty to product inventory after order cancelation
*
* @param mixed $orderItem
* @return void
*/
public function returnQtyToProductInventory($orderItem)
{
if (!$product = $orderItem->product)
return;
$orderedInventory = $product->ordered_inventories()
->where('channel_id', $orderItem->order->channel->id)
->first();
if ($orderedInventory) {
if (($qty = $orderedInventory->qty - $orderItem->qty_to_cancel) < 0) {
$qty = 0;
}
$orderedInventory->update([
'qty' => $qty
]);
}
}
}

View File

@ -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);
}
@ -90,7 +78,7 @@ class OrderRepository extends Repository
unset($data['channel']);
}
$data['status'] = core()->getConfigData('paymentmethods.' . $data['payment']['method'] . '.order_status') ?? 'pending';
$data['status'] = core()->getConfigData('sales.paymentmethods.' . $data['payment']['method'] . '.order_status') ?? 'pending';
$order = $this->model->create(array_merge($data, ['increment_id' => $this->generateIncrementId()]));
@ -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->manageInventory($orderItem);
}
Event::fire('checkout.order.save.after', $order);
@ -135,6 +123,8 @@ class OrderRepository extends Repository
foreach($order->items as $item) {
if($item->qty_to_cancel) {
$this->orderItem->returnQtyToProductInventory($item);
$item->qty_canceled += $item->qty_to_cancel;
$item->save();

View File

@ -0,0 +1,64 @@
<?php
namespace Webkul\Sales\Repositories;
use Illuminate\Container\Container as App;
use Webkul\Core\Eloquent\Repository;
/**
* ShipmentItem Reposotory
*
* @author Jitendra Singh <jitendra@webkul.com>
* @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)
{
$orderedInventory = $data['product']->ordered_inventories()
->where('channel_id', $data['shipment']->order->channel->id)
->first();
if ($orderedInventory) {
if (($orderedQty = $orderedInventory->qty - $data['qty']) < 0) {
$orderedQty = 0;
}
$orderedInventory->update([
'qty' => $orderedQty
]);
} else {
$data['product']->ordered_inventories()->create([
'qty' => $data['qty'],
'product_id' => $data['product']->id,
'channel_id' => $data['shipment']->order->channel->id
]);
}
$inventory = $data['product']->inventories()
->where('inventory_source_id', $data['shipment']->inventory_source_id)
->first();
if (($qty = $inventory->qty - $data['qty']) < 0) {
$qty = 0;
}
$inventory->update([
'qty' => $qty
]);
}
}

View File

@ -88,31 +88,33 @@ 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;
$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 +126,24 @@ class ShipmentRepository extends Repository
'additional' => $orderItem->additional,
]);
$product = ($orderItem->type == 'configurable')
? $orderItem->child->product
: $orderItem->product;
$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);

View File

@ -69,7 +69,7 @@ abstract class AbstractShipping
*/
public function getConfigData($field)
{
return core()->getConfigData('carriers.' . $this->getCode() . '.' . $field);
return core()->getConfigData('sales.carriers.' . $this->getCode() . '.' . $field);
}
}
?>

View File

@ -5,6 +5,7 @@ namespace Webkul\Shipping\Carriers;
use Config;
use Webkul\Checkout\Models\CartShippingRate;
use Webkul\Shipping\Facades\Shipping;
use Webkul\Checkout\Facades\Cart;
/**
* Class Rate.
@ -29,6 +30,8 @@ class FlatRate extends AbstractShipping
if(!$this->isAvailable())
return false;
$cart = Cart::getCart();
$object = new CartShippingRate;
$object->carrier = 'flatrate';
@ -36,8 +39,15 @@ class FlatRate extends AbstractShipping
$object->method = 'flatrate_flatrate';
$object->method_title = $this->getConfigData('title');
$object->method_description = $this->getConfigData('description');
$object->price = core()->convertPrice($this->getConfigData('default_rate'));
$object->base_price = $this->getConfigData('default_rate');
if ($this->getConfigData('type') == 'per_unit') {
$object->price = core()->convertPrice($this->getConfigData('default_rate')) * $cart->items_qty;
$object->base_price = $this->getConfigData('default_rate') * $cart->items_qty;
} else {
$object->price = core()->convertPrice($this->getConfigData('default_rate'));
$object->base_price = $this->getConfigData('default_rate');
}
return $object;
}

View File

@ -74,9 +74,9 @@ return [
'options' => [
[
'title' => 'Per Unit',
'value' => 'Per Order'
'value' => 'per_unit'
], [
'title' => 'Inactive',
'title' => 'Per Order',
'value' => 'per_order'
]
],
@ -97,5 +97,57 @@ return [
'validation' => 'required'
]
]
], [
'key' => 'sales.shipping',
'name' => 'Shipping',
'sort' => 0
], [
'key' => 'sales.shipping.origin',
'name' => 'Origin',
'sort' => 0,
'fields' => [
[
'name' => 'country',
'title' => 'Country',
'type' => 'text',
'validation' => 'required',
'channel_based' => true,
'locale_based' => false
], [
'name' => 'state',
'title' => 'State',
'type' => 'text',
'validation' => 'required',
'channel_based' => true,
'locale_based' => false
], [
'name' => 'address1',
'title' => 'Address Line 1',
'type' => 'text',
'validation' => 'required',
'channel_based' => true,
'locale_based' => false
], [
'name' => 'address2',
'title' => 'Address Line 2',
'type' => 'text',
'channel_based' => true,
'locale_based' => false
], [
'name' => 'zipcode',
'title' => 'Zip',
'type' => 'text',
'validation' => 'required',
'channel_based' => true,
'locale_based' => false
], [
'name' => 'city',
'title' => 'City',
'type' => 'text',
'validation' => 'required',
'channel_based' => true,
'locale_based' => false
]
]
]
];

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,10 @@
{
<<<<<<< HEAD
"/js/shop.js": "/js/shop.js?id=0e3e1ea03fe1f7358aaa",
"/css/shop.css": "/css/shop.css?id=d6b0cd4b3af8277a77b1"
}
=======
"/js/shop.js": "/js/shop.js?id=dc2ea56a854d779e7089",
"/css/shop.css": "/css/shop.css?id=7aa91d217344fc8f4f53"
}
>>>>>>> 4e89ce082ea6e0282b569e4928016771b99a8f56

View File

@ -57,7 +57,7 @@ class SliderController extends controller
$this->validate(request(), [
'title' => 'string|required',
'channel_id' => 'required',
'image' => 'required|mimes:jpeg,bmp,png'
'image.*' => 'required|mimes:jpeg,bmp,png,jpg'
]);
$result = $this->slider->save(request()->all());
@ -90,7 +90,7 @@ class SliderController extends controller
$this->validate(request(), [
'title' => 'string|required',
'channel_id' => 'required',
'image' => 'sometimes|mimes:jpeg,bmp,png'
'image.*' => 'sometimes|mimes:jpeg,bmp,png,jpg'
]);
$result = $this->slider->updateItem(request()->all(), $id);

View File

@ -44,7 +44,7 @@ class CategoryComposer
{
$categories = [];
foreach ($this->category->getVisibleCategoryTree() as $category) {
foreach ($this->category->getVisibleCategoryTree(core()->getCurrentChannel()->root_category_id) as $category) {
if($category->slug)
array_push($categories, $category);
}

View File

@ -328,6 +328,10 @@ input {
.account-items-list {
display: block;
width: 100%;
.grid-container {
margin-top: 40px;
}
}
//no search results
.search-result-status {

View File

@ -9,7 +9,7 @@
<div style="display: inline-block; cursor: pointer;">
<span class="name">
Cart
<span class="count"> ({{ intval($cart->items_qty) }})</span>
<span class="count"> ({{ $cart->items->count() }})</span>
</span>
</div>

View File

@ -122,7 +122,7 @@
</div>
<div class="text">
{{ core()->getConfigData('paymentmethods.' . $cart->payment->method . '.title') }}
{{ core()->getConfigData('sales.paymentmethods.' . $cart->payment->method . '.title') }}
</div>
</div>

View File

@ -142,7 +142,7 @@
<tbody>
<tr>
<td>
{{ core()->getConfigData('paymentmethods.' . $invoice->order->payment->method . '.title') }}
{{ core()->getConfigData('sales.paymentmethods.' . $invoice->order->payment->method . '.title') }}
</td>
<td>
{{ $invoice->order->shipping_title }}

View File

@ -483,7 +483,7 @@
</div>
<div class="box-content">
{{ core()->getConfigData('paymentmethods.' . $order->payment->method . '.title') }}
{{ core()->getConfigData('sales.paymentmethods.' . $order->payment->method . '.title') }}
</div>
</div>
</div>

View File

@ -64,16 +64,18 @@
{!! view_render_event('bagisto.shop.customers.signup_form_controls.after') !!}
<div class="control-group" :class="[errors.has('agreement') ? 'has-error' : '']">
{{-- <div class="control-group" :class="[errors.has('agreement') ? 'has-error' : '']">
<input type="checkbox" id="checkbox2" name="agreement" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.signup-form.agreement') }}&quot;">
<span>{{ __('shop::app.customer.signup-form.agree') }}
<a href="">{{ __('shop::app.customer.signup-form.terms') }}</a> & <a href="">{{ __('shop::app.customer.signup-form.conditions') }}</a> {{ __('shop::app.customer.signup-form.using') }}.
</span>
<span class="control-error" v-if="errors.has('agreement')">@{{ errors.first('agreement') }}</span>
</div>
</div> --}}
<input class="btn btn-primary btn-lg" type="submit" value="{{ __('shop::app.customer.signup-form.button_title') }}">
<button class="btn btn-primary btn-lg" type="submit">
{{ __('shop::app.customer.signup-form.button_title') }}
</button>
</div>
</form>

View File

@ -91,7 +91,7 @@
</div>
<div style="font-weight: bold;font-size: 16px; color: #242424;">
{{ core()->getConfigData('paymentmethods.' . $order->payment->method . '.title') }}
{{ core()->getConfigData('sales.paymentmethods.' . $order->payment->method . '.title') }}
</div>
</div>
</div>

View File

@ -89,7 +89,7 @@
</div>
<div style="font-weight: bold;font-size: 16px; color: #242424;">
{{ core()->getConfigData('paymentmethods.' . $order->payment->method . '.title') }}
{{ core()->getConfigData('sales.paymentmethods.' . $order->payment->method . '.title') }}
</div>
</div>
</div>

View File

@ -101,7 +101,7 @@
</div>
<div style="font-weight: bold;font-size: 16px; color: #242424;">
{{ core()->getConfigData('paymentmethods.' . $order->payment->method . '.title') }}
{{ core()->getConfigData('sales.paymentmethods.' . $order->payment->method . '.title') }}
</div>
</div>
</div>

View File

@ -60,8 +60,6 @@ class TaxCategoryController extends Controller
TaxMap $taxMap
)
{
$this->middleware('admin');
$this->taxCategory = $taxCategory;
$this->taxRate = $taxRate;

View File

@ -38,8 +38,6 @@ class TaxRateController extends Controller
*/
public function __construct(TaxRate $taxRate)
{
$this->middleware('admin');
$this->taxRate = $taxRate;
$this->_config = request('_config');

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,10 @@
{
<<<<<<< HEAD
"/js/ui.js": "/js/ui.js?id=188cc8772638ec817a35",
"/css/ui.css": "/css/ui.css?id=014ff883008a2459b5e1"
}
=======
"/js/ui.js": "/js/ui.js?id=c3ee60fd11e29aca2922",
"/css/ui.css": "/css/ui.css?id=0433c5b81c6583e79c04"
}
>>>>>>> 4e89ce082ea6e0282b569e4928016771b99a8f56

View File

@ -355,7 +355,7 @@ h2 {
position: relative;
display: block;
vertical-align: middle;
margin: 10px 5px 5px 0px;
margin: 0px 5px 5px 0px;
input {
left: 0;

View File

@ -1,7 +1,7 @@
<div class="{{ $css->filter }} filter-wrapper">
<div class="filter-row-one">
<div class="search-filter" style="display: inline-flex; align-items: center;">
<input type="search" class="control search-field" placeholder="Search Here..." value="" />
<input type="search" id="search-field" class="control" placeholder="Search Here..." value="" />
<div class="ic-wrapper">
<span class="icon search-icon search-btn"></span>
</div>

View File

@ -45,13 +45,15 @@
}
$('.search-btn').click(function() {
search_value = $(".search-field").val();
search_value = $("#search-field").val();
alert(search_value);
formURL('search', 'all', search_value, params); //format for search
});
$(".search-field").on('keyup', function (e) {
if (e.keyCode == 13) {
search_value = $(".search-field").val();
search_value = $("#search-field").val();
alert(search_value);
formURL('search', 'all', search_value, params); //format for search
}
});

View File

@ -29,8 +29,6 @@ class AccountController extends Controller
*/
public function __construct()
{
$this->middleware('admin');
$this->_config = request('_config');
}

View File

@ -48,8 +48,6 @@ class UserController extends Controller
*/
public function __construct(Admin $admin, Role $role)
{
$this->middleware('admin');
$this->admin = $admin;
$this->role = $role;