Group product added
This commit is contained in:
parent
3d527d6aba
commit
29e4851bfb
|
|
@ -129,7 +129,7 @@ class CartController extends Controller
|
|||
|
||||
Event::fire('checkout.cart.item.update.before', $itemId);
|
||||
|
||||
Cart::updateItem($item->product_id, ['quantity' => $qty], $itemId);
|
||||
Cart::updateItem(['quantity' => $qty], $itemId);
|
||||
|
||||
Event::fire('checkout.cart.item.update.after', $item);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ class ConfigurationController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ class CustomerController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -81,7 +81,7 @@ class CustomerController extends Controller
|
|||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
@ -127,7 +127,7 @@ class CustomerController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
@ -190,7 +190,7 @@ class CustomerController extends Controller
|
|||
/**
|
||||
* To load the note taking screen for the customers
|
||||
*
|
||||
* @return view
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function createNote($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class CustomerGroupController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -55,7 +55,7 @@ class CustomerGroupController extends Controller
|
|||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
@ -89,7 +89,7 @@ class CustomerGroupController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ class DashboardController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class InvoiceController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -72,7 +72,7 @@ class InvoiceController extends Controller
|
|||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @param int $orderId
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create($orderId)
|
||||
{
|
||||
|
|
@ -128,7 +128,7 @@ class InvoiceController extends Controller
|
|||
* Show the view for the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function view($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class OrderController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -57,7 +57,7 @@ class OrderController extends Controller
|
|||
* Show the view for the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function view($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ class ShipmentController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -82,7 +82,7 @@ class ShipmentController extends Controller
|
|||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @param int $orderId
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create($orderId)
|
||||
{
|
||||
|
|
@ -177,7 +177,7 @@ class ShipmentController extends Controller
|
|||
* Show the view for the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function view($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -248,6 +248,9 @@ Route::group(['middleware' => ['web']], function () {
|
|||
'view' => 'admin::catalog.products.edit'
|
||||
])->name('admin.catalog.products.productlinksearch');
|
||||
|
||||
//product search for linked products
|
||||
Route::get('products/search/{id}', 'Webkul\Product\Http\Controllers\ProductController@searchProductForGroupedAssociation')->name('admin.catalog.products.search_product_for_grouped_association');
|
||||
|
||||
Route::get('/products/{id}/{attribute_id}', 'Webkul\Product\Http\Controllers\ProductController@download')->defaults('_config', [
|
||||
'view' => 'admin.catalog.products.edit'
|
||||
])->name('admin.catalog.products.file.download');
|
||||
|
|
|
|||
|
|
@ -360,7 +360,33 @@ return [
|
|||
'add-image-btn-title' => 'إضافة صورة',
|
||||
'mass-delete-success' => 'تم حذف كل الفهرس المنتقى من المنتجات بنجاح',
|
||||
'mass-update-success' => 'كل الفهرس المختار من المنتجات تم تحديثه بنجاح',
|
||||
'configurable-error' => 'رجاء تحديد واحد مهيء الصفة.'
|
||||
'configurable-error' => 'رجاء تحديد واحد مهيء الصفة.',
|
||||
'categories' => 'Categories',
|
||||
'images' => 'Images',
|
||||
'inventories' => 'Inventories',
|
||||
'variations' => 'Variations',
|
||||
'downloadable' => 'Downloadable Information',
|
||||
'links' => 'Links',
|
||||
'add-link-btn-title' => 'Add Link',
|
||||
'samples' => 'Samples',
|
||||
'add-sample-btn-title' => 'Add Sample',
|
||||
'downloads' => 'Download Allowed',
|
||||
'file' => 'File',
|
||||
'sample' => 'Sample',
|
||||
'upload-file' => 'Upload File',
|
||||
'url' => 'Url',
|
||||
'sort-order' => 'Sort Order',
|
||||
'browse-file' => 'Browse File',
|
||||
'product-link' => 'Linked Products',
|
||||
'cross-selling' => 'Cross Selling',
|
||||
'up-selling' => 'Up Selling',
|
||||
'related-products' => 'Related Products',
|
||||
'product-search-hint' => 'Start typing product name',
|
||||
'no-result-found' => 'Products not found with same name.',
|
||||
'searching' => 'Searching ...',
|
||||
'grouped-products' => 'Grouped Products',
|
||||
'search-products' => 'Search Products',
|
||||
'no-result-found' => 'Products not found with same name.'
|
||||
],
|
||||
'attributes' => [
|
||||
'title' => 'الصفات',
|
||||
|
|
|
|||
|
|
@ -408,7 +408,10 @@ return [
|
|||
'related-products' => 'Related Products',
|
||||
'product-search-hint' => 'Start typing product name',
|
||||
'no-result-found' => 'Products not found with same name.',
|
||||
'searching' => 'Searching ...'
|
||||
'searching' => 'Searching ...',
|
||||
'grouped-products' => 'Grouped Products',
|
||||
'search-products' => 'Search Products',
|
||||
'no-result-found' => 'Products not found with same name.'
|
||||
],
|
||||
|
||||
'attributes' => [
|
||||
|
|
|
|||
|
|
@ -362,7 +362,34 @@ return [
|
|||
'variant-already-exist-message' => 'Variante com as mesmas opções de atributo já existe.',
|
||||
'add-image-btn-title' => 'Add Imagem',
|
||||
'mass-delete-success' => 'Todos os índices de produtos selecionados foram excluídos com sucesso',
|
||||
'mass-update-success' => 'Todo o índice selecionado de produtos foi atualizado com sucesso'
|
||||
'mass-update-success' => 'Todo o índice selecionado de produtos foi atualizado com sucesso',
|
||||
'configurable-error' => 'Please select atleast one configurable attribute.',
|
||||
'categories' => 'Categories',
|
||||
'images' => 'Images',
|
||||
'inventories' => 'Inventories',
|
||||
'variations' => 'Variations',
|
||||
'downloadable' => 'Downloadable Information',
|
||||
'links' => 'Links',
|
||||
'add-link-btn-title' => 'Add Link',
|
||||
'samples' => 'Samples',
|
||||
'add-sample-btn-title' => 'Add Sample',
|
||||
'downloads' => 'Download Allowed',
|
||||
'file' => 'File',
|
||||
'sample' => 'Sample',
|
||||
'upload-file' => 'Upload File',
|
||||
'url' => 'Url',
|
||||
'sort-order' => 'Sort Order',
|
||||
'browse-file' => 'Browse File',
|
||||
'product-link' => 'Linked Products',
|
||||
'cross-selling' => 'Cross Selling',
|
||||
'up-selling' => 'Up Selling',
|
||||
'related-products' => 'Related Products',
|
||||
'product-search-hint' => 'Start typing product name',
|
||||
'no-result-found' => 'Products not found with same name.',
|
||||
'searching' => 'Searching ...',
|
||||
'grouped-products' => 'Grouped Products',
|
||||
'search-products' => 'Search Products',
|
||||
'no-result-found' => 'Products not found with same name.'
|
||||
],
|
||||
|
||||
'attributes' => [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,209 @@
|
|||
@section('css')
|
||||
@parent
|
||||
<style>
|
||||
.table th.price, .table th.weight {
|
||||
width: 100px;
|
||||
}
|
||||
.table th.actions {
|
||||
width: 85px;
|
||||
}
|
||||
.table td.actions .icon {
|
||||
margin-top: 8px;
|
||||
}
|
||||
.table td.actions .icon.pencil-lg-icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
@stop
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.grouped_products.before', ['product' => $product]) !!}
|
||||
|
||||
<accordian :title="'{{ __('admin::app.catalog.products.grouped-products') }}'" :active="true">
|
||||
<div slot="body">
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.grouped_products.controls.before', ['product' => $product]) !!}
|
||||
|
||||
<grouped-product-list></grouped-product-list>
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.grouped_products.controls.after', ['product' => $product]) !!}
|
||||
|
||||
</div>
|
||||
</accordian>
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.grouped_products.after', ['product' => $product]) !!}
|
||||
|
||||
@push('scripts')
|
||||
@parent
|
||||
|
||||
<script type="text/x-template" id="grouped-product-list-template">
|
||||
<div>
|
||||
<div class="control-group">
|
||||
<label>{{ __('admin::app.catalog.products.search-products') }}</label>
|
||||
|
||||
<input type="text" class="control" placeholder="{{ __('admin::app.catalog.products.product-search-hint') }}" v-model.lazy="search_term" v-debounce="500" autocomplete="off">
|
||||
|
||||
<div class="linked-product-search-result">
|
||||
<ul>
|
||||
<li v-for='(product, index) in searched_results' v-if='searched_results.length' @click="addGroupedProduct(product)">
|
||||
@{{ product.name }}
|
||||
</li>
|
||||
|
||||
<li v-if='! searched_results.length && search_term.length && ! is_searching'>
|
||||
{{ __('admin::app.catalog.products.no-result-found') }}
|
||||
</li>
|
||||
|
||||
<li v-if="is_searching && search_term.length">
|
||||
{{ __('admin::app.catalog.products.searching') }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table" style="margin-top: 20px; overflow-x: unset;">
|
||||
<table>
|
||||
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="name">{{ __('admin::app.catalog.products.name') }}</th>
|
||||
<th class="sku">{{ __('admin::app.catalog.products.sku') }}</th>
|
||||
<th class="qty">{{ __('admin::app.catalog.products.qty') }}</th>
|
||||
<th class="sort-order">{{ __('admin::app.catalog.products.sort-order') }}</th>
|
||||
<th class="actions"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
<grouped-product-item v-for='(groupedProduct, index) in grouped_products' :grouped-product="groupedProduct" :key="index" :index="index" @onRemoveGroupedProduct="removeGroupedProduct($event)"></grouped-product-item>
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="grouped-product-item-template">
|
||||
<tr>
|
||||
<td>
|
||||
@{{ groupedProduct.associated_product.name }}
|
||||
<input type="hidden" :name="[inputName + '[associated_product_id]']" :value="groupedProduct.associated_product.id"/>
|
||||
</td>
|
||||
|
||||
<td>@{{ groupedProduct.associated_product.sku }}</td>
|
||||
|
||||
<td>
|
||||
<div class="control-group" :class="[errors.has(inputName + '[qty]') ? 'has-error' : '']">
|
||||
<input type="number" v-validate="'required|min_value:0'" :name="[inputName + '[qty]']" v-model="groupedProduct.qty" class="control" data-vv-as=""{{ __('admin::app.catalog.products.qty') }}""/>
|
||||
<span class="control-error" v-if="errors.has(inputName + '[qty]')">@{{ errors.first(inputName + '[qty]') }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div class="control-group" :class="[errors.has(inputName + '[sort_order]') ? 'has-error' : '']">
|
||||
<input type="number" v-validate="'required|min_value:0'" :name="[inputName + '[sort_order]']" v-model="groupedProduct.sort_order" class="control" data-vv-as=""{{ __('admin::app.catalog.products.sort-order') }}""/>
|
||||
<span class="control-error" v-if="errors.has(inputName + '[sort_order]')">@{{ errors.first(inputName + '[sort_order]') }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="actions">
|
||||
<i class="icon remove-icon" @click="removeGroupedProduct()"></i>
|
||||
</td>
|
||||
</tr>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('grouped-product-list', {
|
||||
|
||||
template: '#grouped-product-list-template',
|
||||
|
||||
inject: ['$validator'],
|
||||
|
||||
data: function() {
|
||||
return {
|
||||
search_term: '',
|
||||
|
||||
is_searching: false,
|
||||
|
||||
searched_results: [],
|
||||
|
||||
grouped_products: @json($product->grouped_products()->with('associated_product')->get())
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
'search_term': function(newVal, oldVal) {
|
||||
this.search('products')
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
addGroupedProduct: function(item, key) {
|
||||
this.grouped_products.push({
|
||||
associated_product: item,
|
||||
qty: 0,
|
||||
sort_order: 0
|
||||
});
|
||||
|
||||
this.search_term = '';
|
||||
|
||||
this.searched_result = [];
|
||||
},
|
||||
|
||||
removeGroupedProduct: function(groupedProduct) {
|
||||
let index = this.grouped_products.indexOf(groupedProduct)
|
||||
|
||||
this.grouped_products.splice(index, 1)
|
||||
},
|
||||
|
||||
search: function (key) {
|
||||
this.is_searching = true;
|
||||
|
||||
if (this.search_term.length < 3) {
|
||||
this.searched_results = [];
|
||||
|
||||
this.is_searching = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var this_this = this;
|
||||
|
||||
this.$http.get ("{{ route('admin.catalog.products.search_product_for_grouped_association', $product->id) }}", {params: {query: this.search_term}})
|
||||
.then (function(response) {
|
||||
this_this.searched_results = response.data;
|
||||
|
||||
this_this.is_searching = false;
|
||||
})
|
||||
.catch (function (error) {
|
||||
this_this.is_searching = false;
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Vue.component('grouped-product-item', {
|
||||
|
||||
template: '#grouped-product-item-template',
|
||||
|
||||
props: ['index', 'groupedProduct'],
|
||||
|
||||
inject: ['$validator'],
|
||||
|
||||
computed: {
|
||||
inputName: function () {
|
||||
if (this.groupedProduct.id)
|
||||
return "links[" + this.groupedProduct.id + "]";
|
||||
|
||||
return "links[link_" + this.index + "]";
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
removeGroupedProduct: function () {
|
||||
this.$emit('onRemoveGroupedProduct', this.groupedProduct)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
@{{ product.name }}
|
||||
</li>
|
||||
|
||||
<li v-if='!products[key].length && search_term[key].length && !is_searching[key]'>
|
||||
<li v-if='! products[key].length && search_term[key].length && ! is_searching[key]'>
|
||||
{{ __('admin::app.catalog.products.no-result-found') }}
|
||||
</li>
|
||||
|
||||
|
|
|
|||
|
|
@ -224,14 +224,18 @@
|
|||
@foreach ($order->items as $item)
|
||||
@if ($item->qty_to_invoice > 0)
|
||||
<tr>
|
||||
<td>{{ $item->type == 'configurable' ? $item->child->sku : $item->sku }}</td>
|
||||
<td>{{ $item->getTypeInstance()->getOrderedItem($item)->sku }}</td>
|
||||
<td>
|
||||
{{ $item->name }}
|
||||
|
||||
@if ($html = $item->getOptionDetailHtml())
|
||||
<p>{{ $html }}</p>
|
||||
@elseif ($item->type == 'downloadable')
|
||||
<p><b>Downloads : </b>{{ $item->getDownloadableDetailHtml() }}</p>
|
||||
@if (isset($item->additional['attributes']))
|
||||
<div class="item-options">
|
||||
|
||||
@foreach ($item->additional['attributes'] as $attribute)
|
||||
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $item->qty_ordered }}</td>
|
||||
|
|
|
|||
|
|
@ -174,14 +174,18 @@
|
|||
|
||||
@foreach ($invoice->items as $item)
|
||||
<tr>
|
||||
<td>{{ $item->child ? $item->child->sku : $item->sku }}</td>
|
||||
<td>{{ $item->getTypeInstance()->getOrderedItem($item)->sku }}</td>
|
||||
<td>
|
||||
{{ $item->name }}
|
||||
|
||||
@if ($html = $item->getOptionDetailHtml())
|
||||
<p>{{ $html }}</p>
|
||||
@elseif ($item->type == 'downloadable')
|
||||
<p><b>Downloads : </b>{{ $item->getDownloadableDetailHtml() }}</p>
|
||||
@if (isset($item->additional['attributes']))
|
||||
<div class="item-options">
|
||||
|
||||
@foreach ($item->additional['attributes'] as $attribute)
|
||||
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ core()->formatBasePrice($item->base_price) }}</td>
|
||||
|
|
|
|||
|
|
@ -229,15 +229,19 @@
|
|||
|
||||
@foreach ($invoice->items as $item)
|
||||
<tr>
|
||||
<td>{{ $item->child ? $item->child->sku : $item->sku }}</td>
|
||||
<td>{{ $item->getTypeInstance()->getOrderedItem($item)->sku }}</td>
|
||||
|
||||
<td>
|
||||
{{ $item->name }}
|
||||
|
||||
@if ($html = $item->getOptionDetailHtml())
|
||||
<p>{{ $html }}</p>
|
||||
@elseif ($item->type == 'downloadable')
|
||||
<p><b>Downloads : </b>{{ $item->getDownloadableDetailHtml() }}</p>
|
||||
|
||||
@if (isset($item->additional['attributes']))
|
||||
<div class="item-options">
|
||||
|
||||
@foreach ($item->additional['attributes'] as $attribute)
|
||||
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
|
|
|||
|
|
@ -250,16 +250,20 @@
|
|||
@foreach ($order->items as $item)
|
||||
<tr>
|
||||
<td>
|
||||
{{ $item->type == 'configurable' ? $item->child->sku : $item->sku }}
|
||||
{{ $item->getTypeInstance()->getOrderedItem($item)->sku }}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ $item->name }}
|
||||
|
||||
@if ($html = $item->getOptionDetailHtml())
|
||||
<p>{{ $html }}</p>
|
||||
@elseif ($item->type == 'downloadable')
|
||||
<p><b>Downloads : </b>{{ $item->getDownloadableDetailHtml() }}</p>
|
||||
@if (isset($item->additional['attributes']))
|
||||
<div class="item-options">
|
||||
|
||||
@foreach ($item->additional['attributes'] as $attribute)
|
||||
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
|
|
|||
|
|
@ -273,14 +273,18 @@
|
|||
@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->getTypeInstance()->getOrderedItem($item)->sku }}</td>
|
||||
<td>
|
||||
{{ $item->name }}
|
||||
|
||||
@if ($html = $item->getOptionDetailHtml())
|
||||
<p>{{ $html }}</p>
|
||||
@elseif ($item->type == 'downloadable')
|
||||
<p><b>Downloads : </b>{{ $item->getDownloadableDetailHtml() }}</p>
|
||||
|
||||
@if (isset($item->additional['attributes']))
|
||||
<div class="item-options">
|
||||
|
||||
@foreach ($item->additional['attributes'] as $attribute)
|
||||
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $item->qty_ordered }}</td>
|
||||
|
|
@ -304,18 +308,11 @@
|
|||
</td>
|
||||
|
||||
<td>
|
||||
<?php
|
||||
if ($item->type == 'configurable') {
|
||||
$sourceQty = $item->child->product->inventory_source_qty($inventorySource);
|
||||
} else {
|
||||
$sourceQty = $item->product->inventory_source_qty($inventorySource);
|
||||
}
|
||||
?>
|
||||
|
||||
<?php
|
||||
$sourceQty = 0;
|
||||
$product = $item->getTypeInstance()->getOrderedItem($item)->product;
|
||||
|
||||
$product = $item->type == 'configurable' ? $item->child->product : $item->product;
|
||||
$sourceQty = $product->inventory_source_qty($inventorySource);
|
||||
|
||||
foreach ($product->inventories as $inventory) {
|
||||
if ($inventory->inventory_source_id == $inventorySource->id) {
|
||||
|
|
|
|||
|
|
@ -251,11 +251,15 @@
|
|||
<td>{{ $item->sku }}</td>
|
||||
<td>
|
||||
{{ $item->name }}
|
||||
|
||||
@if ($html = $item->getOptionDetailHtml())
|
||||
<p>{{ $html }}</p>
|
||||
@elseif ($item->type == 'downloadable')
|
||||
<p><b>Downloads : </b>{{ $item->getDownloadableDetailHtml() }}</p>
|
||||
|
||||
@if (isset($item->additional['attributes']))
|
||||
<div class="item-options">
|
||||
|
||||
@foreach ($item->additional['attributes'] as $attribute)
|
||||
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $item->qty }}</td>
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class AttributeController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -53,7 +53,7 @@ class AttributeController extends Controller
|
|||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
@ -88,7 +88,7 @@ class AttributeController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class AttributeFamilyController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -66,7 +66,7 @@ class AttributeFamilyController extends Controller
|
|||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
@ -100,7 +100,7 @@ class AttributeFamilyController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class CategoryController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -54,7 +54,7 @@ class CategoryController extends Controller
|
|||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
@ -100,7 +100,7 @@ class CategoryController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use Webkul\Checkout\Models\CartPayment;
|
|||
use Webkul\Customer\Repositories\WishlistRepository;
|
||||
use Webkul\Customer\Repositories\CustomerAddressRepository;
|
||||
use Webkul\Product\Helpers\Price;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
|
||||
/**
|
||||
* Facades handler for all the methods to be implemented in Cart.
|
||||
|
|
@ -121,7 +122,7 @@ class Cart {
|
|||
/**
|
||||
* Return current logged in customer
|
||||
*
|
||||
* @return Customer | Boolean
|
||||
* @return Customer|boolean
|
||||
*/
|
||||
public function getCurrentCustomer()
|
||||
{
|
||||
|
|
@ -130,15 +131,62 @@ class Cart {
|
|||
return auth()->guard($guard);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Items in a cart with some cart and item details.
|
||||
*
|
||||
* @param integer $productId
|
||||
* @param array $data
|
||||
* @return Cart
|
||||
*/
|
||||
public function addProduct($productId, $data)
|
||||
{
|
||||
Event::fire('checkout.cart.add.before', $productId);
|
||||
|
||||
$cart = $this->getCart();
|
||||
|
||||
if (! $cart && ! $cart = $this->create($data))
|
||||
return;
|
||||
|
||||
$product = $this->productRepository->findOneByField('id', $productId);
|
||||
|
||||
$cartProducts = $product->getTypeInstance()->prepareForCart($data);
|
||||
|
||||
if (is_string($cartProducts)) {
|
||||
throw new \Exception($cartProducts);
|
||||
} else {
|
||||
$parentCartItem = null;
|
||||
|
||||
foreach ($cartProducts as $cartProduct) {
|
||||
$cartItem = $this->getItemByProduct($cartProduct);
|
||||
|
||||
if (isset($cartProduct['parent_id']))
|
||||
$cartProduct['parent_id'] = $parentCartItem->id;
|
||||
|
||||
if (! $cartItem) {
|
||||
$cartItem = $this->cartItemRepository->create(array_merge($cartProduct, ['cart_id' => $cart->id]));
|
||||
} else {
|
||||
$cartItem = $this->cartItemRepository->update($cartProduct, $cartItem->id);
|
||||
}
|
||||
|
||||
if (! $parentCartItem)
|
||||
$parentCartItem = $cartItem;
|
||||
}
|
||||
}
|
||||
|
||||
Event::fire('checkout.cart.add.after', $cart);
|
||||
|
||||
$this->collectTotals();
|
||||
|
||||
return $cart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new cart instance.
|
||||
*
|
||||
* @param integer $id
|
||||
* @param array $data
|
||||
*
|
||||
* @return Boolean
|
||||
* @param array $data
|
||||
* @return Cart|null
|
||||
*/
|
||||
public function create($id, $data, $qty = 1)
|
||||
public function create($data)
|
||||
{
|
||||
$cartData = [
|
||||
'channel_id' => core()->getCurrentChannel()->id,
|
||||
|
|
@ -160,392 +208,192 @@ class Cart {
|
|||
$cartData['is_guest'] = 1;
|
||||
}
|
||||
|
||||
$result = $this->cartRepository->create($cartData);
|
||||
$cart = $this->cartRepository->create($cartData);
|
||||
|
||||
$this->putCart($result);
|
||||
|
||||
if ($result) {
|
||||
if ($item = $this->createItem($id, $data))
|
||||
return $item;
|
||||
else
|
||||
return false;
|
||||
} else {
|
||||
if (! $cart) {
|
||||
session()->flash('error', trans('shop::app.checkout.cart.create-error'));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->putCart($cart);
|
||||
|
||||
return $cart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Items in a cart with some cart and item details.
|
||||
* Update cart items information
|
||||
*
|
||||
* @param integer $id
|
||||
* @param array $data
|
||||
* @param array $data
|
||||
*
|
||||
* @return void
|
||||
* @return string|boolean
|
||||
*/
|
||||
public function add($id, $data)
|
||||
public function updateItems($data)
|
||||
{
|
||||
$cart = $this->getCart();
|
||||
foreach ($data['qty'] as $itemId => $quantity) {
|
||||
$item = $this->cartItemRepository->findOneByField('id', $itemId);
|
||||
|
||||
if (! $item)
|
||||
continue;
|
||||
|
||||
if ($cart != null) {
|
||||
$ifExists = $this->checkIfItemExists($id, $data);
|
||||
if ($quantity <= 0) {
|
||||
$this->removeItem($itemId);
|
||||
|
||||
if ($ifExists) {
|
||||
$item = $this->cartItemRepository->findOneByField('id', $ifExists);
|
||||
|
||||
$data['quantity'] = $data['quantity'] + $item->quantity;
|
||||
|
||||
$result = $this->updateItem($id, $data, $ifExists);
|
||||
} else {
|
||||
$result = $this->createItem($id, $data);
|
||||
throw new \Exception(trans('shop::app.checkout.cart.quantity.illegal'));
|
||||
}
|
||||
|
||||
return $result;
|
||||
} else {
|
||||
return $this->create($id, $data);
|
||||
if ($item->product->isStockable() && ! $item->product->haveSufficientQuantity($quantity))
|
||||
throw new \Exception(trans('shop::app.checkout.cart.quantity.inventory_warning'));
|
||||
|
||||
Event::fire('checkout.cart.update.before', $item);
|
||||
|
||||
$this->cartItemRepository->update([
|
||||
'quantity' => $quantity,
|
||||
'total' => core()->convertPrice($item->price * $quantity),
|
||||
'base_total' => $item->price * $quantity,
|
||||
'total_weight' => $item->weight * $quantity,
|
||||
'base_total_weight' => $item->weight * $quantity
|
||||
], $itemId);
|
||||
|
||||
Event::fire('checkout.cart.update.after', $item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* To check if the items exists in the cart or not
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function checkIfItemExists($id, $data)
|
||||
{
|
||||
$items = $this->getCart()->items;
|
||||
|
||||
foreach ($items as $item) {
|
||||
if ($id == $item->product_id) {
|
||||
$product = $this->productRepository->findOnebyField('id', $id);
|
||||
|
||||
if ($product->type == 'configurable') {
|
||||
$variant = $this->productRepository->findOneByField('id', $data['selected_configurable_option']);
|
||||
|
||||
if ($item->child->product_id == $data['selected_configurable_option'])
|
||||
return $item->id;
|
||||
} else if ($product->type == 'downloadable') {
|
||||
// if ($data['links'] == $item->additional['links'])
|
||||
return $item->id;
|
||||
} else {
|
||||
return $item->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the item based on the type of product whether simple or configurable
|
||||
*
|
||||
* @return Mixed Array $item || Error
|
||||
*/
|
||||
public function createItem($id, $data)
|
||||
{
|
||||
$childProduct = $configurable = false;
|
||||
|
||||
$product = $this->productRepository->findOneByField('id', $id);
|
||||
|
||||
if ($product->type == 'configurable') {
|
||||
if (! isset($data['selected_configurable_option']) || ! $data['selected_configurable_option']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$childProduct = $this->productRepository->findOneByField('id', $data['selected_configurable_option']);
|
||||
|
||||
if (! $childProduct->haveSufficientQuantity($data['quantity'])) {
|
||||
session()->flash('warning', trans('shop::app.checkout.cart.quantity.inventory_warning'));
|
||||
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ($product->isStockable() && ! $product->haveSufficientQuantity($data['quantity'])) {
|
||||
session()->flash('warning', trans('shop::app.checkout.cart.quantity.inventory_warning'));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Check if the product's information is proper or not
|
||||
if (! isset($data['product']) || ! isset($data['quantity'])) {
|
||||
session()->flash('error', trans('shop::app.checkout.cart.integrity.missing_fields'));
|
||||
|
||||
return false;
|
||||
} else {
|
||||
if ($product->type == 'configurable' && ! isset($data['super_attribute'])) {
|
||||
session()->flash('error', trans('shop::app.checkout.cart.integrity.missing_options'));
|
||||
|
||||
return false;
|
||||
} else if ($product->type == 'downloadable' && (! isset($data['links']) || ! count($data['links']))) {
|
||||
throw new \Exception('shop::app.checkout.cart.integrity.missing_links');
|
||||
}
|
||||
}
|
||||
|
||||
$child = $childData = null;
|
||||
$additional = [];
|
||||
|
||||
$price = $this->price->getMinimalPrice($product->type == 'configurable' ? $childProduct : $product);
|
||||
|
||||
if ($product->type == 'configurable') {
|
||||
$weight = $childProduct->weight;
|
||||
} else {
|
||||
$weight = $product->isStockable() ? $product->weight : 0;
|
||||
}
|
||||
|
||||
$parentData = [
|
||||
'sku' => $product->sku,
|
||||
'quantity' => $data['quantity'],
|
||||
'cart_id' => $this->getCart()->id,
|
||||
'name' => $product->name,
|
||||
'price' => core()->convertPrice($price),
|
||||
'base_price' => $price,
|
||||
'total' => core()->convertPrice($price * $data['quantity']),
|
||||
'base_total' => $price * $data['quantity'],
|
||||
'weight' => $weight,
|
||||
'total_weight' => $weight * $data['quantity'],
|
||||
'base_total_weight' => $weight * $data['quantity'],
|
||||
'additional' => $additional,
|
||||
'type' => $product->type,
|
||||
'product_id' => $product->id,
|
||||
'additional' => $data,
|
||||
];
|
||||
|
||||
if ($product->type == 'configurable') {
|
||||
$attributeDetails = $this->getProductAttributeOptionDetails($childProduct);
|
||||
unset($attributeDetails['html']);
|
||||
|
||||
$parentData['additional'] = array_merge($parentData['additional'], $attributeDetails);
|
||||
|
||||
$childData = [
|
||||
'product_id' => (int) $data['selected_configurable_option'],
|
||||
'sku' => $childProduct->sku,
|
||||
'name' => $childProduct->name,
|
||||
'type' => 'simple',
|
||||
'cart_id' => $this->getCart()->id
|
||||
];
|
||||
} else if ($product->type == 'downloadable') {
|
||||
$parentData['additional'] = array_merge($parentData['additional'], ['link_lables' => $this->getDownloadableDetails($product)]);
|
||||
}
|
||||
|
||||
$item = $this->cartItemRepository->create($parentData);
|
||||
|
||||
if (is_array($childData)) {
|
||||
$childData['parent_id'] = $item->id;
|
||||
|
||||
$this->cartItemRepository->create($childData);
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the cartItem on cart checkout page and if already added item is added again
|
||||
*
|
||||
* @param $id product_id of cartItem instance
|
||||
* @param $data new requested quantities by customer
|
||||
* @param $itemId is id from cartItem instance
|
||||
* @return boolean
|
||||
*/
|
||||
public function updateItem($id, $data, $itemId)
|
||||
{
|
||||
$item = $this->cartItemRepository->findOneByField('id', $itemId);
|
||||
|
||||
$additional = isset($data['product']) ? $data : $item->additional;
|
||||
|
||||
if ($item->type == 'configurable') {
|
||||
$product = $this->productRepository->findOneByField('id', $item->child->product_id);
|
||||
|
||||
if (! $product->haveSufficientQuantity($data['quantity'])) {
|
||||
session()->flash('warning', trans('shop::app.checkout.cart.quantity.inventory_warning'));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$attributeDetails = $this->getProductAttributeOptionDetails($product);
|
||||
unset($attributeDetails['html']);
|
||||
|
||||
$additional = array_merge($additional, $attributeDetails);
|
||||
} else if ($item->type == 'downloadable') {
|
||||
$additional = array_merge($additional, ['link_lables' => $this->getDownloadableDetails($item)]);
|
||||
} else {
|
||||
$product = $this->productRepository->findOneByField('id', $item->product_id);
|
||||
|
||||
if ($product->isStockable() && ! $product->haveSufficientQuantity($data['quantity'])) {
|
||||
session()->flash('warning', trans('shop::app.checkout.cart.quantity.inventory_warning'));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$quantity = $data['quantity'];
|
||||
|
||||
$result = $item->update([
|
||||
'quantity' => $quantity,
|
||||
'total' => core()->convertPrice($item->price * ($quantity)),
|
||||
'base_total' => $item->price * ($quantity),
|
||||
'total_weight' => $item->weight * ($quantity),
|
||||
'base_total_weight' => $item->weight * ($quantity),
|
||||
'additional' => $additional
|
||||
]);
|
||||
|
||||
$this->collectTotals();
|
||||
|
||||
if ($result) {
|
||||
session()->flash('success', trans('shop::app.checkout.cart.quantity.success'));
|
||||
return true;
|
||||
}
|
||||
|
||||
return $item;
|
||||
} else {
|
||||
session()->flash('warning', trans('shop::app.checkout.cart.quantity.error'));
|
||||
/**
|
||||
* Get cart item by product
|
||||
*
|
||||
* @param array $data
|
||||
* @return CartItem|void
|
||||
*/
|
||||
public function getItemByProduct($data)
|
||||
{
|
||||
$items = $this->getCart()->all_items;
|
||||
|
||||
return false;
|
||||
foreach ($items as $item) {
|
||||
if ($item->product->getTypeInstance()->compareOptions($item->additional, $data['additional']))
|
||||
return $item;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the item from the cart
|
||||
*
|
||||
* @return response
|
||||
* @param integer $itemId
|
||||
* @return boolean
|
||||
*/
|
||||
public function removeItem($itemId)
|
||||
{
|
||||
if ($cart = $this->getCart()) {
|
||||
$this->cartItemRepository->delete($itemId);
|
||||
Event::fire('checkout.cart.delete.before', $itemId);
|
||||
|
||||
//delete the cart instance if no items are there
|
||||
if ($cart->items()->get()->count() == 0) {
|
||||
$this->cartRepository->delete($cart->id);
|
||||
if (! $cart = $this->getCart())
|
||||
return false;
|
||||
|
||||
// $this->deActivateCart();
|
||||
if (session()->has('cart')) {
|
||||
session()->forget('cart');
|
||||
}
|
||||
$this->cartItemRepository->delete($itemId);
|
||||
|
||||
//delete the cart instance if no items are there
|
||||
if ($cart->items()->get()->count() == 0) {
|
||||
$this->cartRepository->delete($cart->id);
|
||||
|
||||
if (session()->has('cart')) {
|
||||
session()->forget('cart');
|
||||
}
|
||||
|
||||
session()->flash('success', trans('shop::app.checkout.cart.item.success-remove'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
Event::fire('checkout.cart.delete.after', $itemId);
|
||||
|
||||
$this->collectTotals();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function handles when guest has some of cart products and then logs in.
|
||||
*
|
||||
* @return Response
|
||||
* @return boolean
|
||||
*/
|
||||
public function mergeCart()
|
||||
{
|
||||
if (session()->has('cart')) {
|
||||
$cart = $this->cartRepository->findWhere(['customer_id' => $this->getCurrentCustomer()->user()->id, 'is_active' => 1]);
|
||||
|
||||
$cart = $cart->count() ? $cart->first() : false;
|
||||
$cart = $this->cartRepository->findOneWhere(['customer_id' => $this->getCurrentCustomer()->user()->id, 'is_active' => 1]);
|
||||
|
||||
$guestCart = session()->get('cart');
|
||||
|
||||
//when the logged in customer is not having any of the cart instance previously and are active.
|
||||
if (! $cart) {
|
||||
$guestCart->update([
|
||||
$this->cartRepository->update([
|
||||
'customer_id' => $this->getCurrentCustomer()->user()->id,
|
||||
'is_guest' => 0,
|
||||
'customer_first_name' => $this->getCurrentCustomer()->user()->first_name,
|
||||
'customer_last_name' => $this->getCurrentCustomer()->user()->last_name,
|
||||
'customer_email' => $this->getCurrentCustomer()->user()->email
|
||||
]);
|
||||
], $guestCart->id);
|
||||
|
||||
session()->forget('cart');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$cartItems = $cart->items;
|
||||
foreach ($guestCart->items as $key => $guestCartItem) {
|
||||
$found = false;
|
||||
foreach ($cart->items as $cartItem) {
|
||||
if (! $cartItem->product->getTypeInstance()->compareOptions($cartItem->additional, $guestCartItem->additional))
|
||||
continue;
|
||||
|
||||
$guestCartId = $guestCart->id;
|
||||
|
||||
$guestCartItems = $this->cartRepository->findOneByField('id', $guestCartId)->items;
|
||||
|
||||
foreach ($guestCartItems as $key => $guestCartItem) {
|
||||
foreach ($cartItems as $cartItem) {
|
||||
|
||||
if ($guestCartItem->type == "configurable" && $cartItem->type == "configurable") {
|
||||
$guestCartItemChild = $guestCartItem->child;
|
||||
|
||||
$cartItemChild = $cartItem->child;
|
||||
|
||||
if ($guestCartItemChild->product_id != $cartItemChild->product_id)
|
||||
continue;
|
||||
|
||||
$prevQty = $guestCartItem->quantity;
|
||||
$newQty = $cartItem->quantity;
|
||||
|
||||
$product = $this->productRepository->findOneByField('id', $cartItem->child->product_id);
|
||||
|
||||
if ($product->isStockable() && ! $product->haveSufficientQuantity($prevQty + $newQty)) {
|
||||
$this->cartItemRepository->delete($guestCartItem->id);
|
||||
continue;
|
||||
}
|
||||
|
||||
$data['quantity'] = $newQty + $prevQty;
|
||||
|
||||
$this->updateItem($cartItem->product_id, $data, $cartItem->id);
|
||||
|
||||
$guestCartItems->forget($key);
|
||||
$newQuantity = $cartItem->quantity + $guestCartItem->quantity;
|
||||
|
||||
if ($cartItem->product->isStockable() && ! $cartItem->product->haveSufficientQuantity($newQuantity)) {
|
||||
$this->cartItemRepository->delete($guestCartItem->id);
|
||||
} else {
|
||||
if ($cartItem->product_id == $guestCartItem->product_id)
|
||||
continue;
|
||||
|
||||
$prevQty = $cartItem->quantity;
|
||||
$newQty = $guestCartItem->quantity;
|
||||
continue;
|
||||
}
|
||||
|
||||
$product = $this->productRepository->findOneByField('id', $cartItem->product_id);
|
||||
$this->cartItemRepository->update([
|
||||
'quantity' => $newQuantity,
|
||||
'total' => core()->convertPrice($cartItem->price * $newQuantity),
|
||||
'base_total' => $cartItem->price * $newQuantity,
|
||||
'total_weight' => $cartItem->weight * $newQuantity,
|
||||
'base_total_weight' => $cartItem->weight * $newQuantity
|
||||
], $cartItem->id);
|
||||
|
||||
if ($product->isStockable() && ! $product->haveSufficientQuantity($prevQty + $newQty)) {
|
||||
$this->cartItemRepository->delete($guestCartItem->id);
|
||||
$guestCart->items->forget($key);
|
||||
|
||||
continue;
|
||||
}
|
||||
$this->cartItemRepository->delete($guestCartItem->id);
|
||||
|
||||
$data['quantity'] = $newQty + $prevQty;
|
||||
$found = true;
|
||||
}
|
||||
|
||||
$this->updateItem($cartItem->product_id, $data, $cartItem->id);
|
||||
if (! $found) {
|
||||
$this->cartItemRepository->update([
|
||||
'cart_id' => $cart->id
|
||||
], $guestCartItem->id);
|
||||
|
||||
$guestCartItems->forget($key);
|
||||
$this->cartItemRepository->delete($guestCartItem->id);
|
||||
foreach ($guestCartItem->children as $child) {
|
||||
$this->cartItemRepository->update([
|
||||
'cart_id' => $cart->id
|
||||
], $child->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//now handle the products that are not removed from the list of items in the guest cart.
|
||||
foreach ($guestCartItems as $guestCartItem) {
|
||||
if ($guestCartItem->type == "configurable") {
|
||||
$guestCartItem->update(['cart_id' => $cart->id]);
|
||||
|
||||
$guestCartItem->child->update(['cart_id' => $cart->id]);
|
||||
} else{
|
||||
$guestCartItem->update(['cart_id' => $cart->id]);
|
||||
}
|
||||
}
|
||||
|
||||
//delete the guest cart instance.
|
||||
$this->cartRepository->delete($guestCartId);
|
||||
|
||||
//forget the guest cart instance
|
||||
session()->forget('cart');
|
||||
|
||||
$this->collectTotals();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return true;
|
||||
$this->cartRepository->delete($guestCart->id);
|
||||
|
||||
session()->forget('cart');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save cart
|
||||
*
|
||||
* @return mixed
|
||||
* @param Cart $cart
|
||||
* @return void
|
||||
*/
|
||||
public function putCart($cart)
|
||||
{
|
||||
|
|
@ -557,7 +405,7 @@ class Cart {
|
|||
/**
|
||||
* Returns cart
|
||||
*
|
||||
* @return mixed
|
||||
* @return Cart|null
|
||||
*/
|
||||
public function getCart()
|
||||
{
|
||||
|
|
@ -602,63 +450,11 @@ class Cart {
|
|||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the items details of the configurable and simple products
|
||||
*
|
||||
* @return Mixed
|
||||
*/
|
||||
public function getProductAttributeOptionDetails($product)
|
||||
{
|
||||
$data = [];
|
||||
|
||||
$labels = [];
|
||||
|
||||
foreach ($product->parent->super_attributes as $attribute) {
|
||||
$option = $attribute->options()->where('id', $product->{$attribute->code})->first();
|
||||
|
||||
$data['attributes'][$attribute->code] = [
|
||||
'attribute_name' => $attribute->name ? $attribute->name : $attribute->admin_name,
|
||||
'option_id' => $option->id,
|
||||
'option_label' => $option->label,
|
||||
];
|
||||
|
||||
$labels[] = ($attribute->name ? $attribute->name : $attribute->admin_name) . ' : ' . $option->label;
|
||||
}
|
||||
|
||||
$data['html'] = implode(', ', $labels);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the items details of the downloadable names
|
||||
*
|
||||
* @return Mixed
|
||||
*/
|
||||
public function getDownloadableDetails($item)
|
||||
{
|
||||
$labels = [];
|
||||
|
||||
if ($item instanceOf CartItem) {
|
||||
$links = $item->additional['links'];
|
||||
|
||||
$item = $item->product;
|
||||
} else {
|
||||
$links = request('links');
|
||||
}
|
||||
|
||||
foreach ($item->downloadable_links as $link) {
|
||||
if (in_array($link->id, $links))
|
||||
$labels[] = $link->title;
|
||||
}
|
||||
|
||||
return implode(', ', $labels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save customer address
|
||||
*
|
||||
* @return Mixed
|
||||
* @param array $data
|
||||
* @return boolean
|
||||
*/
|
||||
public function saveCustomerAddress($data)
|
||||
{
|
||||
|
|
@ -761,7 +557,7 @@ class Cart {
|
|||
* Save shipping method for cart
|
||||
*
|
||||
* @param string $shippingMethodCode
|
||||
* @return Mixed
|
||||
* @return boolean
|
||||
*/
|
||||
public function saveShippingMethod($shippingMethodCode)
|
||||
{
|
||||
|
|
@ -778,7 +574,7 @@ class Cart {
|
|||
* Save payment method for cart
|
||||
*
|
||||
* @param string $payment
|
||||
* @return Mixed
|
||||
* @return CartPayment
|
||||
*/
|
||||
public function savePaymentMethod($payment)
|
||||
{
|
||||
|
|
@ -806,9 +602,8 @@ class Cart {
|
|||
{
|
||||
$validated = $this->validateItems();
|
||||
|
||||
if (! $validated) {
|
||||
if (! $validated)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $cart = $this->getCart())
|
||||
return false;
|
||||
|
|
@ -859,70 +654,27 @@ class Cart {
|
|||
*/
|
||||
public function validateItems()
|
||||
{
|
||||
$cart = $this->getCart();
|
||||
|
||||
if (! $cart)
|
||||
return false;
|
||||
if (! $cart = $this->getCart())
|
||||
return;
|
||||
|
||||
//rare case of accident-->used when there are no items.
|
||||
if (count($cart->items) == 0) {
|
||||
$this->cartRepository->delete($cart->id);
|
||||
|
||||
|
||||
return false;
|
||||
} else {
|
||||
$items = $cart->items;
|
||||
foreach ($cart->items as $item) {
|
||||
if ($item->product_flat->getTypeInstance()->getMinimalPrice($item) == $item->price)
|
||||
continue;
|
||||
|
||||
foreach ($items as $item) {
|
||||
$productFlat = $item->product_flat;
|
||||
$price = ! is_null($item->custom_price) ? $item->custom_price : $this->price->getMinimalPrice($productFlat);
|
||||
|
||||
if ($productFlat->type == 'configurable') {
|
||||
if ($productFlat->sku != $item->sku) {
|
||||
$item->update(['sku' => $productFlat->sku]);
|
||||
|
||||
} else if ($productFlat->name != $item->name) {
|
||||
$item->update(['name' => $productFlat->name]);
|
||||
|
||||
} else if ($this->price->getMinimalPrice($item->child->product_flat) != $item->price) {
|
||||
// $price = (float) $item->custom_price ? $item->custom_price : $item->child->product->price;
|
||||
|
||||
if (! is_null($item->custom_price)) {
|
||||
$price = $item->custom_price;
|
||||
} else {
|
||||
$price = $this->price->getMinimalPrice($item->child->product_flat);
|
||||
}
|
||||
|
||||
$item->update([
|
||||
'price' => core()->convertPrice($price),
|
||||
'base_price' => $price,
|
||||
'total' => core()->convertPrice($price * ($item->quantity)),
|
||||
'base_total' => $price * ($item->quantity),
|
||||
]);
|
||||
}
|
||||
|
||||
} else {
|
||||
if ($productFlat->sku != $item->sku) {
|
||||
$item->update(['sku' => $productFlat->sku]);
|
||||
|
||||
} else if ($productFlat->name != $item->name) {
|
||||
$item->update(['name' => $productFlat->name]);
|
||||
|
||||
} else if ($this->price->getMinimalPrice($productFlat) != $item->price) {
|
||||
// $price = (float) $item->custom_price ? $item->custom_price : $item->product->price;
|
||||
|
||||
if (! is_null($item->custom_price)) {
|
||||
$price = $item->custom_price;
|
||||
} else {
|
||||
$price = $this->price->getMinimalPrice($productFlat);
|
||||
}
|
||||
|
||||
$item->update([
|
||||
'price' => core()->convertPrice($price),
|
||||
'base_price' => $price,
|
||||
'total' => core()->convertPrice($price * ($item->quantity)),
|
||||
'base_total' => $price * ($item->quantity),
|
||||
]);
|
||||
}
|
||||
}
|
||||
$this->cartItemRepository->update([
|
||||
'price' => core()->convertPrice($price),
|
||||
'base_price' => $price,
|
||||
'total' => core()->convertPrice($price * ($item->quantity)),
|
||||
'base_total' => $price * ($item->quantity),
|
||||
], $item->id);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -1012,16 +764,12 @@ class Cart {
|
|||
/**
|
||||
* Checks if all cart items have sufficient quantity.
|
||||
*
|
||||
* @param CartItem $item
|
||||
* @return boolean
|
||||
*/
|
||||
public function isItemHaveQuantity($item)
|
||||
{
|
||||
$product = $item->type == 'configurable' ? $item->child->product : $item->product;
|
||||
|
||||
if ($product->isStockable() && ! $product->haveSufficientQuantity($item->quantity))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return $item->product->getTypeInstance()->isItemHaveQuantity($item);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1096,6 +844,7 @@ class Cart {
|
|||
/**
|
||||
* Prepares data for order item
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function prepareDataForOrderItem($data)
|
||||
|
|
@ -1129,117 +878,70 @@ class Cart {
|
|||
}
|
||||
|
||||
/**
|
||||
* Move to Cart
|
||||
*
|
||||
* Move a wishlist item to cart
|
||||
*
|
||||
* @param WishlistItem $wishlistItem
|
||||
* @return boolean
|
||||
*/
|
||||
public function moveToCart($wishlistItem)
|
||||
{
|
||||
$product = $wishlistItem->product;
|
||||
|
||||
if ($product->getTypeInstance()->canBeMovedFromWishlistToCart()) {
|
||||
\Event::fire('checkout.cart.add.before', $product->id);
|
||||
|
||||
$result = $this->add($product->id, ['quantity' => 1, 'product' => $product->id]);
|
||||
|
||||
if ($result) {
|
||||
\Event::fire('checkout.cart.add.after', $result);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (! $wishlistItem->product->getTypeInstance()->canBeMovedFromWishlistToCart($wishlistItem))
|
||||
return false;
|
||||
|
||||
$result = $this->addProduct($wishlistItem->product_id, $wishlistItem->additional);
|
||||
|
||||
if ($result) {
|
||||
$this->wishlistRepository->delete($wishlistItem->id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to move a already added product to wishlist will run only on customer authentication.
|
||||
*
|
||||
* @param instance cartItem $id
|
||||
* @param integer $itemId
|
||||
* @return boolean|void
|
||||
*/
|
||||
public function moveToWishlist($itemId)
|
||||
{
|
||||
$cart = $this->getCart();
|
||||
|
||||
$wishlist = [
|
||||
'channel_id' => $cart->channel_id,
|
||||
'customer_id' => $this->getCurrentCustomer()->user()->id,
|
||||
];
|
||||
|
||||
foreach ($cart->items as $item) {
|
||||
if ($item->id == $itemId) {
|
||||
if ($item->type == 'configurable') {
|
||||
$wishlist['product_id'] = $item->child->product_id;
|
||||
$wishtlist['options'] = $item->additional;
|
||||
} else {
|
||||
$wishlist['product_id'] = $item->product_id;
|
||||
}
|
||||
|
||||
$shouldBe = $this->wishlistRepository->findWhere([
|
||||
'customer_id' => $this->getCurrentCustomer()->user()->id,
|
||||
'product_id' => $wishlist['product_id']
|
||||
]);
|
||||
|
||||
if ($shouldBe->isEmpty()) {
|
||||
$wishlist = $this->wishlistRepository->create($wishlist);
|
||||
}
|
||||
|
||||
$result = $this->cartItemRepository->delete($itemId);
|
||||
|
||||
if ($result) {
|
||||
if ($cart->items()->count() == 0)
|
||||
$this->cartRepository->delete($cart->id);
|
||||
|
||||
session()->flash('success', trans('shop::app.checkout.cart.move-to-wishlist-success'));
|
||||
|
||||
return $result;
|
||||
} else {
|
||||
session()->flash('success', trans('shop::app.checkout.cart.move-to-wishlist-error'));
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the buy now process for simple as well as configurable products
|
||||
*
|
||||
* @return response mixed
|
||||
*/
|
||||
public function proceedToBuyNow($id, $quantity)
|
||||
{
|
||||
$product = $this->productRepository->findOneByField('id', $id);
|
||||
|
||||
if ($product->type == 'configurable') {
|
||||
session()->flash('warning', trans('shop::app.buynow.no-options'));
|
||||
$cartItem = $cart->items()->find($itemId);
|
||||
|
||||
if (! $cartItem)
|
||||
return false;
|
||||
} else {
|
||||
$simpleOrVariant = $this->productRepository->find($id);
|
||||
|
||||
if ($simpleOrVariant->parent_id != null) {
|
||||
$parent = $simpleOrVariant->parent;
|
||||
$wishlistItems = $this->wishlistRepository->findWhere([
|
||||
'customer_id' => $this->getCurrentCustomer()->user()->id,
|
||||
'product_id' => $cartItem->product_id
|
||||
]);
|
||||
|
||||
$data['product'] = $parent->id;
|
||||
$data['selected_configurable_option'] = $simpleOrVariant->id;
|
||||
$data['quantity'] = $quantity;
|
||||
$data['super_attribute'] = 'From Buy Now';
|
||||
$found = false;
|
||||
|
||||
$result = $this->add($parent->id, $data);
|
||||
|
||||
return $result;
|
||||
} else {
|
||||
$data['product'] = $id;
|
||||
$data['is_configurable'] = false;
|
||||
$data['quantity'] = $quantity;
|
||||
|
||||
$result = $this->add($id, $data);
|
||||
|
||||
return $result;
|
||||
}
|
||||
foreach ($wishlistItems as $wishlistItem) {
|
||||
if ($cartItem->product->getTypeInstance()->compareOptions($cartItem->additional, $wishlistItem->item_options))
|
||||
$found = true;
|
||||
}
|
||||
|
||||
if (! $found) {
|
||||
$this->wishlistRepository->create([
|
||||
'channel_id' => $cart->channel_id,
|
||||
'customer_id' => $this->getCurrentCustomer()->user()->id,
|
||||
'product_id' => $cartItem->product_id,
|
||||
'additional' => $cartItem->additional
|
||||
]);
|
||||
}
|
||||
|
||||
$result = $this->cartItemRepository->delete($itemId);
|
||||
|
||||
if (! $cart->items()->count())
|
||||
$this->cartRepository->delete($cart->id);
|
||||
|
||||
$this->collectTotals();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -55,4 +55,12 @@ class CartItem extends Model implements CartItemContract
|
|||
{
|
||||
return $this->belongsTo(self::class, 'id', 'parent_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the children items.
|
||||
*/
|
||||
public function children()
|
||||
{
|
||||
return $this->hasMany(self::class, 'parent_id');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,14 +33,15 @@ class CartItemRepository extends Repository
|
|||
|
||||
public function update(array $data, $id, $attribute = "id")
|
||||
{
|
||||
$cartitems = $this->find($id);
|
||||
$item = $this->find($id);
|
||||
|
||||
$cartitems->update($data);
|
||||
$item->update($data);
|
||||
|
||||
return $cartitems;
|
||||
return $item;
|
||||
}
|
||||
|
||||
public function getProduct($cartItemId) {
|
||||
public function getProduct($cartItemId)
|
||||
{
|
||||
return $this->model->find($cartItemId)->product->id;
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ class ChannelController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -53,7 +53,7 @@ class ChannelController extends Controller
|
|||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
@ -94,7 +94,7 @@ class ChannelController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ class CountryStateController extends Controller
|
|||
/**
|
||||
* Function to retrieve states with respect to countries with codes and names for both of the countries and states.
|
||||
*
|
||||
* @return array
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function getCountries()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class CurrencyController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -53,7 +53,7 @@ class CurrencyController extends Controller
|
|||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
@ -87,7 +87,7 @@ class CurrencyController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class ExchangeRateController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -67,7 +67,7 @@ class ExchangeRateController extends Controller
|
|||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
@ -103,7 +103,7 @@ class ExchangeRateController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class LocaleController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -53,7 +53,7 @@ class LocaleController extends Controller
|
|||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
@ -87,7 +87,7 @@ class LocaleController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class SliderController extends Controller
|
|||
/**
|
||||
* Loads the index for the sliders settings.
|
||||
*
|
||||
* @return mixed
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -57,7 +57,7 @@ class SliderController extends Controller
|
|||
/**
|
||||
* Loads the form for creating slider.
|
||||
*
|
||||
* @return mixed
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
@ -92,7 +92,7 @@ class SliderController extends Controller
|
|||
/**
|
||||
* Edit the previously created slider item.
|
||||
*
|
||||
* @return mixed
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class SubscriptionController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -55,8 +55,7 @@ class SubscriptionController extends Controller
|
|||
* To unsubscribe the user without deleting the resource of the subscribed user
|
||||
*
|
||||
* @param integer $id
|
||||
*
|
||||
* @return mixed
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
@ -69,7 +68,6 @@ class SubscriptionController extends Controller
|
|||
* To unsubscribe the user without deleting the resource of the subscribed user
|
||||
*
|
||||
* @param integer $id
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function update($id)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ class AddNotesColumnInCustomersTable extends Migration
|
|||
public function down()
|
||||
{
|
||||
Schema::table('customers', function (Blueprint $table) {
|
||||
$table->dropColumn('notes');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddAdditionalCloumnInWishlistTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('wishlist', function (Blueprint $table) {
|
||||
$table->json('additional')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('wishlist', function (Blueprint $table) {
|
||||
//
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ class AccountController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class AddressController extends Controller
|
|||
/**
|
||||
* Address Route index page
|
||||
*
|
||||
* @return view
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -55,7 +55,7 @@ class AddressController extends Controller
|
|||
/**
|
||||
* Show the address create form
|
||||
*
|
||||
* @return view
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
@ -103,7 +103,7 @@ class AddressController extends Controller
|
|||
/**
|
||||
* For editing the existing addresses of current logged in customer
|
||||
*
|
||||
* @return view
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class CustomerController extends Controller
|
|||
/**
|
||||
* Taking the customer to profile details page
|
||||
*
|
||||
* @return View
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -57,7 +57,7 @@ class CustomerController extends Controller
|
|||
/**
|
||||
* For loading the edit form page.
|
||||
*
|
||||
* @return View
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit()
|
||||
{
|
||||
|
|
@ -116,7 +116,7 @@ class CustomerController extends Controller
|
|||
/**
|
||||
* Load the view for the customer account panel, showing approved reviews.
|
||||
*
|
||||
* @return Mixed
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function reviews()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class ForgotPasswordController extends Controller
|
|||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class RegistrationController extends Controller
|
|||
/**
|
||||
* Opens up the user's sign up form.
|
||||
*
|
||||
* @return view
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class ResetPasswordController extends Controller
|
|||
* If no token is present, display the link request form.
|
||||
*
|
||||
* @param string|null $token
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create($token = null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ class SessionController extends Controller
|
|||
/**
|
||||
* Display the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ class WishlistController extends Controller
|
|||
|
||||
/**
|
||||
* Displays the listing resources if the customer having items in wishlist.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -79,9 +81,8 @@ class WishlistController extends Controller
|
|||
{
|
||||
$product = $this->productRepository->findOneByField('id', $itemId);
|
||||
|
||||
if (! $product->status) {
|
||||
if (! $product->status)
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
$data = [
|
||||
'channel_id' => core()->getCurrentChannel()->id,
|
||||
|
|
@ -149,39 +150,31 @@ class WishlistController extends Controller
|
|||
*/
|
||||
public function move($itemId)
|
||||
{
|
||||
$wishlistItem = $this->wishlistRepository->findOneByField('id', $itemId);
|
||||
$wishlistItem = $this->wishlistRepository->findOneWhere([
|
||||
'id' => $itemId,
|
||||
'customer_id' => auth()->guard('customer')->user()->id
|
||||
]);
|
||||
|
||||
if (! isset($wishlistItem) || $wishlistItem->customer_id != auth()->guard('customer')->user()->id) {
|
||||
session()->flash('warning', trans('shop::app.security-warning'));
|
||||
|
||||
return redirect()->route('customer.wishlist.index');
|
||||
}
|
||||
if (! $wishlistItem)
|
||||
abort(404);
|
||||
|
||||
try {
|
||||
$result = Cart::moveToCart($wishlistItem);
|
||||
|
||||
if ($result) {
|
||||
session()->flash('success', trans('shop::app.wishlist.moved'));
|
||||
} else {
|
||||
session()->flash('info', trans('shop::app.wishlist.option-missing'));
|
||||
|
||||
return redirect()->route('shop.products.index', $wishlistItem->product->url_key);
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
} catch (\Exception $e) {
|
||||
session()->flash('warning', $e->getMessage());
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
if ($wishlistItem->delete()) {
|
||||
session()->flash('success', trans('shop::app.wishlist.moved'));
|
||||
|
||||
Cart::collectTotals();
|
||||
|
||||
return redirect()->back();
|
||||
} else {
|
||||
session()->flash('error', trans('shop::app.wishlist.move-error'));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
} else {
|
||||
session()->flash('info', trans('shop::app.wishlist.option-missing'));
|
||||
|
||||
return redirect()->route('shop.products.index', $wishlistItem->product->url_key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class VerificationEmail extends Mailable
|
|||
/**
|
||||
* Build the message.
|
||||
*
|
||||
* @return $this
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,9 +10,17 @@ class Wishlist extends Model implements WishlistContract
|
|||
{
|
||||
protected $table = 'wishlist';
|
||||
|
||||
protected $fillable = ['channel_id', 'product_id', 'customer_id', 'item_options','moved_to_cart','shared','time_of_moving'];
|
||||
protected $casts = [
|
||||
'additional' => 'array',
|
||||
];
|
||||
|
||||
public function product() {
|
||||
protected $fillable = ['channel_id', 'product_id', 'customer_id', 'additional', 'moved_to_cart', 'shared', 'time_of_moving'];
|
||||
|
||||
/**
|
||||
* The Product that belong to the wishlist.
|
||||
*/
|
||||
public function product()
|
||||
{
|
||||
return $this->hasOne(ProductProxy::modelClass(), 'id', 'product_id');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ class CartRuleController extends Controller
|
|||
}
|
||||
|
||||
/**
|
||||
* @return view
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -71,7 +71,7 @@ class CartRuleController extends Controller
|
|||
}
|
||||
|
||||
/**
|
||||
* @return view
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
@ -277,7 +277,7 @@ class CartRuleController extends Controller
|
|||
}
|
||||
|
||||
/**
|
||||
* @return view
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class InventorySourceController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -53,7 +53,7 @@ class InventorySourceController extends Controller
|
|||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
@ -99,7 +99,7 @@ class InventorySourceController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class StandardController extends Controller
|
|||
/**
|
||||
* Redirects to the paypal.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function redirect()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ return [
|
|||
'name' => 'Simple',
|
||||
'class' => 'Webkul\Product\Type\Simple',
|
||||
'sort' => 1
|
||||
|
||||
],
|
||||
'configurable' => [
|
||||
'key' => 'configurable',
|
||||
|
|
@ -20,10 +19,16 @@ return [
|
|||
'class' => 'Webkul\Product\Type\Virtual',
|
||||
'sort' => 3
|
||||
],
|
||||
'grouped' => [
|
||||
'key' => 'grouped',
|
||||
'name' => 'Grouped',
|
||||
'class' => 'Webkul\Product\Type\Grouped',
|
||||
'sort' => 4
|
||||
],
|
||||
'downloadable' => [
|
||||
'key' => 'downloadable',
|
||||
'name' => 'Downloadable',
|
||||
'class' => 'Webkul\Product\Type\Downloadable',
|
||||
'sort' => 4
|
||||
'sort' => 5
|
||||
]
|
||||
];
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Contracts;
|
||||
|
||||
interface ProductGroupedProduct
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateProductGroupedProductsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('product_grouped_products', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('qty')->default(0);
|
||||
$table->integer('sort_order')->default(0);
|
||||
|
||||
$table->integer('product_id')->unsigned();
|
||||
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
|
||||
|
||||
$table->integer('associated_product_id')->unsigned();
|
||||
$table->foreign('associated_product_id')->references('id')->on('products')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('product_grouped_products');
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,12 @@ use Webkul\Product\Models\ProductAttributeValue;
|
|||
use Webkul\Product\Models\ProductFlatProxy;
|
||||
use Webkul\Product\Models\ProductFlat;
|
||||
|
||||
/**
|
||||
* Abstract Product Helper
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
abstract class AbstractProduct
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -8,6 +8,12 @@ use Webkul\Product\Helpers\Price;
|
|||
use Webkul\Product\Models\Product;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
|
||||
/**
|
||||
* Configurable Option Helper
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class ConfigurableOption extends AbstractProduct
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Helpers;
|
||||
|
||||
use Webkul\Product\Repositories\ProductGroupedProductRepository;
|
||||
|
||||
/**
|
||||
* Grouped Product Helper
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class GroupedProduct extends AbstractProduct
|
||||
{
|
||||
/**
|
||||
* ProductGroupedProductRepository object
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $productGroupedProductRepository;
|
||||
|
||||
/**
|
||||
* Create a new helper instance.
|
||||
*
|
||||
* @param Webkul\Product\Repositories\ProductGroupedProductRepository $productGroupedProductRepository
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(ProductGroupedProductRepository $productGroupedProductRepository)
|
||||
{
|
||||
$this->productGroupedProductRepository = $productGroupedProductRepository;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,12 @@ use Webkul\Product\Models\ProductAttributeValue;
|
|||
use Webkul\Product\Models\Product;
|
||||
use Webkul\Product\Models\ProductFlat;
|
||||
|
||||
/**
|
||||
* Price Helper
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class Price extends AbstractProduct
|
||||
{
|
||||
/**
|
||||
|
|
@ -60,6 +66,7 @@ class Price extends AbstractProduct
|
|||
public function getVariantMinPrice($product)
|
||||
{
|
||||
static $price = [];
|
||||
|
||||
$finalPrice = [];
|
||||
|
||||
if (array_key_exists($product->id, $price))
|
||||
|
|
@ -122,9 +129,8 @@ class Price extends AbstractProduct
|
|||
if (is_null($product->special_price) || ! (float) $product->special_price)
|
||||
return false;
|
||||
|
||||
if (core()->isChannelDateInInterval($product->special_price_from, $product->special_price_to)) {
|
||||
if (core()->isChannelDateInInterval($product->special_price_from, $product->special_price_to))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,12 @@ namespace Webkul\Product\Helpers;
|
|||
use Webkul\Attribute\Repositories\AttributeOptionRepository as AttributeOption;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
/**
|
||||
* Product Image Helper
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class ProductImage extends AbstractProduct
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
namespace Webkul\Product\Helpers;
|
||||
use DB;
|
||||
|
||||
/**
|
||||
* Product Review Helper
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class Review extends AbstractProduct
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@
|
|||
|
||||
namespace Webkul\Product\Helpers;
|
||||
|
||||
/**
|
||||
* Toolbar Helper
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class Toolbar extends AbstractProduct
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@
|
|||
|
||||
namespace Webkul\Product\Helpers;
|
||||
|
||||
/**
|
||||
* Product View Helper
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class View extends AbstractProduct
|
||||
{
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use Webkul\Category\Repositories\CategoryRepository;
|
|||
use Webkul\Product\Repositories\ProductRepository;
|
||||
use Webkul\Product\Repositories\ProductDownloadableLinkRepository;
|
||||
use Webkul\Product\Repositories\ProductDownloadableSampleRepository;
|
||||
use Webkul\Product\Repositories\ProductGroupedProductRepository;
|
||||
use Webkul\Attribute\Repositories\AttributeFamilyRepository;
|
||||
use Webkul\Inventory\Repositories\InventorySourceRepository;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
|
@ -69,6 +70,13 @@ class ProductController extends Controller
|
|||
*/
|
||||
protected $inventorySourceRepository;
|
||||
|
||||
/**
|
||||
* ProductGroupedProductRepository object
|
||||
*
|
||||
* @var Object
|
||||
*/
|
||||
protected $productGroupedProductRepository;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
|
|
@ -78,6 +86,7 @@ class ProductController extends Controller
|
|||
* @param \Webkul\Product\Repositories\ProductDownloadableSampleRepository $productDownloadableSampleRepository
|
||||
* @param \Webkul\Attribute\Repositories\AttributeFamilyRepository $attributeFamilyRepository
|
||||
* @param \Webkul\Inventory\Repositories\InventorySourceRepository $inventorySource
|
||||
* @param \Webkul\Inventory\Repositories\ProductGroupedProductRepository $productGroupedProductRepository
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
|
|
@ -86,7 +95,8 @@ class ProductController extends Controller
|
|||
ProductDownloadableLinkRepository $productDownloadableLinkRepository,
|
||||
ProductDownloadableSampleRepository $productDownloadableSampleRepository,
|
||||
AttributeFamilyRepository $attributeFamilyRepository,
|
||||
InventorySourceRepository $inventorySourceRepository
|
||||
InventorySourceRepository $inventorySourceRepository,
|
||||
ProductGroupedProductRepository $productGroupedProductRepository
|
||||
)
|
||||
{
|
||||
$this->_config = request('_config');
|
||||
|
|
@ -102,12 +112,14 @@ class ProductController extends Controller
|
|||
$this->attributeFamilyRepository = $attributeFamilyRepository;
|
||||
|
||||
$this->inventorySourceRepository = $inventorySourceRepository;
|
||||
|
||||
$this->productGroupedProductRepository = $productGroupedProductRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -117,7 +129,7 @@ class ProductController extends Controller
|
|||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
|
|
@ -172,7 +184,7 @@ class ProductController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
@ -317,7 +329,7 @@ class ProductController extends Controller
|
|||
/**
|
||||
* Result of search product.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View | \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function productLinkSearch()
|
||||
{
|
||||
|
|
@ -353,4 +365,16 @@ class ProductController extends Controller
|
|||
|
||||
return Storage::download($productAttribute['text_value']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search simple products for grouped product association
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function searchProductForGroupedAssociation()
|
||||
{
|
||||
return response()->json(
|
||||
$this->productGroupedProductRepository->searchSimpleProducts(request('id'), request()->input('query'))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ class ReviewController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -56,7 +56,7 @@ class ReviewController extends Controller
|
|||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -157,6 +157,14 @@ class Product extends Model implements ProductContract
|
|||
return $this->hasMany(ProductDownloadableLinkProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the grouped products that owns the product.
|
||||
*/
|
||||
public function grouped_products()
|
||||
{
|
||||
return $this->hasMany(ProductGroupedProductProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $qty
|
||||
*
|
||||
|
|
|
|||
|
|
@ -13,6 +13,16 @@ class ProductFlat extends Model implements ProductFlatContract
|
|||
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* Retrieve type instance
|
||||
*
|
||||
* @return AbstractType
|
||||
*/
|
||||
public function getTypeInstance()
|
||||
{
|
||||
return $this->product->getTypeInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product that owns the attribute value.
|
||||
*/
|
||||
|
|
@ -149,6 +159,14 @@ class ProductFlat extends Model implements ProductFlatContract
|
|||
return $this->product->downloadable_links();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the grouped products that owns the product.
|
||||
*/
|
||||
public function grouped_products()
|
||||
{
|
||||
return $this->product->grouped_products();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve product attributes
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Product\Contracts\ProductGroupedProduct as ProductGroupedProductContract;
|
||||
|
||||
class ProductGroupedProduct extends Model implements ProductGroupedProductContract
|
||||
{
|
||||
protected $fillable = ['qty', 'sort_order', 'product_id', 'associated_product_id'];
|
||||
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* Get the product that owns the image.
|
||||
*/
|
||||
public function product()
|
||||
{
|
||||
return $this->belongsTo(ProductProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product that owns the image.
|
||||
*/
|
||||
public function associated_product()
|
||||
{
|
||||
return $this->belongsTo(ProductProxy::modelClass());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class ProductGroupedProductProxy extends ModelProxy
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -17,5 +17,6 @@ class ModuleServiceProvider extends BaseModuleServiceProvider
|
|||
\Webkul\Product\Models\ProductSalableInventory::class,
|
||||
\Webkul\Product\Models\ProductDownloadableSample::class,
|
||||
\Webkul\Product\Models\ProductDownloadableLink::class,
|
||||
\Webkul\Product\Models\ProductGroupedProduct::class
|
||||
];
|
||||
}
|
||||
|
|
@ -50,9 +50,6 @@ class ProductDownloadableLinkRepository extends Repository
|
|||
*/
|
||||
public function saveLinks(array $data, $product)
|
||||
{
|
||||
if ($product->type != 'downloadable')
|
||||
return;
|
||||
|
||||
$previousLinkIds = $product->downloadable_links()->pluck('id');
|
||||
|
||||
if (isset($data['downloadable_links'])) {
|
||||
|
|
|
|||
|
|
@ -48,9 +48,6 @@ class ProductDownloadableSampleRepository extends Repository
|
|||
*/
|
||||
public function saveSamples(array $data, $product)
|
||||
{
|
||||
if ($product->type != 'downloadable')
|
||||
return;
|
||||
|
||||
$previousSampleIds = $product->downloadable_samples()->pluck('id');
|
||||
|
||||
if (isset($data['downloadable_samples'])) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
use Webkul\Product\Repositories\ProductRepository;
|
||||
use Webkul\Product\Repositories\ProductFlatRepository;
|
||||
|
||||
/**
|
||||
* Product Grouped Product Repository
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class ProductGroupedProductRepository extends Repository
|
||||
{
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Product\Contracts\ProductGroupedProduct';
|
||||
}
|
||||
|
||||
/**
|
||||
* Search simple products for grouped product association
|
||||
*
|
||||
* @param integer $productId
|
||||
* @param string $term
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function searchSimpleProducts($productId, $term)
|
||||
{
|
||||
$product = app(ProductRepository::class)->find($productId);
|
||||
|
||||
$groupedProductIds = $product->grouped_products()->pluck('product_id');
|
||||
|
||||
$groupedProductIds = $groupedProductIds->concat([$productId]);
|
||||
|
||||
return app(ProductFlatRepository::class)->scopeQuery(function($query) use($groupedProductIds, $term) {
|
||||
$channel = request()->get('channel') ?: (core()->getCurrentChannelCode() ?: core()->getDefaultChannelCode());
|
||||
|
||||
$locale = request()->get('locale') ?: app()->getLocale();
|
||||
|
||||
return $query->distinct()
|
||||
->addSelect('product_flat.*')
|
||||
->addSelect('product_flat.product_id as id')
|
||||
->leftJoin('products', 'product_flat.product_id', '=', 'products.id')
|
||||
->where('products.type', 'simple')
|
||||
->where('product_flat.channel', $channel)
|
||||
->where('product_flat.locale', $locale)
|
||||
->whereNotIn('product_flat.product_id', $groupedProductIds)
|
||||
->where('product_flat.name', 'like', '%' . urldecode($term) . '%')
|
||||
->orderBy('product_id', 'desc');
|
||||
})->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param Product $product
|
||||
* @return void
|
||||
*/
|
||||
public function saveGroupedProducts($data, $product)
|
||||
{
|
||||
$previousGroupedProductIds = $product->grouped_products()->pluck('id');
|
||||
|
||||
if (isset($data['links'])) {
|
||||
foreach ($data['links'] as $linkId => $linkInputs) {
|
||||
if (str_contains($linkId, 'link_')) {
|
||||
$this->create(array_merge([
|
||||
'product_id' => $product->id,
|
||||
], $linkInputs));
|
||||
} else {
|
||||
if (is_numeric($index = $previousGroupedProductIds->search($linkId)))
|
||||
$previousGroupedProductIds->forget($index);
|
||||
|
||||
$this->update($linkInputs, $linkId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($previousGroupedProductIds as $previousGroupedProductId) {
|
||||
$this->delete($previousGroupedProductId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -30,14 +30,12 @@ class ProductInventoryRepository extends Repository
|
|||
*/
|
||||
public function saveInventories(array $data, $product)
|
||||
{
|
||||
if ($product->type != 'simple')
|
||||
if (! $product->isStockable())
|
||||
return;
|
||||
|
||||
if (isset($data['inventories'])) {
|
||||
foreach ($data['inventories'] as $inventorySourceId => $qty) {
|
||||
if (is_null($qty)) {
|
||||
$qty = 0;
|
||||
}
|
||||
$qty = is_null($qty) ? 0 : $qty;
|
||||
|
||||
$productInventory = $this->findOneWhere([
|
||||
'product_id' => $product->id,
|
||||
|
|
@ -45,7 +43,6 @@ class ProductInventoryRepository extends Repository
|
|||
'vendor_id' => isset($data['vendor_id']) ? $data['vendor_id'] : 0
|
||||
]);
|
||||
|
||||
|
||||
if ($productInventory) {
|
||||
$productInventory->qty = $qty;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,12 @@
|
|||
|
||||
namespace Webkul\Product\Repositories;
|
||||
|
||||
use Illuminate\Container\Container as App;
|
||||
use DB;
|
||||
use Illuminate\Container\Container as App;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Storage;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
/**
|
||||
* Product Repository
|
||||
|
|
@ -26,78 +24,23 @@ class ProductRepository extends Repository
|
|||
*/
|
||||
protected $attributeRepository;
|
||||
|
||||
/**
|
||||
* ProductAttributeValueRepository object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributeValueRepository;
|
||||
|
||||
/**
|
||||
* ProductFlatRepository object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $productInventoryRepository;
|
||||
|
||||
/**
|
||||
* ProductImageRepository object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $productImageRepository;
|
||||
|
||||
/**
|
||||
* ProductDownloadableLinkRepository object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $productDownloadableLinkRepository;
|
||||
|
||||
/**
|
||||
* ProductDownloadableLinkRepository object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $productDownloadableSampleRepository;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @param Webkul\Attribute\Repositories\AttributeRepository $attributeRepository
|
||||
* @param Webkul\Attribute\Repositories\ProductAttributeValueRepository $attributeValueRepository
|
||||
* @param Webkul\Product\Repositories\ProductInventoryRepository $productInventoryRepository
|
||||
* @param Webkul\Product\Repositories\ProductImageRepository $productImageRepository
|
||||
* @param Webkul\Product\Repositories\ProductDownloadableLinkRepository $productDownloadableLinkRepository
|
||||
* @param Webkul\Product\Repositories\ProductDownloadableSampleRepository $productDownloadableSampleRepository
|
||||
* @param Webkul\Attribute\Repositories\AttributeRepository $attributeRepository
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
AttributeRepository $attributeRepository,
|
||||
ProductAttributeValueRepository $attributeValueRepository,
|
||||
ProductInventoryRepository $productInventoryRepository,
|
||||
ProductImageRepository $productImageRepository,
|
||||
ProductDownloadableLinkRepository $productDownloadableLinkRepository,
|
||||
ProductDownloadableSampleRepository $productDownloadableSampleRepository,
|
||||
App $app
|
||||
)
|
||||
{
|
||||
$this->attributeRepository = $attributeRepository;
|
||||
|
||||
$this->attributeValueRepository = $attributeValueRepository;
|
||||
|
||||
$this->productInventoryRepository = $productInventoryRepository;
|
||||
|
||||
$this->productImageRepository = $productImageRepository;
|
||||
|
||||
$this->productDownloadableLinkRepository = $productDownloadableLinkRepository;
|
||||
|
||||
$this->productDownloadableSampleRepository = $productDownloadableSampleRepository;
|
||||
|
||||
parent::__construct($app);
|
||||
}
|
||||
|
||||
/**->where('product_flat.visible_individually', 1)
|
||||
/**
|
||||
* Specify Model class name
|
||||
*
|
||||
* @return mixed
|
||||
|
|
@ -113,36 +56,12 @@ 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);
|
||||
$typeInstance = app(config('product_types.' . $data['type'] . '.class'));
|
||||
|
||||
$nameAttribute = $this->attributeRepository->findOneByField('code', 'status');
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $product->id,
|
||||
'attribute_id' => $nameAttribute->id,
|
||||
'value' => 1
|
||||
]);
|
||||
$product = $typeInstance->create($data);
|
||||
|
||||
if (isset($data['super_attributes'])) {
|
||||
|
||||
$super_attributes = [];
|
||||
|
||||
foreach ($data['super_attributes'] as $attributeCode => $attributeOptions) {
|
||||
$attribute = $this->attributeRepository->findOneByField('code', $attributeCode);
|
||||
|
||||
$super_attributes[$attribute->id] = $attributeOptions;
|
||||
|
||||
$product->super_attributes()->attach($attribute->id);
|
||||
}
|
||||
|
||||
foreach (array_permutation($super_attributes) as $permutation) {
|
||||
$this->createVariant($product, $permutation);
|
||||
}
|
||||
}
|
||||
|
||||
//after store of the product
|
||||
Event::fire('catalog.product.create.after', $product);
|
||||
|
||||
return $product;
|
||||
|
|
@ -160,121 +79,7 @@ class ProductRepository extends Repository
|
|||
|
||||
$product = $this->find($id);
|
||||
|
||||
if ($product->parent_id && $this->checkVariantOptionAvailabiliy($data, $product)) {
|
||||
$data['parent_id'] = NULL;
|
||||
}
|
||||
|
||||
$product->update($data);
|
||||
|
||||
$attributes = $product->attribute_family->custom_attributes;
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
if (! isset($data[$attribute->code]) || (in_array($attribute->type, ['date', 'datetime']) && ! $data[$attribute->code]))
|
||||
continue;
|
||||
|
||||
if ($attribute->type == 'multiselect') {
|
||||
$data[$attribute->code] = implode(",", $data[$attribute->code]);
|
||||
}
|
||||
|
||||
if ($attribute->type == 'image' || $attribute->type == 'file') {
|
||||
$dir = 'product/' . $product->id;
|
||||
|
||||
if (gettype($data[$attribute->code]) == 'object') {
|
||||
$data[$attribute->code] = request()->file($attribute->code)->store($dir);
|
||||
} else {
|
||||
$data[$attribute->code] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
$attributeValue = $this->attributeValueRepository->findOneWhere([
|
||||
'product_id' => $product->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'channel' => $attribute->value_per_channel ? $data['channel'] : null,
|
||||
'locale' => $attribute->value_per_locale ? $data['locale'] : null
|
||||
]);
|
||||
|
||||
if (! $attributeValue) {
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $product->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'value' => $data[$attribute->code],
|
||||
'channel' => $attribute->value_per_channel ? $data['channel'] : null,
|
||||
'locale' => $attribute->value_per_locale ? $data['locale'] : null
|
||||
]);
|
||||
} else {
|
||||
$this->attributeValueRepository->update([
|
||||
ProductAttributeValue::$attributeTypeFields[$attribute->type] => $data[$attribute->code]
|
||||
], $attributeValue->id
|
||||
);
|
||||
|
||||
if ($attribute->type == 'image' || $attribute->type == 'file') {
|
||||
Storage::delete($attributeValue->text_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (request()->route()->getName() != 'admin.catalog.products.massupdate') {
|
||||
if (isset($data['categories'])) {
|
||||
$product->categories()->sync($data['categories']);
|
||||
}
|
||||
|
||||
if (isset($data['up_sell'])) {
|
||||
$product->up_sells()->sync($data['up_sell']);
|
||||
} else {
|
||||
$data['up_sell'] = [];
|
||||
$product->up_sells()->sync($data['up_sell']);
|
||||
}
|
||||
|
||||
if (isset($data['cross_sell'])) {
|
||||
$product->cross_sells()->sync($data['cross_sell']);
|
||||
} else {
|
||||
$data['cross_sell'] = [];
|
||||
$product->cross_sells()->sync($data['cross_sell']);
|
||||
}
|
||||
|
||||
if (isset($data['related_products'])) {
|
||||
$product->related_products()->sync($data['related_products']);
|
||||
} else {
|
||||
$data['related_products'] = [];
|
||||
$product->related_products()->sync($data['related_products']);
|
||||
}
|
||||
|
||||
$previousVariantIds = $product->variants->pluck('id');
|
||||
|
||||
if (isset($data['variants'])) {
|
||||
foreach ($data['variants'] as $variantId => $variantData) {
|
||||
if (str_contains($variantId, 'variant_')) {
|
||||
$permutation = [];
|
||||
foreach ($product->super_attributes as $superAttribute) {
|
||||
$permutation[$superAttribute->id] = $variantData[$superAttribute->code];
|
||||
}
|
||||
|
||||
$this->createVariant($product, $permutation, $variantData);
|
||||
} else {
|
||||
if (is_numeric($index = $previousVariantIds->search($variantId))) {
|
||||
$previousVariantIds->forget($index);
|
||||
}
|
||||
|
||||
$variantData['channel'] = $data['channel'];
|
||||
$variantData['locale'] = $data['locale'];
|
||||
|
||||
$this->updateVariant($variantData, $variantId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($previousVariantIds as $variantId) {
|
||||
$this->delete($variantId);
|
||||
}
|
||||
|
||||
$this->productInventoryRepository->saveInventories($data, $product);
|
||||
|
||||
$this->productImageRepository->uploadImages($data, $product);
|
||||
|
||||
$this->productDownloadableLinkRepository->saveLinks($data, $product);
|
||||
|
||||
$this->productDownloadableSampleRepository->saveSamples($data, $product);
|
||||
}
|
||||
$product = $product->getTypeInstance()->update($data, $id, $attribute);
|
||||
|
||||
Event::fire('catalog.product.update.after', $product);
|
||||
|
||||
|
|
@ -294,167 +99,6 @@ class ProductRepository extends Repository
|
|||
Event::fire('catalog.product.delete.after', $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $product
|
||||
* @param array $permutation
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function createVariant($product, $permutation, $data = [])
|
||||
{
|
||||
if (! count($data)) {
|
||||
$data = [
|
||||
"sku" => $product->sku . '-variant-' . implode('-', $permutation),
|
||||
"name" => "",
|
||||
"inventories" => [],
|
||||
"price" => 0,
|
||||
"weight" => 0,
|
||||
"status" => 1
|
||||
];
|
||||
}
|
||||
|
||||
$variant = $this->model->create([
|
||||
'parent_id' => $product->id,
|
||||
'type' => 'simple',
|
||||
'attribute_family_id' => $product->attribute_family_id,
|
||||
'sku' => $data['sku'],
|
||||
]);
|
||||
|
||||
foreach (['sku', 'name', 'price', 'weight', 'status'] as $attributeCode) {
|
||||
$attribute = $this->attributeRepository->findOneByField('code', $attributeCode);
|
||||
|
||||
if ($attribute->value_per_channel) {
|
||||
if ($attribute->value_per_locale) {
|
||||
foreach (core()->getAllChannels() as $channel) {
|
||||
foreach (core()->getAllLocales() as $locale) {
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $variant->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'channel' => $channel->code,
|
||||
'locale' => $locale->code,
|
||||
'value' => $data[$attributeCode]
|
||||
]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach (core()->getAllChannels() as $channel) {
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $variant->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'channel' => $channel->code,
|
||||
'value' => $data[$attributeCode]
|
||||
]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($attribute->value_per_locale) {
|
||||
foreach (core()->getAllLocales() as $locale) {
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $variant->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'locale' => $locale->code,
|
||||
'value' => $data[$attributeCode]
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $variant->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'value' => $data[$attributeCode]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($permutation as $attributeId => $optionId) {
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $variant->id,
|
||||
'attribute_id' => $attributeId,
|
||||
'value' => $optionId
|
||||
]);
|
||||
}
|
||||
|
||||
$this->productInventoryRepository->saveInventories($data, $variant);
|
||||
|
||||
return $variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateVariant(array $data, $id)
|
||||
{
|
||||
$variant = $this->find($id);
|
||||
|
||||
$variant->update(['sku' => $data['sku']]);
|
||||
|
||||
foreach (['sku', 'name', 'price', 'weight', 'status'] as $attributeCode) {
|
||||
$attribute = $this->attributeRepository->findOneByField('code', $attributeCode);
|
||||
|
||||
$attributeValue = $this->attributeValueRepository->findOneWhere([
|
||||
'product_id' => $id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'channel' => $attribute->value_per_channel ? $data['channel'] : null,
|
||||
'locale' => $attribute->value_per_locale ? $data['locale'] : null
|
||||
]);
|
||||
|
||||
if (! $attributeValue) {
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'value' => $data[$attribute->code],
|
||||
'channel' => $attribute->value_per_channel ? $data['channel'] : null,
|
||||
'locale' => $attribute->value_per_locale ? $data['locale'] : null
|
||||
]);
|
||||
} else {
|
||||
$this->attributeValueRepository->update([
|
||||
ProductAttributeValue::$attributeTypeFields[$attribute->type] => $data[$attribute->code]
|
||||
], $attributeValue->id);
|
||||
}
|
||||
}
|
||||
|
||||
$this->productInventoryRepository->saveInventories($data, $variant);
|
||||
|
||||
return $variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param mixed $product
|
||||
* @return mixed
|
||||
*/
|
||||
public function checkVariantOptionAvailabiliy($data, $product)
|
||||
{
|
||||
$parent = $product->parent;
|
||||
|
||||
$superAttributeCodes = $parent->super_attributes->pluck('code');
|
||||
|
||||
$isAlreadyExist = false;
|
||||
|
||||
foreach ($parent->variants as $variant) {
|
||||
if ($variant->id == $product->id)
|
||||
continue;
|
||||
|
||||
$matchCount = 0;
|
||||
|
||||
foreach ($superAttributeCodes as $attributeCode) {
|
||||
if (! isset($data[$attributeCode]))
|
||||
return false;
|
||||
|
||||
if ($data[$attributeCode] == $variant->{$attributeCode})
|
||||
$matchCount++;
|
||||
}
|
||||
|
||||
if ($matchCount == $superAttributeCodes->count()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $categoryId
|
||||
* @return Collection
|
||||
|
|
@ -473,24 +117,20 @@ class ProductRepository extends Repository
|
|||
->addSelect(DB::raw('IF( product_flat.special_price_from IS NOT NULL
|
||||
AND product_flat.special_price_to IS NOT NULL , IF( NOW( ) >= product_flat.special_price_from
|
||||
AND NOW( ) <= product_flat.special_price_to, IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , product_flat.price ) , IF( product_flat.special_price_from IS NULL , IF( product_flat.special_price_to IS NULL , IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , IF( NOW( ) <= product_flat.special_price_to, IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , product_flat.price ) ) , IF( product_flat.special_price_to IS NULL , IF( NOW( ) >= product_flat.special_price_from, IF( product_flat.special_price IS NULL OR product_flat.special_price = 0 , product_flat.price, LEAST( product_flat.special_price, product_flat.price ) ) , product_flat.price ) , product_flat.price ) ) ) AS final_price'))
|
||||
|
||||
->leftJoin('products', 'product_flat.product_id', '=', 'products.id')
|
||||
->leftJoin('product_categories', 'products.id', '=', 'product_categories.product_id')
|
||||
->where('product_flat.channel', $channel)
|
||||
->where('product_flat.locale', $locale)
|
||||
->whereNotNull('product_flat.url_key');
|
||||
|
||||
if ($categoryId) {
|
||||
if ($categoryId)
|
||||
$qb->where('product_categories.category_id', $categoryId);
|
||||
}
|
||||
|
||||
if (is_null(request()->input('status'))) {
|
||||
if (is_null(request()->input('status')))
|
||||
$qb->where('product_flat.status', 1);
|
||||
}
|
||||
|
||||
if (is_null(request()->input('visible_individually'))) {
|
||||
if (is_null(request()->input('visible_individually')))
|
||||
$qb->where('product_flat.visible_individually', 1);
|
||||
}
|
||||
|
||||
$queryBuilder = $qb->leftJoin('product_flat as flat_variants', function($qb) use($channel, $locale) {
|
||||
$qb->on('product_flat.id', '=', 'flat_variants.parent_id')
|
||||
|
|
@ -498,9 +138,8 @@ class ProductRepository extends Repository
|
|||
->where('flat_variants.locale', $locale);
|
||||
});
|
||||
|
||||
if (isset($params['search'])) {
|
||||
if (isset($params['search']))
|
||||
$qb->where('product_flat.name', 'like', '%' . urldecode($params['search']) . '%');
|
||||
}
|
||||
|
||||
if (isset($params['sort'])) {
|
||||
$attribute = $this->attributeRepository->findOneByField('code', $params['sort']);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,17 @@
|
|||
|
||||
namespace Webkul\Product\Type;
|
||||
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Product\Repositories\ProductRepository;
|
||||
use Webkul\Product\Repositories\ProductAttributeValueRepository;
|
||||
use Webkul\Product\Repositories\ProductInventoryRepository;
|
||||
use Webkul\Product\Repositories\ProductImageRepository;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
use Webkul\Product\Helpers\Price;
|
||||
use Webkul\Product\Helpers\ProductImage;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Cart;
|
||||
|
||||
/**
|
||||
* Abstract class Type
|
||||
*
|
||||
|
|
@ -10,6 +21,55 @@ namespace Webkul\Product\Type;
|
|||
*/
|
||||
abstract class AbstractType
|
||||
{
|
||||
/**
|
||||
* AttributeRepository instance
|
||||
*
|
||||
* @var AttributeRepository
|
||||
*/
|
||||
protected $attributeRepository;
|
||||
|
||||
/**
|
||||
* ProductRepository instance
|
||||
*
|
||||
* @var ProductRepository
|
||||
*/
|
||||
protected $productRepository;
|
||||
|
||||
/**
|
||||
* ProductAttributeValueRepository instance
|
||||
*
|
||||
* @var ProductAttributeValueRepository
|
||||
*/
|
||||
protected $attributeValueRepository;
|
||||
|
||||
/**
|
||||
* ProductInventoryRepository instance
|
||||
*
|
||||
* @var ProductInventoryRepository
|
||||
*/
|
||||
protected $productInventoryRepository;
|
||||
|
||||
/**
|
||||
* ProductImageRepository instance
|
||||
*
|
||||
* @var ProductImageRepository
|
||||
*/
|
||||
protected $productImageRepository;
|
||||
|
||||
/**
|
||||
* Product price helper instance
|
||||
*
|
||||
* @var Price
|
||||
*/
|
||||
protected $priceHelper;
|
||||
|
||||
/**
|
||||
* Product Image helper instance
|
||||
*
|
||||
* @var ProductImage
|
||||
*/
|
||||
protected $productImageHelper;
|
||||
|
||||
/**
|
||||
* Product model instance
|
||||
*
|
||||
|
|
@ -17,11 +77,126 @@ abstract class AbstractType
|
|||
*/
|
||||
protected $product;
|
||||
|
||||
/**
|
||||
* Create a new product type instance.
|
||||
*
|
||||
* @param Webkul\Attribute\Repositories\AttributeRepository $attributeRepository
|
||||
* @param Webkul\Product\Repositories\ProductRepository $productRepository
|
||||
* @param Webkul\Product\Repositories\ProductAttributeValueRepository $attributeValueRepository
|
||||
* @param Webkul\Product\Repositories\ProductInventoryRepository $productInventoryRepository
|
||||
* @param Webkul\Product\Repositories\ProductImageRepository $productImageRepository
|
||||
* @param Webkul\Product\Helpers\Price $priceHelper
|
||||
* @param Webkul\Product\Helpers\ProductImage $productImageHelper
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
AttributeRepository $attributeRepository,
|
||||
ProductRepository $productRepository,
|
||||
ProductAttributeValueRepository $attributeValueRepository,
|
||||
ProductInventoryRepository $productInventoryRepository,
|
||||
ProductImageRepository $productImageRepository,
|
||||
Price $priceHelper,
|
||||
ProductImage $productImageHelper
|
||||
)
|
||||
{
|
||||
$this->attributeRepository = $attributeRepository;
|
||||
|
||||
$this->productRepository = $productRepository;
|
||||
|
||||
$this->attributeValueRepository = $attributeValueRepository;
|
||||
|
||||
$this->productInventoryRepository = $productInventoryRepository;
|
||||
|
||||
$this->productImageRepository = $productImageRepository;
|
||||
|
||||
$this->priceHelper = $priceHelper;
|
||||
|
||||
$this->productImageHelper = $productImageHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Product
|
||||
*/
|
||||
public function create(array $data)
|
||||
{
|
||||
return $this->productRepository->getModel()->create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param $id
|
||||
* @param string $attribute
|
||||
* @return Product
|
||||
*/
|
||||
public function update(array $data, $id, $attribute = "id")
|
||||
{
|
||||
$product = $this->productRepository->find($id);
|
||||
|
||||
$product->update($data);
|
||||
|
||||
foreach ($product->attribute_family->custom_attributes as $attribute) {
|
||||
if (! isset($data[$attribute->code]) || (in_array($attribute->type, ['date', 'datetime']) && ! $data[$attribute->code]))
|
||||
continue;
|
||||
|
||||
if ($attribute->type == 'multiselect')
|
||||
$data[$attribute->code] = implode(",", $data[$attribute->code]);
|
||||
|
||||
if ($attribute->type == 'image' || $attribute->type == 'file') {
|
||||
$data[$attribute->code] = gettype($data[$attribute->code]) == 'object'
|
||||
? request()->file($attribute->code)->store('product/' . $product->id)
|
||||
: NULL;
|
||||
}
|
||||
|
||||
$attributeValue = $this->attributeValueRepository->findOneWhere([
|
||||
'product_id' => $product->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'channel' => $attribute->value_per_channel ? $data['channel'] : null,
|
||||
'locale' => $attribute->value_per_locale ? $data['locale'] : null
|
||||
]);
|
||||
|
||||
if (! $attributeValue) {
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $product->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'value' => $data[$attribute->code],
|
||||
'channel' => $attribute->value_per_channel ? $data['channel'] : null,
|
||||
'locale' => $attribute->value_per_locale ? $data['locale'] : null
|
||||
]);
|
||||
} else {
|
||||
$this->attributeValueRepository->update([
|
||||
ProductAttributeValue::$attributeTypeFields[$attribute->type] => $data[$attribute->code]
|
||||
], $attributeValue->id
|
||||
);
|
||||
|
||||
if ($attribute->type == 'image' || $attribute->type == 'file')
|
||||
Storage::delete($attributeValue->text_value);
|
||||
}
|
||||
}
|
||||
|
||||
if (request()->route()->getName() != 'admin.catalog.products.massupdate') {
|
||||
if (isset($data['categories']))
|
||||
$product->categories()->sync($data['categories']);
|
||||
|
||||
$product->up_sells()->sync($data['up_sell'] ?? []);
|
||||
|
||||
$product->cross_sells()->sync($data['cross_sell'] ?? []);
|
||||
|
||||
$product->related_products()->sync($data['related_products'] ?? []);
|
||||
|
||||
$this->productInventoryRepository->saveInventories($data, $product);
|
||||
|
||||
$this->productImageRepository->uploadImages($data, $product);
|
||||
}
|
||||
|
||||
return $product;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify type instance product
|
||||
*
|
||||
* @param Product $product
|
||||
* @return AbstractType
|
||||
* @param Product $product
|
||||
* @return AbstractType
|
||||
*/
|
||||
public function setProduct($product)
|
||||
{
|
||||
|
|
@ -33,25 +208,52 @@ abstract class AbstractType
|
|||
/**
|
||||
* Return true if this product type is saleable
|
||||
*
|
||||
* @return array
|
||||
* @return boolean
|
||||
*/
|
||||
abstract public function isSaleable();
|
||||
public function isSaleable()
|
||||
{
|
||||
if (! $this->product->status)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this product can have inventory
|
||||
*
|
||||
* @return array
|
||||
* @return boolean
|
||||
*/
|
||||
abstract public function isStockable();
|
||||
public function isStockable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $qty
|
||||
* @return bool
|
||||
*/
|
||||
public function haveSufficientQuantity($qty)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CartItem $cartItem
|
||||
* @return bool
|
||||
*/
|
||||
public function isItemHaveQuantity($cartItem)
|
||||
{
|
||||
return $cartItem->product->getTypeInstance()->haveSufficientQuantity($cartItem->quantity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if item can be moved to cart from wishlist
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canBeMovedFromWishlistToCart()
|
||||
public function canBeMovedFromWishlistToCart($item)
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -91,5 +293,120 @@ abstract class AbstractType
|
|||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
/**
|
||||
* Add product. Returns error message if can't prepare product.
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function prepareForCart($data)
|
||||
{
|
||||
$data = $this->getQtyRequest($data);
|
||||
|
||||
if ($this->isStockable() && ! $this->haveSufficientQuantity($data['quantity']))
|
||||
return trans('shop::app.checkout.cart.quantity.inventory_warning');
|
||||
|
||||
$price = $this->priceHelper->getMinimalPrice($this->product);
|
||||
|
||||
$products = [
|
||||
[
|
||||
'product_id' => $this->product->id,
|
||||
'sku' => $this->product->sku,
|
||||
'quantity' => $data['quantity'],
|
||||
'name' => $this->product->name,
|
||||
'price' => $convertedPrice = core()->convertPrice($price),
|
||||
'base_price' => $price,
|
||||
'total' => $convertedPrice * $data['quantity'],
|
||||
'base_total' => $price * $data['quantity'],
|
||||
'weight' => $this->product->weight ?? 0,
|
||||
'total_weight' => ($this->product->weight ?? 0) * $data['quantity'],
|
||||
'base_total_weight' => ($this->product->weight ?? 0) * $data['quantity'],
|
||||
'type' => $this->product->type,
|
||||
'additional' => $this->getAdditionalOptions($data)
|
||||
]
|
||||
];
|
||||
|
||||
return $products;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get request quantity
|
||||
*
|
||||
* @param Product $product
|
||||
* @param array $data
|
||||
* @return CartItem|void
|
||||
*/
|
||||
public function getQtyRequest($data)
|
||||
{
|
||||
if ($item = Cart::getItemByProduct(['additional' => $data]))
|
||||
$data['quantity'] += $item->quantity;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if product can be configured
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canConfigure()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array $options1
|
||||
* @param array $options2
|
||||
* @return boolean
|
||||
*/
|
||||
public function compareOptions($options1, $options2)
|
||||
{
|
||||
return $this->product->id == $options2['product_id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns additional information for items
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function getAdditionalOptions($data)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get actual ordered item
|
||||
*
|
||||
* @param CartItem $item
|
||||
* @return CartItem|OrderItem|InvoiceItem|ShipmentItem|Wishlist
|
||||
*/
|
||||
public function getOrderedItem($item)
|
||||
{
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product base image
|
||||
*
|
||||
* @param Wishlist|CartItem $item
|
||||
* @return array
|
||||
*/
|
||||
public function getBaseImage($item)
|
||||
{
|
||||
return $this->productImageHelper->getProductBaseImage($item->product);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product base image
|
||||
*
|
||||
* @param CartItem $item
|
||||
* @return float
|
||||
*/
|
||||
public function getMinimalPrice($item)
|
||||
{
|
||||
return $this->priceHelper->getMinimalPrice($item->product);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,433 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Type;
|
||||
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
|
||||
/**
|
||||
* Class Configurable.
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class Configurable extends AbstractType
|
||||
{
|
||||
/**
|
||||
* Skip attribute for downloadable product type
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $skipAttributes = ['price', 'cost', 'special_price', 'special_price_from', 'special_price_to', 'width', 'height', 'depth', 'weight'];
|
||||
|
||||
/**
|
||||
* These blade files will be included in product edit page
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $additionalViews = [
|
||||
'admin::catalog.products.accordians.images',
|
||||
'admin::catalog.products.accordians.categories',
|
||||
'admin::catalog.products.accordians.variations',
|
||||
'admin::catalog.products.accordians.product-links'
|
||||
];
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return Product
|
||||
*/
|
||||
public function create(array $data)
|
||||
{
|
||||
$product = $this->productRepository->getModel()->create($data);
|
||||
|
||||
if (isset($data['super_attributes'])) {
|
||||
$super_attributes = [];
|
||||
|
||||
foreach ($data['super_attributes'] as $attributeCode => $attributeOptions) {
|
||||
$attribute = $this->attributeRepository->findOneByField('code', $attributeCode);
|
||||
|
||||
$super_attributes[$attribute->id] = $attributeOptions;
|
||||
|
||||
$product->super_attributes()->attach($attribute->id);
|
||||
}
|
||||
|
||||
foreach (array_permutation($super_attributes) as $permutation) {
|
||||
$this->createVariant($product, $permutation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param $id
|
||||
* @param string $attribute
|
||||
* @return Product
|
||||
*/
|
||||
public function update(array $data, $id, $attribute = "id")
|
||||
{
|
||||
$product = parent::update($data, $id, $attribute);
|
||||
|
||||
if (request()->route()->getName() != 'admin.catalog.products.massupdate') {
|
||||
$previousVariantIds = $product->variants->pluck('id');
|
||||
|
||||
if (isset($data['variants'])) {
|
||||
foreach ($data['variants'] as $variantId => $variantData) {
|
||||
if (str_contains($variantId, 'variant_')) {
|
||||
$permutation = [];
|
||||
|
||||
foreach ($product->super_attributes as $superAttribute) {
|
||||
$permutation[$superAttribute->id] = $variantData[$superAttribute->code];
|
||||
}
|
||||
|
||||
$this->createVariant($product, $permutation, $variantData);
|
||||
} else {
|
||||
if (is_numeric($index = $previousVariantIds->search($variantId)))
|
||||
$previousVariantIds->forget($index);
|
||||
|
||||
$variantData['channel'] = $data['channel'];
|
||||
$variantData['locale'] = $data['locale'];
|
||||
|
||||
$this->updateVariant($variantData, $variantId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($previousVariantIds as $variantId) {
|
||||
$this->productRepository->delete($variantId);
|
||||
}
|
||||
}
|
||||
|
||||
return $product;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $product
|
||||
* @param array $permutation
|
||||
* @param array $data
|
||||
* @return mixed
|
||||
*/
|
||||
public function createVariant($product, $permutation, $data = [])
|
||||
{
|
||||
if (! count($data)) {
|
||||
$data = [
|
||||
"sku" => $product->sku . '-variant-' . implode('-', $permutation),
|
||||
"name" => "",
|
||||
"inventories" => [],
|
||||
"price" => 0,
|
||||
"weight" => 0,
|
||||
"status" => 1
|
||||
];
|
||||
}
|
||||
|
||||
$variant = $this->productRepository->getModel()->create([
|
||||
'parent_id' => $product->id,
|
||||
'type' => 'simple',
|
||||
'attribute_family_id' => $product->attribute_family_id,
|
||||
'sku' => $data['sku'],
|
||||
]);
|
||||
|
||||
foreach (['sku', 'name', 'price', 'weight', 'status'] as $attributeCode) {
|
||||
$attribute = $this->attributeRepository->findOneByField('code', $attributeCode);
|
||||
|
||||
if ($attribute->value_per_channel) {
|
||||
if ($attribute->value_per_locale) {
|
||||
foreach (core()->getAllChannels() as $channel) {
|
||||
foreach (core()->getAllLocales() as $locale) {
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $variant->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'channel' => $channel->code,
|
||||
'locale' => $locale->code,
|
||||
'value' => $data[$attributeCode]
|
||||
]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach (core()->getAllChannels() as $channel) {
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $variant->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'channel' => $channel->code,
|
||||
'value' => $data[$attributeCode]
|
||||
]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($attribute->value_per_locale) {
|
||||
foreach (core()->getAllLocales() as $locale) {
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $variant->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'locale' => $locale->code,
|
||||
'value' => $data[$attributeCode]
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $variant->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'value' => $data[$attributeCode]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($permutation as $attributeId => $optionId) {
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $variant->id,
|
||||
'attribute_id' => $attributeId,
|
||||
'value' => $optionId
|
||||
]);
|
||||
}
|
||||
|
||||
$this->productInventoryRepository->saveInventories($data, $variant);
|
||||
|
||||
return $variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateVariant(array $data, $id)
|
||||
{
|
||||
$variant = $this->productRepository->find($id);
|
||||
|
||||
$variant->update(['sku' => $data['sku']]);
|
||||
|
||||
foreach (['sku', 'name', 'price', 'weight', 'status'] as $attributeCode) {
|
||||
$attribute = $this->attributeRepository->findOneByField('code', $attributeCode);
|
||||
|
||||
$attributeValue = $this->attributeValueRepository->findOneWhere([
|
||||
'product_id' => $id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'channel' => $attribute->value_per_channel ? $data['channel'] : null,
|
||||
'locale' => $attribute->value_per_locale ? $data['locale'] : null
|
||||
]);
|
||||
|
||||
if (! $attributeValue) {
|
||||
$this->attributeValueRepository->create([
|
||||
'product_id' => $id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'value' => $data[$attribute->code],
|
||||
'channel' => $attribute->value_per_channel ? $data['channel'] : null,
|
||||
'locale' => $attribute->value_per_locale ? $data['locale'] : null
|
||||
]);
|
||||
} else {
|
||||
$this->attributeValueRepository->update([
|
||||
ProductAttributeValue::$attributeTypeFields[$attribute->type] => $data[$attribute->code]
|
||||
], $attributeValue->id);
|
||||
}
|
||||
}
|
||||
|
||||
$this->productInventoryRepository->saveInventories($data, $variant);
|
||||
|
||||
return $variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param mixed $product
|
||||
* @return mixed
|
||||
*/
|
||||
public function checkVariantOptionAvailabiliy($data, $product)
|
||||
{
|
||||
$superAttributeCodes = $product->parent->super_attributes->pluck('code');
|
||||
|
||||
foreach ($product->parent->variants as $variant) {
|
||||
if ($variant->id == $product->id)
|
||||
continue;
|
||||
|
||||
$matchCount = 0;
|
||||
|
||||
foreach ($superAttributeCodes as $attributeCode) {
|
||||
if (! isset($data[$attributeCode]))
|
||||
return false;
|
||||
|
||||
if ($data[$attributeCode] == $variant->{$attributeCode})
|
||||
$matchCount++;
|
||||
}
|
||||
|
||||
if ($matchCount == $superAttributeCodes->count())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CartItem $cartItem
|
||||
* @return bool
|
||||
*/
|
||||
public function isItemHaveQuantity($cartItem)
|
||||
{
|
||||
return $cartItem->child->product->getTypeInstance()->haveSufficientQuantity($cartItem->quantity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns validation rules
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTypeValidationRules()
|
||||
{
|
||||
return [
|
||||
'variants.*.name' => 'required',
|
||||
'variants.*.sku' => 'required',
|
||||
'variants.*.price' => 'required',
|
||||
'variants.*.weight' => 'required',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if item can be moved to cart from wishlist
|
||||
*
|
||||
* @param Wishlist $item
|
||||
* @return boolean
|
||||
*/
|
||||
public function canBeMovedFromWishlistToCart($item)
|
||||
{
|
||||
if (isset($item->additional['selected_configurable_option']))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add product. Returns error message if can't prepare product.
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function prepareForCart($data)
|
||||
{
|
||||
if (! isset($data['selected_configurable_option']) || ! $data['selected_configurable_option'])
|
||||
return trans('shop::app.checkout.cart.item.error-add');
|
||||
|
||||
$data = $this->getQtyRequest($data);
|
||||
|
||||
$childProduct = $this->productRepository->find($data['selected_configurable_option']);
|
||||
|
||||
if (! $childProduct->haveSufficientQuantity($data['quantity']))
|
||||
return trans('shop::app.checkout.cart.quantity.inventory_warning');
|
||||
|
||||
$price = $this->priceHelper->getMinimalPrice($childProduct);
|
||||
|
||||
$products = [
|
||||
[
|
||||
'product_id' => $this->product->id,
|
||||
'sku' => $this->product->sku,
|
||||
'quantity' => $data['quantity'],
|
||||
'name' => $this->product->name,
|
||||
'price' => $convertedPrice = core()->convertPrice($price),
|
||||
'base_price' => $price,
|
||||
'total' => $convertedPrice * $data['quantity'],
|
||||
'base_total' => $price * $data['quantity'],
|
||||
'weight' => $childProduct->weight,
|
||||
'total_weight' => $childProduct->weight * $data['quantity'],
|
||||
'base_total_weight' => $childProduct->weight * $data['quantity'],
|
||||
'type' => $this->product->type,
|
||||
'additional' => $this->getAdditionalOptions($data)
|
||||
], [
|
||||
'parent_id' => $this->product->id,
|
||||
'product_id' => (int) $data['selected_configurable_option'],
|
||||
'sku' => $childProduct->sku,
|
||||
'name' => $childProduct->name,
|
||||
'type' => 'simple',
|
||||
'additional' => ['product_id' => (int) $data['selected_configurable_option']]
|
||||
]
|
||||
];
|
||||
|
||||
return $products;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if product can be configured
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canConfigure()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array $options1
|
||||
* @param array $options2
|
||||
* @return boolean
|
||||
*/
|
||||
public function compareOptions($options1, $options2)
|
||||
{
|
||||
if ($this->product->id != $options2['product_id'])
|
||||
return false;
|
||||
|
||||
return $options1['selected_configurable_option'] === $options2['selected_configurable_option'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns additional information for items
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function getAdditionalOptions($data)
|
||||
{
|
||||
$childProduct = app('Webkul\Product\Repositories\ProductRepository')->findOneByField('id', $data['selected_configurable_option']);
|
||||
|
||||
foreach ($this->product->super_attributes as $attribute) {
|
||||
$option = $attribute->options()->where('id', $childProduct->{$attribute->code})->first();
|
||||
|
||||
$data['attributes'][$attribute->code] = [
|
||||
'attribute_name' => $attribute->name ? $attribute->name : $attribute->admin_name,
|
||||
'option_id' => $option->id,
|
||||
'option_label' => $option->label,
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get actual ordered item
|
||||
*
|
||||
* @param CartItem $item
|
||||
* @return CartItem|OrderItem|InvoiceItem|ShipmentItem
|
||||
*/
|
||||
public function getOrderedItem($item)
|
||||
{
|
||||
return $item->child;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product base image
|
||||
*
|
||||
* @param Wishlist|CartItem $item
|
||||
* @return array
|
||||
*/
|
||||
public function getBaseImage($item)
|
||||
{
|
||||
if ($item instanceof \Webkul\Customer\Contracts\Wishlist) {
|
||||
if (isset($item->additional['selected_configurable_option'])) {
|
||||
$product = $this->productRepository->find($item->additional['selected_configurable_option']);
|
||||
} else {
|
||||
$product = $item->product;
|
||||
}
|
||||
} else {
|
||||
$product = $item->child->product;
|
||||
}
|
||||
|
||||
return $this->productImageHelper->getProductBaseImage($product);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product base image
|
||||
*
|
||||
* @param CartItem $item
|
||||
* @return array
|
||||
*/
|
||||
public function getMinimalPrice($item)
|
||||
{
|
||||
return $this->priceHelper->getMinimalPrice($item->child->product);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Type;
|
||||
|
||||
/**
|
||||
* Class Configurable.
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class Configurable extends AbstractType
|
||||
{
|
||||
/**
|
||||
* Skip attribute for downloadable product type
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $skipAttributes = ['price', 'cost', 'special_price', 'special_price_from', 'special_price_to', 'width', 'height', 'depth', 'weight'];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $additionalViews = [
|
||||
'admin::catalog.products.accordians.images',
|
||||
'admin::catalog.products.accordians.categories',
|
||||
'admin::catalog.products.accordians.variations',
|
||||
'admin::catalog.products.accordians.product-links'
|
||||
];
|
||||
|
||||
/**
|
||||
* Return true if this product type is saleable
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function isSaleable()
|
||||
{
|
||||
if (! $this->product->status)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this product can have inventory
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function isStockable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns validation rules
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTypeValidationRules()
|
||||
{
|
||||
return [
|
||||
'variants.*.name' => 'required',
|
||||
'variants.*.sku' => 'required',
|
||||
'variants.*.price' => 'required',
|
||||
'variants.*.weight' => 'required',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,18 @@
|
|||
|
||||
namespace Webkul\Product\Type;
|
||||
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Product\Repositories\ProductRepository;
|
||||
use Webkul\Product\Repositories\ProductAttributeValueRepository;
|
||||
use Webkul\Product\Repositories\ProductInventoryRepository;
|
||||
use Webkul\Product\Repositories\ProductImageRepository;
|
||||
use Webkul\Product\Repositories\ProductDownloadableLinkRepository;
|
||||
use Webkul\Product\Repositories\ProductDownloadableSampleRepository;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
use Webkul\Product\Helpers\Price;
|
||||
use Webkul\Product\Helpers\ProductImage;
|
||||
use Webkul\Checkout\Models\CartItem;
|
||||
|
||||
/**
|
||||
* Class Downloadable.
|
||||
*
|
||||
|
|
@ -10,6 +22,69 @@ namespace Webkul\Product\Type;
|
|||
*/
|
||||
class Downloadable extends AbstractType
|
||||
{
|
||||
/**
|
||||
* AttributeRepository instance
|
||||
*
|
||||
* @var AttributeRepository
|
||||
*/
|
||||
protected $attributeRepository;
|
||||
|
||||
/**
|
||||
* ProductRepository instance
|
||||
*
|
||||
* @var ProductRepository
|
||||
*/
|
||||
protected $productRepository;
|
||||
|
||||
/**
|
||||
* ProductAttributeValueRepository instance
|
||||
*
|
||||
* @var ProductAttributeValueRepository
|
||||
*/
|
||||
protected $attributeValueRepository;
|
||||
|
||||
/**
|
||||
* ProductInventoryRepository instance
|
||||
*
|
||||
* @var ProductInventoryRepository
|
||||
*/
|
||||
protected $productInventoryRepository;
|
||||
|
||||
/**
|
||||
* ProductImageRepository instance
|
||||
*
|
||||
* @var ProductImageRepository
|
||||
*/
|
||||
protected $productImageRepository;
|
||||
|
||||
/**
|
||||
* ProductDownloadableLinkRepository instance
|
||||
*
|
||||
* @var ProductDownloadableLinkRepository
|
||||
*/
|
||||
protected $productDownloadableLinkRepository;
|
||||
|
||||
/**
|
||||
* ProductDownloadableSampleRepository instance
|
||||
*
|
||||
* @var ProductDownloadableSampleRepository
|
||||
*/
|
||||
protected $productDownloadableSampleRepository;
|
||||
|
||||
/**
|
||||
* Product price helper instance
|
||||
*
|
||||
* @var Price
|
||||
*/
|
||||
protected $priceHelper;
|
||||
|
||||
/**
|
||||
* Product Image helper instance
|
||||
*
|
||||
* @var ProductImage
|
||||
*/
|
||||
protected $productImageHelper;
|
||||
|
||||
/**
|
||||
* Skip attribute for downloadable product type
|
||||
*
|
||||
|
|
@ -18,6 +93,8 @@ class Downloadable extends AbstractType
|
|||
protected $skipAttributes = ['width', 'height', 'depth', 'weight'];
|
||||
|
||||
/**
|
||||
* These blade files will be included in product edit page
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $additionalViews = [
|
||||
|
|
@ -27,10 +104,70 @@ class Downloadable extends AbstractType
|
|||
'admin::catalog.products.accordians.product-links'
|
||||
];
|
||||
|
||||
/**
|
||||
* Create a new product type instance.
|
||||
*
|
||||
* @param Webkul\Attribute\Repositories\AttributeRepository $attributeRepository
|
||||
* @param Webkul\Product\Repositories\ProductRepository $productRepository
|
||||
* @param Webkul\Product\Repositories\ProductAttributeValueRepository $attributeValueRepository
|
||||
* @param Webkul\Product\Repositories\ProductInventoryRepository $productInventoryRepository
|
||||
* @param Webkul\Product\Repositories\ProductImageRepository $productImageRepository
|
||||
* @param Webkul\Product\Repositories\ProductDownloadableLinkRepository $productDownloadableLinkRepository
|
||||
* @param Webkul\Product\Repositories\ProductDownloadableSampleRepository $productDownloadableSampleRepository
|
||||
* @param Webkul\Product\Helpers\Price $priceHelper
|
||||
* @param Webkul\Product\Helpers\ProductImage $productImageHelper
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
AttributeRepository $attributeRepository,
|
||||
ProductRepository $productRepository,
|
||||
ProductAttributeValueRepository $attributeValueRepository,
|
||||
ProductInventoryRepository $productInventoryRepository,
|
||||
productImageRepository $productImageRepository,
|
||||
ProductDownloadableLinkRepository $productDownloadableLinkRepository,
|
||||
ProductDownloadableSampleRepository $productDownloadableSampleRepository,
|
||||
Price $priceHelper,
|
||||
ProductImage $productImageHelper
|
||||
)
|
||||
{
|
||||
parent::__construct(
|
||||
$attributeRepository,
|
||||
$productRepository,
|
||||
$attributeValueRepository,
|
||||
$productInventoryRepository,
|
||||
$productImageRepository,
|
||||
$priceHelper,
|
||||
$productImageHelper
|
||||
);
|
||||
|
||||
$this->productDownloadableLinkRepository = $productDownloadableLinkRepository;
|
||||
|
||||
$this->productDownloadableSampleRepository = $productDownloadableSampleRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param $id
|
||||
* @param string $attribute
|
||||
* @return Product
|
||||
*/
|
||||
public function update(array $data, $id, $attribute = "id")
|
||||
{
|
||||
$product = parent::update($data, $id, $attribute);
|
||||
|
||||
if (request()->route()->getName() != 'admin.catalog.products.massupdate') {
|
||||
$this->productDownloadableLinkRepository->saveLinks($data, $product);
|
||||
|
||||
$this->productDownloadableSampleRepository->saveSamples($data, $product);
|
||||
}
|
||||
|
||||
return $product;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this product type is saleable
|
||||
*
|
||||
* @return array
|
||||
* @return boolean
|
||||
*/
|
||||
public function isSaleable()
|
||||
{
|
||||
|
|
@ -43,16 +180,6 @@ class Downloadable extends AbstractType
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this product can have inventory
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function isStockable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns validation rules
|
||||
*
|
||||
|
|
@ -70,4 +197,66 @@ class Downloadable extends AbstractType
|
|||
'downloadable_links.*.sort_order' => 'required',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add product. Returns error message if can't prepare product.
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function prepareForCart($data)
|
||||
{
|
||||
if(! isset($data['links']) || ! count($data['links']))
|
||||
return trans('shop::app.checkout.cart.integrity.missing_links');
|
||||
|
||||
return parent::prepareForCart($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if product can be configured
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canConfigure()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param array $options1
|
||||
* @param array $options2
|
||||
* @return boolean
|
||||
*/
|
||||
public function compareOptions($options1, $options2)
|
||||
{
|
||||
if ($this->product->id != $options2['product_id'])
|
||||
return false;
|
||||
|
||||
return $options1['links'] == $options2['links'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns additional information for items
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function getAdditionalOptions($data)
|
||||
{
|
||||
$labels = [];
|
||||
|
||||
foreach ($this->product->downloadable_links as $link) {
|
||||
if (in_array($link->id, $data['links']))
|
||||
$labels[] = $link->title;
|
||||
}
|
||||
|
||||
$data['attributes'][0] = [
|
||||
'attribute_name' => 'Downloads',
|
||||
'option_id' => 0,
|
||||
'option_label' => implode(', ', $labels),
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Type;
|
||||
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Product\Repositories\ProductRepository;
|
||||
use Webkul\Product\Repositories\ProductAttributeValueRepository;
|
||||
use Webkul\Product\Repositories\ProductInventoryRepository;
|
||||
use Webkul\Product\Repositories\ProductImageRepository;
|
||||
use Webkul\Product\Repositories\ProductGroupedProductRepository;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
use Webkul\Product\Helpers\Price;
|
||||
use Webkul\Product\Helpers\ProductImage;
|
||||
|
||||
/**
|
||||
* Class Grouped.
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class Grouped extends AbstractType
|
||||
{
|
||||
/**
|
||||
* AttributeRepository instance
|
||||
*
|
||||
* @var AttributeRepository
|
||||
*/
|
||||
protected $attributeRepository;
|
||||
|
||||
/**
|
||||
* ProductRepository instance
|
||||
*
|
||||
* @var ProductRepository
|
||||
*/
|
||||
protected $productRepository;
|
||||
|
||||
/**
|
||||
* ProductAttributeValueRepository instance
|
||||
*
|
||||
* @var ProductAttributeValueRepository
|
||||
*/
|
||||
protected $attributeValueRepository;
|
||||
|
||||
/**
|
||||
* ProductInventoryRepository instance
|
||||
*
|
||||
* @var ProductInventoryRepository
|
||||
*/
|
||||
protected $productInventoryRepository;
|
||||
|
||||
/**
|
||||
* ProductImageRepository instance
|
||||
*
|
||||
* @var ProductImageRepository
|
||||
*/
|
||||
protected $productImageRepository;
|
||||
|
||||
/**
|
||||
* ProductGroupedProductRepository instance
|
||||
*
|
||||
* @var ProductGroupedProductRepository
|
||||
*/
|
||||
protected $productGroupedProductRepository;
|
||||
|
||||
/**
|
||||
* Product price helper instance
|
||||
*
|
||||
* @var Price
|
||||
*/
|
||||
protected $priceHelper;
|
||||
|
||||
/**
|
||||
* Product Image helper instance
|
||||
*
|
||||
* @var ProductImage
|
||||
*/
|
||||
protected $productImageHelper;
|
||||
|
||||
/**
|
||||
* Skip attribute for downloadable product type
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $skipAttributes = ['price', 'cost', 'special_price', 'special_price_from', 'special_price_to', 'width', 'height', 'depth', 'weight'];
|
||||
|
||||
/**
|
||||
* These blade files will be included in product edit page
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $additionalViews = [
|
||||
'admin::catalog.products.accordians.images',
|
||||
'admin::catalog.products.accordians.categories',
|
||||
'admin::catalog.products.accordians.grouped-products',
|
||||
'admin::catalog.products.accordians.product-links'
|
||||
];
|
||||
|
||||
/**
|
||||
* Create a new product type instance.
|
||||
*
|
||||
* @param Webkul\Attribute\Repositories\AttributeRepository $attributeRepository
|
||||
* @param Webkul\Product\Repositories\ProductRepository $productRepository
|
||||
* @param Webkul\Product\Repositories\ProductAttributeValueRepository $attributeValueRepository
|
||||
* @param Webkul\Product\Repositories\ProductInventoryRepository $productInventoryRepository
|
||||
* @param Webkul\Product\Repositories\ProductImageRepository $productImageRepository
|
||||
* @param Webkul\Product\Repositories\ProductGroupedProductRepository $productGroupedProductRepository
|
||||
* @param Webkul\Product\Helpers\Price $priceHelper
|
||||
* @param Webkul\Product\Helpers\ProductImage $productImageHelper
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
AttributeRepository $attributeRepository,
|
||||
ProductRepository $productRepository,
|
||||
ProductAttributeValueRepository $attributeValueRepository,
|
||||
ProductInventoryRepository $productInventoryRepository,
|
||||
ProductImageRepository $productImageRepository,
|
||||
ProductGroupedProductRepository $productGroupedProductRepository,
|
||||
Price $priceHelper,
|
||||
ProductImage $productImageHelper
|
||||
)
|
||||
{
|
||||
parent::__construct(
|
||||
$attributeRepository,
|
||||
$productRepository,
|
||||
$attributeValueRepository,
|
||||
$productInventoryRepository,
|
||||
$productImageRepository,
|
||||
$priceHelper,
|
||||
$productImageHelper
|
||||
);
|
||||
|
||||
$this->productGroupedProductRepository = $productGroupedProductRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param $id
|
||||
* @param string $attribute
|
||||
* @return Product
|
||||
*/
|
||||
public function update(array $data, $id, $attribute = "id")
|
||||
{
|
||||
$product = parent::update($data, $id, $attribute);
|
||||
|
||||
if (request()->route()->getName() != 'admin.catalog.products.massupdate')
|
||||
$this->productGroupedProductRepository->saveGroupedProducts($data, $product);
|
||||
|
||||
return $product;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns validation rules
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getTypeValidationRules()
|
||||
{
|
||||
return [
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add product. Returns error message if can't prepare product.
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function prepareForCart($data)
|
||||
{
|
||||
$products = [];
|
||||
|
||||
foreach ($data['qty'] as $productId => $qty) {
|
||||
$product = $this->productRepository->find($productId);
|
||||
|
||||
$cartProducts = $product->getTypeInstance()->prepareForCart([
|
||||
'product_id' => $productId,
|
||||
'quantity' => $qty,
|
||||
]);
|
||||
|
||||
if (is_string($cartProducts))
|
||||
return $cartProducts;
|
||||
|
||||
$products = array_merge($products, $cartProducts);
|
||||
}
|
||||
|
||||
return $products;
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,8 @@ class Simple extends AbstractType
|
|||
protected $skipAttributes = [];
|
||||
|
||||
/**
|
||||
* These blade files will be included in product edit page
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $additionalViews = [
|
||||
|
|
@ -30,7 +32,7 @@ class Simple extends AbstractType
|
|||
/**
|
||||
* Return true if this product type is saleable
|
||||
*
|
||||
* @return array
|
||||
* @return boolean
|
||||
*/
|
||||
public function isSaleable()
|
||||
{
|
||||
|
|
@ -46,7 +48,7 @@ class Simple extends AbstractType
|
|||
/**
|
||||
* Return true if this product can have inventory
|
||||
*
|
||||
* @return array
|
||||
* @return boolean
|
||||
*/
|
||||
public function isStockable()
|
||||
{
|
||||
|
|
@ -54,13 +56,13 @@ class Simple extends AbstractType
|
|||
}
|
||||
|
||||
/**
|
||||
* Return true if item can be moved to cart from wishlist
|
||||
* @param integer $qty
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canBeMovedFromWishlistToCart()
|
||||
public function haveSufficientQuantity($qty)
|
||||
{
|
||||
return true;
|
||||
return $qty <= $this->totalQuantity() ? true : (core()->getConfigData('catalog.inventory.stock_options.backorders') ? true : false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -91,14 +93,4 @@ class Simple extends AbstractType
|
|||
|
||||
return $total;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $qty
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function haveSufficientQuantity($qty)
|
||||
{
|
||||
return $qty <= $this->totalQuantity() ? true : (core()->getConfigData('catalog.inventory.stock_options.backorders') ? true : false);
|
||||
}
|
||||
}
|
||||
|
|
@ -18,6 +18,8 @@ class Virtual extends AbstractType
|
|||
protected $skipAttributes = ['width', 'height', 'depth', 'weight'];
|
||||
|
||||
/**
|
||||
* These blade files will be included in product edit page
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $additionalViews = [
|
||||
|
|
@ -25,37 +27,4 @@ class Virtual extends AbstractType
|
|||
'admin::catalog.products.accordians.categories',
|
||||
'admin::catalog.products.accordians.product-links'
|
||||
];
|
||||
|
||||
/**
|
||||
* Return true if this product type is saleable
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function isSaleable()
|
||||
{
|
||||
if (! $this->product->status)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this product can have inventory
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function isStockable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if item can be moved to cart from wishlist
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function canBeMovedFromWishlistToCart()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -12,6 +12,16 @@ class InvoiceItem extends Model implements InvoiceItemContract
|
|||
protected $casts = [
|
||||
'additional' => 'array',
|
||||
];
|
||||
|
||||
/**
|
||||
* Retrieve type instance
|
||||
*
|
||||
* @return AbstractType
|
||||
*/
|
||||
public function getTypeInstance()
|
||||
{
|
||||
return $this->order_item->getTypeInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the invoice record associated with the invoice item.
|
||||
|
|
|
|||
|
|
@ -12,6 +12,16 @@ class ShipmentItem extends Model implements ShipmentItemContract
|
|||
protected $casts = [
|
||||
'additional' => 'array',
|
||||
];
|
||||
|
||||
/**
|
||||
* Retrieve type instance
|
||||
*
|
||||
* @return AbstractType
|
||||
*/
|
||||
public function getTypeInstance()
|
||||
{
|
||||
return $this->order_item->getTypeInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the shipment record associated with the shipment item.
|
||||
|
|
|
|||
|
|
@ -2,10 +2,7 @@
|
|||
|
||||
namespace Webkul\Shop\Http\Controllers;
|
||||
|
||||
use Webkul\Checkout\Repositories\CartItemRepository;
|
||||
use Webkul\Product\Repositories\ProductRepository;
|
||||
use Webkul\Customer\Repositories\WishlistRepository;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Cart;
|
||||
|
||||
/**
|
||||
|
|
@ -13,6 +10,7 @@ use Cart;
|
|||
* removing the products in the cart.
|
||||
*
|
||||
* @author Prashant Singh <prashant.singh852@webkul.com> @prashant-webkul
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class CartController extends Controller
|
||||
|
|
@ -24,20 +22,6 @@ class CartController extends Controller
|
|||
*/
|
||||
protected $_config;
|
||||
|
||||
/**
|
||||
* CartItemRepository object
|
||||
*
|
||||
* @var Object
|
||||
*/
|
||||
protected $cartItemRepository;
|
||||
|
||||
/**
|
||||
* ProductRepository object
|
||||
*
|
||||
* @var Object
|
||||
*/
|
||||
protected $productRepository;
|
||||
|
||||
/**
|
||||
* WishlistRepository Repository object
|
||||
*
|
||||
|
|
@ -45,31 +29,16 @@ class CartController extends Controller
|
|||
*/
|
||||
protected $wishlistRepository;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $suppressFlash = false;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @param \Webkul\Checkout\Repositories\CartItemRepository $cartItemRepository
|
||||
* @param \Webkul\Product\Repositories\ProductRepository $productRepository
|
||||
* @param \Webkul\Customer\Repositories\CartItemRepository $wishlistRepository
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
CartItemRepository $cartItemRepository,
|
||||
ProductRepository $productRepository,
|
||||
WishlistRepository $wishlistRepository
|
||||
)
|
||||
public function __construct(WishlistRepository $wishlistRepository)
|
||||
{
|
||||
$this->middleware('customer')->only(['moveToWishlist']);
|
||||
|
||||
$this->cartItemRepository = $cartItemRepository;
|
||||
|
||||
$this->productRepository = $productRepository;
|
||||
|
||||
$this->wishlistRepository = $wishlistRepository;
|
||||
|
||||
$this->_config = request('_config');
|
||||
|
|
@ -78,7 +47,7 @@ class CartController extends Controller
|
|||
/**
|
||||
* Method to populate the cart page which will be populated before the checkout process.
|
||||
*
|
||||
* @return Mixed
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -93,74 +62,38 @@ class CartController extends Controller
|
|||
public function add($id)
|
||||
{
|
||||
try {
|
||||
$product = $this->productRepository->find($id);
|
||||
|
||||
$data = request()->all();
|
||||
|
||||
if ($product->type == 'downloadable' && ! isset($data['links'])) {
|
||||
session()->flash('warning', trans('shop::app.checkout.cart.integrity.missing_links'));
|
||||
|
||||
return redirect()->route('shop.products.index', $product->url_key);
|
||||
} else if ($product->type == 'configurable'
|
||||
&& (! isset($data['selected_configurable_option']) || ! $data['selected_configurable_option'])) {
|
||||
session()->flash('warning', trans('shop::app.checkout.cart.add-config-warning'));
|
||||
|
||||
return redirect()->route('shop.products.index', $product->url_key);
|
||||
}
|
||||
|
||||
Event::fire('checkout.cart.add.before', $id);
|
||||
|
||||
$result = Cart::add($id, request()->except('_token'));
|
||||
|
||||
Event::fire('checkout.cart.add.after', $result);
|
||||
|
||||
Cart::collectTotals();
|
||||
$result = Cart::addProduct($id, request()->all());
|
||||
|
||||
if ($result) {
|
||||
session()->flash('success', trans('shop::app.checkout.cart.item.success'));
|
||||
|
||||
if (auth()->guard('customer')->user()) {
|
||||
$customer = auth()->guard('customer')->user();
|
||||
if ($customer = auth()->guard('customer')->user())
|
||||
$this->wishlistRepository->deleteWhere(['product_id' => $id]);
|
||||
|
||||
if (count($customer->wishlist_items)) {
|
||||
foreach ($customer->wishlist_items as $wishlist) {
|
||||
if ($wishlist->product_id == $id) {
|
||||
$this->wishlistRepository->delete($wishlist->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
if (request()->get('is_buy_now'))
|
||||
return redirect()->route('shop.checkout.onepage.index');
|
||||
} else {
|
||||
session()->flash('warning', trans('shop::app.checkout.cart.item.error-add'));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
return redirect()->route($this->_config['redirect']);
|
||||
|
||||
} catch(\Exception $e) {
|
||||
session()->flash('error', trans($e->getMessage()));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the item from the cart if it exists
|
||||
*
|
||||
* @param integer $itemId
|
||||
* @return Response
|
||||
*/
|
||||
public function remove($itemId)
|
||||
{
|
||||
Event::fire('checkout.cart.delete.before', $itemId);
|
||||
$result = Cart::removeItem($itemId);
|
||||
|
||||
Cart::removeItem($itemId);
|
||||
|
||||
Event::fire('checkout.cart.delete.after', $itemId);
|
||||
|
||||
Cart::collectTotals();
|
||||
if ($result)
|
||||
session()->flash('success', trans('shop::app.checkout.cart.item.success-remove'));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
|
@ -168,47 +101,15 @@ class CartController extends Controller
|
|||
/**
|
||||
* Updates the quantity of the items present in the cart.
|
||||
*
|
||||
* @return response
|
||||
* @return Response
|
||||
*/
|
||||
public function updateBeforeCheckout()
|
||||
{
|
||||
try {
|
||||
$request = request()->except('_token');
|
||||
$result = Cart::updateItems(request()->all());
|
||||
|
||||
foreach ($request['qty'] as $id => $quantity) {
|
||||
if ($quantity <= 0) {
|
||||
session()->flash('warning', trans('shop::app.checkout.cart.quantity.illegal'));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($request['qty'] as $key => $value) {
|
||||
$item = $this->cartItemRepository->findOneByField('id', $key);
|
||||
|
||||
$data['quantity'] = $value;
|
||||
|
||||
Event::fire('checkout.cart.update.before', $item);
|
||||
|
||||
$result = Cart::updateItem($item->product_id, $data, $key);
|
||||
|
||||
if ($result == false) {
|
||||
$this->suppressFlash = true;
|
||||
}
|
||||
|
||||
Event::fire('checkout.cart.update.after', $item);
|
||||
|
||||
unset($item);
|
||||
unset($data);
|
||||
}
|
||||
|
||||
Cart::collectTotals();
|
||||
|
||||
if ($this->suppressFlash) {
|
||||
session()->forget('success');
|
||||
session()->forget('warning');
|
||||
session()->flash('info', trans('shop::app.checkout.cart.partial-cart-update'));
|
||||
}
|
||||
if ($result)
|
||||
session()->flash('success', trans('shop::app.checkout.cart.quantity.success'));
|
||||
} catch(\Exception $e) {
|
||||
session()->flash('error', trans($e->getMessage()));
|
||||
}
|
||||
|
|
@ -216,49 +117,22 @@ class CartController extends Controller
|
|||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function buyNow($id, $quantity = 1)
|
||||
{
|
||||
try {
|
||||
Event::fire('checkout.cart.add.before', $id);
|
||||
|
||||
$result = Cart::proceedToBuyNow($id, $quantity);
|
||||
|
||||
Event::fire('checkout.cart.add.after', $result);
|
||||
|
||||
Cart::collectTotals();
|
||||
|
||||
if (! $result) {
|
||||
return redirect()->back();
|
||||
} else {
|
||||
return redirect()->route('shop.checkout.onepage.index');
|
||||
}
|
||||
} catch(\Exception $e) {
|
||||
session()->flash('error', trans($e->getMessage()));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to move a already added product to wishlist
|
||||
* will run only on customer authentication.
|
||||
* Function to move a already added product to wishlist will run only on customer authentication.
|
||||
*
|
||||
* @param instance cartItem $id
|
||||
* @param integer $id
|
||||
* @return Response
|
||||
*/
|
||||
public function moveToWishlist($id)
|
||||
{
|
||||
$result = Cart::moveToWishlist($id);
|
||||
|
||||
if (! $result) {
|
||||
Cart::collectTotals();
|
||||
|
||||
if ($result) {
|
||||
session()->flash('success', trans('shop::app.wishlist.moved'));
|
||||
|
||||
return redirect()->back();
|
||||
} else {
|
||||
session()->flash('warning', trans('shop::app.wishlist.move-error'));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ class CategoryController extends Controller
|
|||
* Display a listing of the resource.
|
||||
*
|
||||
* @param string $slug
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index($slug)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class DownloadableProductController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index() {
|
||||
return view($this->_config['view']);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ use Webkul\Core\Repositories\SliderRepository;
|
|||
|
||||
/**
|
||||
* loads the home page for the storefront
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ class OnepageController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -104,7 +104,7 @@ class OnepageController extends Controller
|
|||
/**
|
||||
* Return order short summary
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function summary()
|
||||
{
|
||||
|
|
@ -170,7 +170,7 @@ class OnepageController extends Controller
|
|||
/**
|
||||
* Saves payment method.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function savePayment()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class OrderController extends Controller
|
|||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
@ -71,7 +71,7 @@ class OrderController extends Controller
|
|||
* Show the view for the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function view($id)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ class ProductController extends Controller
|
|||
* Display a listing of the resource.
|
||||
*
|
||||
* @param string $slug
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index($slug)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class ReviewController extends Controller
|
|||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @param string $slug
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create($slug)
|
||||
{
|
||||
|
|
@ -103,7 +103,7 @@ class ReviewController extends Controller
|
|||
* Display reviews of particular product.
|
||||
*
|
||||
* @param string $slug
|
||||
* @return \Illuminate\Http\Response
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function show($slug)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ use Webkul\Product\Repositories\SearchRepository;
|
|||
|
||||
/**
|
||||
* Index to handle the view loaded with the search results
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -86,9 +86,6 @@ Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function
|
|||
'view' => 'shop::checkout.success'
|
||||
])->name('shop.checkout.success');
|
||||
|
||||
//Shop buynow button action
|
||||
Route::get('buynow/{id}', 'Webkul\Shop\Http\Controllers\CartController@buyNow')->name('shop.product.buynow');
|
||||
|
||||
//Shop buynow button action
|
||||
Route::get('move/wishlist/{id}', 'Webkul\Shop\Http\Controllers\CartController@moveToWishlist')->name('shop.movetowishlist');
|
||||
|
||||
|
|
|
|||
|
|
@ -402,10 +402,10 @@ input {
|
|||
}
|
||||
|
||||
.sticker {
|
||||
border-radius: 100px;
|
||||
border-bottom-right-radius: 15px;
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
top: 15px;
|
||||
left: 15px;
|
||||
text-transform: uppercase;
|
||||
padding: 4px 13px;
|
||||
font-size: 14px;
|
||||
|
|
@ -1828,8 +1828,76 @@ section.product-detail {
|
|||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
a {
|
||||
float: right;
|
||||
margin-top: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.grouped-product-container {
|
||||
.grouped-product-list {
|
||||
padding: 15px 0;
|
||||
border-top: solid 1px rgba(162, 162, 162, 0.2);
|
||||
|
||||
ul {
|
||||
li {
|
||||
margin-bottom: 15px;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
span {
|
||||
font-weight: 600;
|
||||
|
||||
&:last-child {
|
||||
float: right;
|
||||
width: 50px;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
|
||||
.product-price {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 0;
|
||||
font-size: 14px;
|
||||
|
||||
.special-price {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.qty {
|
||||
float: right;
|
||||
|
||||
.control-group {
|
||||
display: inline-block;
|
||||
max-width: 50px;
|
||||
text-align: center;
|
||||
margin-bottom: 0;
|
||||
|
||||
.control {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -351,7 +351,9 @@ return [
|
|||
'less-quantity' => 'Quantity can not be less than one.',
|
||||
'samples' => 'Samples',
|
||||
'links' => 'Links',
|
||||
'sample' => 'Sample'
|
||||
'sample' => 'Sample',
|
||||
'name' => 'Name',
|
||||
'qty' => 'Qty'
|
||||
],
|
||||
|
||||
'wishlist' => [
|
||||
|
|
|
|||
|
|
@ -19,12 +19,9 @@
|
|||
<div class="cart-item-list" style="margin-top: 0">
|
||||
@csrf
|
||||
@foreach ($cart->items as $key => $item)
|
||||
<?php
|
||||
if ($item->type == "configurable")
|
||||
$productBaseImage = $productImageHelper->getProductBaseImage($item->child->product);
|
||||
else
|
||||
$productBaseImage = $productImageHelper->getProductBaseImage($item->product);
|
||||
?>
|
||||
@php
|
||||
$productBaseImage = $item->product->getTypeInstance()->getBaseImage($item);
|
||||
@endphp
|
||||
|
||||
<div class="item mt-5">
|
||||
<div class="item-image" style="margin-right: 15px;">
|
||||
|
|
@ -55,17 +52,12 @@
|
|||
|
||||
{!! view_render_event('bagisto.shop.checkout.cart.item.options.before', ['item' => $item]) !!}
|
||||
|
||||
@if ($item->type == 'configurable')
|
||||
|
||||
<div class="summary">
|
||||
|
||||
{{ Cart::getProductAttributeOptionDetails($item->child->product)['html'] }}
|
||||
|
||||
</div>
|
||||
@elseif ($item->type == 'downloadable')
|
||||
<div class="summary">
|
||||
@if (isset($item->additional['attributes']))
|
||||
<div class="item-options">
|
||||
|
||||
<b>Downloads : </b>{{ $item->additional['link_lables'] }}
|
||||
@foreach ($item->additional['attributes'] as $attribute)
|
||||
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
|
|
|||
|
|
@ -42,12 +42,9 @@
|
|||
|
||||
<div class="item">
|
||||
<div class="item-image" >
|
||||
<?php
|
||||
if ($item->type == "configurable")
|
||||
$images = $productImageHelper->getProductBaseImage($item->child->product);
|
||||
else
|
||||
$images = $productImageHelper->getProductBaseImage($item->product);
|
||||
?>
|
||||
@php
|
||||
$images = $item->product->getTypeInstance()->getBaseImage($item);
|
||||
@endphp
|
||||
<img src="{{ $images['small_image_url'] }}" />
|
||||
</div>
|
||||
|
||||
|
|
@ -60,15 +57,13 @@
|
|||
|
||||
|
||||
{!! view_render_event('bagisto.shop.checkout.cart-mini.item.options.before', ['item' => $item]) !!}
|
||||
|
||||
@if ($item->type == "configurable")
|
||||
<div class="item-options">
|
||||
{{ trim(Cart::getProductAttributeOptionDetails($item->child->product)['html']) }}
|
||||
</div>
|
||||
@elseif ($item->type == 'downloadable')
|
||||
|
||||
@if (isset($item->additional['attributes']))
|
||||
<div class="item-options">
|
||||
|
||||
<b>Downloads : </b>{{ $item->additional['link_lables'] }}
|
||||
@foreach ($item->additional['attributes'] as $attribute)
|
||||
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
@endif
|
||||
|
|
|
|||
|
|
@ -66,12 +66,9 @@
|
|||
|
||||
<div class="cart-item-list mt-20">
|
||||
@foreach ($cart->items as $item)
|
||||
|
||||
<?php
|
||||
$product = $item->product;
|
||||
|
||||
$productBaseImage = $productImageHelper->getProductBaseImage($product);
|
||||
?>
|
||||
@php
|
||||
$productBaseImage = $item->product->getTypeInstance()->getBaseImage($item);
|
||||
@endphp
|
||||
|
||||
<div class="item mb-5" style="margin-bottom: 5px;">
|
||||
<div class="item-image">
|
||||
|
|
@ -83,7 +80,7 @@
|
|||
{!! view_render_event('bagisto.shop.checkout.name.before', ['item' => $item]) !!}
|
||||
|
||||
<div class="item-title">
|
||||
{{ $product->name }}
|
||||
{{ $item->product->name }}
|
||||
</div>
|
||||
|
||||
{!! view_render_event('bagisto.shop.checkout.name.after', ['item' => $item]) !!}
|
||||
|
|
@ -112,23 +109,19 @@
|
|||
|
||||
{!! view_render_event('bagisto.shop.checkout.quantity.after', ['item' => $item]) !!}
|
||||
|
||||
@if ($product->type == 'configurable')
|
||||
{!! view_render_event('bagisto.shop.checkout.options.before', ['item' => $item]) !!}
|
||||
{!! view_render_event('bagisto.shop.checkout.options.before', ['item' => $item]) !!}
|
||||
|
||||
@if (isset($item->additional['attributes']))
|
||||
<div class="item-options">
|
||||
|
||||
@foreach ($item->additional['attributes'] as $attribute)
|
||||
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}
|
||||
@endforeach
|
||||
|
||||
<div class="summary" >
|
||||
{{ Cart::getProductAttributeOptionDetails($item->child->product)['html'] }}
|
||||
</div>
|
||||
|
||||
{!! view_render_event('bagisto.shop.checkout.options.after', ['item' => $item]) !!}
|
||||
@elseif ($product->type == 'downloadable')
|
||||
{!! view_render_event('bagisto.shop.checkout.downlodable_links.before', ['item' => $item]) !!}
|
||||
|
||||
<div class="summary">
|
||||
<b>Downloads : </b>{{ $item->additional['link_lables'] }}
|
||||
</div>
|
||||
|
||||
{!! view_render_event('bagisto.shop.checkout.downlodable_links.after', ['item' => $item]) !!}
|
||||
@endif
|
||||
|
||||
{!! view_render_event('bagisto.shop.checkout.options.after', ['item' => $item]) !!}
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
|
|
|||
|
|
@ -66,15 +66,19 @@
|
|||
@foreach ($order->items as $item)
|
||||
<tr>
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.SKU') }}">
|
||||
{{ $item->type == 'configurable' ? $item->child->sku : $item->sku }}
|
||||
{{ $item->getTypeInstance()->getOrderedItem($item)->sku }}
|
||||
</td>
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.product-name') }}">
|
||||
{{ $item->name }}
|
||||
|
||||
@if (isset($item->additional['attributes']))
|
||||
<div class="item-options">
|
||||
|
||||
@foreach ($item->additional['attributes'] as $attribute)
|
||||
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}
|
||||
@endforeach
|
||||
|
||||
@if ($html = $item->getOptionDetailHtml())
|
||||
<p>{{ $html }}</p>
|
||||
@elseif ($item->type == 'downloadable')
|
||||
<p><b>Downloads : </b>{{ $item->getDownloadableDetailHtml() }}</p>
|
||||
</div>
|
||||
@endif
|
||||
</td>
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.price') }}">{{ core()->formatPrice($item->price, $order->order_currency_code) }}</td>
|
||||
|
|
@ -200,7 +204,7 @@
|
|||
|
||||
@foreach ($invoice->items as $item)
|
||||
<tr>
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.SKU') }}">{{ $item->child ? $item->child->sku : $item->sku }}</td>
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.SKU') }}">{{ $item->getTypeInstance()->getOrderedItem($item)->sku }}</td>
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.product-name') }}">{{ $item->name }}</td>
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.price') }}">{{ core()->formatPrice($item->price, $order->order_currency_code) }}</td>
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.qty') }}">{{ $item->qty }}</td>
|
||||
|
|
|
|||
|
|
@ -1,72 +1,86 @@
|
|||
@extends('shop::layouts.master')
|
||||
|
||||
@section('content-wrapper')
|
||||
<div class="account-content">
|
||||
@inject ('productImageHelper', 'Webkul\Product\Helpers\ProductImage')
|
||||
|
||||
<div class="account-content">
|
||||
@inject ('productImageHelper', 'Webkul\Product\Helpers\ProductImage')
|
||||
@include('shop::customers.account.partials.sidemenu')
|
||||
|
||||
@include('shop::customers.account.partials.sidemenu')
|
||||
@inject ('reviewHelper', 'Webkul\Product\Helpers\Review')
|
||||
|
||||
<div class="account-layout">
|
||||
<div class="account-layout">
|
||||
|
||||
<div class="account-head mb-15">
|
||||
<span class="account-heading">{{ __('shop::app.wishlist.title') }}</span>
|
||||
<div class="account-head mb-15">
|
||||
<span class="account-heading">{{ __('shop::app.wishlist.title') }}</span>
|
||||
|
||||
@if (count($items))
|
||||
<div class="account-action">
|
||||
<a href="{{ route('customer.wishlist.removeall') }}">{{ __('shop::app.wishlist.deleteall') }}</a>
|
||||
@if (count($items))
|
||||
<div class="account-action">
|
||||
<a href="{{ route('customer.wishlist.removeall') }}">{{ __('shop::app.wishlist.deleteall') }}</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="horizontal-rule"></div>
|
||||
</div>
|
||||
@endif
|
||||
<div class="horizontal-rule"></div>
|
||||
</div>
|
||||
|
||||
{!! view_render_event('bagisto.shop.customers.account.wishlist.list.before', ['wishlist' => $items]) !!}
|
||||
{!! view_render_event('bagisto.shop.customers.account.wishlist.list.before', ['wishlist' => $items]) !!}
|
||||
|
||||
<div class="account-items-list">
|
||||
<div class="account-items-list">
|
||||
|
||||
@if ($items->count())
|
||||
@foreach ($items as $item)
|
||||
<div class="account-item-card mt-15 mb-15">
|
||||
<div class="media-info">
|
||||
@php
|
||||
$image = $productImageHelper->getProductBaseImage($item->product);
|
||||
@endphp
|
||||
@if ($items->count())
|
||||
@foreach ($items as $item)
|
||||
<div class="account-item-card mt-15 mb-15">
|
||||
<div class="media-info">
|
||||
@php
|
||||
$image = $item->product->getTypeInstance()->getBaseImage($item);
|
||||
@endphp
|
||||
|
||||
<img class="media" src="{{ $image['small_image_url'] }}" />
|
||||
<img class="media" src="{{ $image['small_image_url'] }}" />
|
||||
|
||||
<div class="info">
|
||||
<div class="product-name">
|
||||
{{$item->product->name}}
|
||||
<div class="info">
|
||||
<div class="product-name">
|
||||
{{ $item->product->name }}
|
||||
|
||||
@if (isset($item->additional['attributes']))
|
||||
<div class="item-options">
|
||||
|
||||
@foreach ($item->additional['attributes'] as $attribute)
|
||||
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<span class="stars" style="display: inline">
|
||||
@for ($i = 1; $i <= $reviewHelper->getAverageRating($item->product); $i++)
|
||||
<span class="icon star-icon"></span>
|
||||
@endfor
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@inject ('reviewHelper', 'Webkul\Product\Helpers\Review')
|
||||
<div class="operations">
|
||||
<a class="mb-50" href="{{ route('customer.wishlist.remove', $item->id) }}">
|
||||
<span class="icon trash-icon"></span>
|
||||
</a>
|
||||
|
||||
<span class="stars" style="display: inline">
|
||||
@for($i=1;$i<=$reviewHelper->getAverageRating($item->product);$i++)
|
||||
<span class="icon star-icon"></span>
|
||||
@endfor
|
||||
</span>
|
||||
<a href="{{ route('customer.wishlist.move', $item->id) }}" class="btn btn-primary btn-md">
|
||||
{{ __('shop::app.wishlist.move-to-cart') }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="horizontal-rule mb-10 mt-10"></div>
|
||||
@endforeach
|
||||
@else
|
||||
<div class="empty">
|
||||
{{ __('customer::app.wishlist.empty') }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
<div class="operations">
|
||||
<a class="mb-50" href="{{ route('customer.wishlist.remove', $item->id) }}"><span class="icon trash-icon"></span></a>
|
||||
{!! view_render_event('bagisto.shop.customers.account.wishlist.list.after', ['wishlist' => $items]) !!}
|
||||
|
||||
<a href="{{ route('customer.wishlist.move', $item->id) }}" class="btn btn-primary btn-md">{{ __('shop::app.wishlist.move-to-cart') }}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="horizontal-rule mb-10 mt-10"></div>
|
||||
@endforeach
|
||||
|
||||
@else
|
||||
<div class="empty">
|
||||
{{ __('customer::app.wishlist.empty') }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
{!! view_render_event('bagisto.shop.customers.account.wishlist.list.after', ['wishlist' => $items]) !!}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -110,19 +110,19 @@
|
|||
<tbody>
|
||||
@foreach ($order->items as $item)
|
||||
<tr>
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.SKU') }}" style="text-align: left;padding: 8px">{{ $item->child ? $item->child->sku : $item->sku }}</td>
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.SKU') }}" style="text-align: left;padding: 8px">{{ $item->getTypeInstance()->getOrderedItem($item)->sku }}</td>
|
||||
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.product-name') }}" style="text-align: left;padding: 8px">
|
||||
{{ $item->name }}
|
||||
|
||||
@if (isset($item->additional['attributes']))
|
||||
<div class="item-options">
|
||||
|
||||
@foreach ($item->additional['attributes'] as $attribute)
|
||||
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}
|
||||
@endforeach
|
||||
|
||||
@if ($html = $item->getOptionDetailHtml())
|
||||
<div style="">
|
||||
<label style="margin-top: 10px; font-size: 16px;color: #5E5E5E; display: block;">
|
||||
{{ $html }}
|
||||
</label>
|
||||
</div>
|
||||
@elseif ($item->type == 'downloadable')
|
||||
<p><b>Downloads : </b>{{ $item->getDownloadableDetailHtml() }}</p>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
|
|
|||
|
|
@ -121,19 +121,19 @@
|
|||
<tbody>
|
||||
@foreach ($shipment->items as $item)
|
||||
<tr>
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.SKU') }}" style="text-align: left;padding: 8px">{{ $item->child ? $item->child->sku : $item->sku }}</td>
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.SKU') }}" style="text-align: left;padding: 8px">{{ $item->getTypeInstance()->getOrderedItem($item)->sku }}</td>
|
||||
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.product-name') }}" style="text-align: left;padding: 8px">
|
||||
{{ $item->name }}
|
||||
|
||||
@if (isset($item->additional['attributes']))
|
||||
<div class="item-options">
|
||||
|
||||
@foreach ($item->additional['attributes'] as $attribute)
|
||||
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}
|
||||
@endforeach
|
||||
|
||||
@if ($html = $item->getOptionDetailHtml())
|
||||
<div style="">
|
||||
<label style="margin-top: 10px; font-size: 16px;color: #5E5E5E; display: block;">
|
||||
{{ $html }}
|
||||
</label>
|
||||
</div>
|
||||
@elseif ($item->type == 'downloadable')
|
||||
<p><b>Downloads : </b>{{ $item->getDownloadableDetailHtml() }}</p>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
|
|
|||
|
|
@ -115,15 +115,15 @@
|
|||
<tr>
|
||||
<td data-value="{{ __('shop::app.customer.account.order.view.product-name') }}" style="text-align: left;padding: 8px">
|
||||
{{ $item->name }}
|
||||
|
||||
@if (isset($item->additional['attributes']))
|
||||
<div class="item-options">
|
||||
|
||||
@foreach ($item->additional['attributes'] as $attribute)
|
||||
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}
|
||||
@endforeach
|
||||
|
||||
@if ($html = $item->getOptionDetailHtml())
|
||||
<div style="">
|
||||
<label style="margin-top: 10px; font-size: 16px;color: #5E5E5E; display: block;">
|
||||
{{ $html }}
|
||||
</label>
|
||||
</div>
|
||||
@elseif ($item->type == 'downloadable')
|
||||
<p><b>Downloads : </b>{{ $item->getDownloadableDetailHtml() }}</p>
|
||||
@endif
|
||||
</td>
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue