Bundle product data save completed
This commit is contained in:
parent
ec567d624f
commit
7352a97797
|
|
@ -248,8 +248,7 @@ 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/search-simple-products', 'Webkul\Product\Http\Controllers\ProductController@searchSimpleProducts')->name('admin.catalog.products.search_simple_product');
|
||||
|
||||
Route::get('/products/{id}/{attribute_id}', 'Webkul\Product\Http\Controllers\ProductController@download')->defaults('_config', [
|
||||
'view' => 'admin.catalog.products.edit'
|
||||
|
|
|
|||
|
|
@ -387,7 +387,16 @@ return [
|
|||
'grouped-products' => 'Grouped Products',
|
||||
'search-products' => 'Search Products',
|
||||
'no-result-found' => 'Products not found with same name.',
|
||||
'bundle-items' => 'Bundle Items'
|
||||
'bundle-items' => 'Bundle Items',
|
||||
'add-option-btn-title' => 'Add Option',
|
||||
'option-title' => 'Option Title',
|
||||
'input-type' => 'Input Type',
|
||||
'is-required' => 'Is Required',
|
||||
'select' => 'Select',
|
||||
'radio' => 'Radio',
|
||||
'checkbox' => 'Checkbox',
|
||||
'multiselect' => 'Multiselect',
|
||||
'new-option' => 'New Option'
|
||||
],
|
||||
'attributes' => [
|
||||
'title' => 'الصفات',
|
||||
|
|
|
|||
|
|
@ -417,7 +417,16 @@ return [
|
|||
'search-products' => 'Search Products',
|
||||
'no-result-found' => 'Products not found with same name.',
|
||||
'channel' => 'Channels',
|
||||
'bundle-items' => 'Bundle Items'
|
||||
'bundle-items' => 'Bundle Items',
|
||||
'add-option-btn-title' => 'Add Option',
|
||||
'option-title' => 'Option Title',
|
||||
'input-type' => 'Input Type',
|
||||
'is-required' => 'Is Required',
|
||||
'select' => 'Select',
|
||||
'radio' => 'Radio',
|
||||
'checkbox' => 'Checkbox',
|
||||
'multiselect' => 'Multiselect',
|
||||
'new-option' => 'New Option'
|
||||
],
|
||||
|
||||
'attributes' => [
|
||||
|
|
|
|||
|
|
@ -399,7 +399,16 @@ return [
|
|||
'product-search-hint' => 'شروع به تایپ نام محصول کنید',
|
||||
'no-result-found' => 'محصولاتی با همین نام یافت نشد',
|
||||
'searching' => 'جست و جو ...',
|
||||
'bundle-items' => 'Bundle Items'
|
||||
'bundle-items' => 'Bundle Items',
|
||||
'add-option-btn-title' => 'Add Option',
|
||||
'option-title' => 'Option Title',
|
||||
'input-type' => 'Input Type',
|
||||
'is-required' => 'Is Required',
|
||||
'select' => 'Select',
|
||||
'radio' => 'Radio',
|
||||
'checkbox' => 'Checkbox',
|
||||
'multiselect' => 'Multiselect',
|
||||
'new-option' => 'New Option'
|
||||
],
|
||||
|
||||
'attributes' => [
|
||||
|
|
|
|||
|
|
@ -393,7 +393,16 @@ return [
|
|||
'grouped-products' => 'Grouped Products',
|
||||
'search-products' => 'Search Products',
|
||||
'no-result-found' => 'Products not found with same name.',
|
||||
'bundle-items' => 'Bundle Items'
|
||||
'bundle-items' => 'Bundle Items',
|
||||
'add-option-btn-title' => 'Add Option',
|
||||
'option-title' => 'Option Title',
|
||||
'input-type' => 'Input Type',
|
||||
'is-required' => 'Is Required',
|
||||
'select' => 'Select',
|
||||
'radio' => 'Radio',
|
||||
'checkbox' => 'Checkbox',
|
||||
'multiselect' => 'Multiselect',
|
||||
'new-option' => 'New Option'
|
||||
],
|
||||
'attributes' => [
|
||||
'title' => 'Atributos',
|
||||
|
|
|
|||
|
|
@ -5,7 +5,344 @@
|
|||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.bundle.controls.before', ['product' => $product]) !!}
|
||||
|
||||
<bundle-option-list></bundle-option-list>
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.bundle.controls.after', ['product' => $product]) !!}
|
||||
|
||||
</div>
|
||||
</accordian>
|
||||
</accordian>
|
||||
|
||||
@push('scripts')
|
||||
@parent
|
||||
|
||||
<script type="text/x-template" id="bundle-option-list-template">
|
||||
<div class="">
|
||||
<button type="button" class="btn btn-md btn-primary" @click="addOption" style="margin-bottom: 20px;">
|
||||
{{ __('admin::app.catalog.products.add-option-btn-title') }}
|
||||
</button>
|
||||
|
||||
<bundle-option-item
|
||||
v-for='(option, index) in options'
|
||||
:option="option"
|
||||
:key="index"
|
||||
:index="index"
|
||||
@onRemoveOption="removeOption($event)"
|
||||
></bundle-option-item>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="bundle-option-item-template">
|
||||
<accordian :active="true">
|
||||
<div slot="header">
|
||||
<i class="icon expand-icon left"></i>
|
||||
<h1 v-if="option.label">@{{ option.label }}</h1>
|
||||
<h1 v-else>{{ __('admin::app.catalog.products.new-option') }}</h1>
|
||||
<i class="icon trash-icon" @click="removeOption()"></i>
|
||||
</div>
|
||||
|
||||
<div slot="body">
|
||||
<div class="control-group" :class="[errors.has(titleInputName + '[label]') ? 'has-error' : '']">
|
||||
<label class="required">{{ __('admin::app.catalog.products.option-title') }}</label>
|
||||
|
||||
<input type="text" v-validate="'required'" :name="titleInputName + '[label]'" v-model="option.label" class="control" data-vv-as=""{{ __('admin::app.catalog.products.option-title') }}""/>
|
||||
|
||||
<span class="control-error" v-if="errors.has(titleInputName + '[label]')">@{{ errors.first(titleInputName + '[label]') }}</span>
|
||||
</div>
|
||||
|
||||
<div class="control-group" :class="[errors.has(inputName + '[type]') ? 'has-error' : '']">
|
||||
<label class="required">{{ __('admin::app.catalog.products.input-type') }}</label>
|
||||
|
||||
<select v-validate="'required'" :name="inputName + '[type]'" v-model="option.type" class="control" data-vv-as=""{{ __('admin::app.catalog.products.input-type') }}"">
|
||||
<option value="select">{{ __('admin::app.catalog.products.select') }}</option>
|
||||
<option value="radio">{{ __('admin::app.catalog.products.radio') }}</option>
|
||||
<option value="checkbox">{{ __('admin::app.catalog.products.checkbox') }}</option>
|
||||
<option value="multiselect">{{ __('admin::app.catalog.products.multiselect') }}</option>
|
||||
</select>
|
||||
|
||||
<span class="control-error" v-if="errors.has(inputName + '[type]')">@{{ errors.first(inputName + '[type]') }}</span>
|
||||
</div>
|
||||
|
||||
<div class="control-group" :class="[errors.has(inputName + '[is_required]') ? 'has-error' : '']">
|
||||
<label class="required">{{ __('admin::app.catalog.products.is-required') }}</label>
|
||||
|
||||
<select v-validate="'required'" :name="inputName + '[is_required]'" v-model="option.is_required" class="control" data-vv-as=""{{ __('admin::app.catalog.products.is-required') }}"">
|
||||
<option value="1">{{ __('admin::app.catalog.products.yes') }}</option>
|
||||
<option value="0">{{ __('admin::app.catalog.products.no') }}</option>
|
||||
</select>
|
||||
|
||||
<span class="control-error" v-if="errors.has(inputName + '[is_required]')">@{{ errors.first(inputName + '[is_required]') }}</span>
|
||||
</div>
|
||||
|
||||
<div class="control-group" :class="[errors.has(inputName + '[sort_order]') ? 'has-error' : '']">
|
||||
<label class="required">{{ __('admin::app.catalog.products.sort-order') }}</label>
|
||||
|
||||
<input type="text" v-validate="'required'" :name="inputName + '[sort_order]'" v-model="option.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>
|
||||
|
||||
<div class="section">
|
||||
<div class="secton-title">
|
||||
<span>Products</span>
|
||||
</div>
|
||||
|
||||
<div class="section-content">
|
||||
<bundle-product-list
|
||||
:bundle-option-products="option.bundle_option_products"
|
||||
:control-name="inputName">
|
||||
</bundle-product-list>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</accordian>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="bundle-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="addProduct(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>
|
||||
|
||||
<bundle-product-item
|
||||
v-for='(product, index) in bundle_option_products'
|
||||
:product="product"
|
||||
:key="index"
|
||||
:index="index"
|
||||
:control-name="controlName"
|
||||
@onRemoveProduct="removeProduct($event)">
|
||||
</bundle-product-item>
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="bundle-product-item-template">
|
||||
<tr>
|
||||
<td>
|
||||
@{{ product.product.name }}
|
||||
<input type="hidden" :name="[inputName + '[product_id]']" :value="product.product.id"/>
|
||||
</td>
|
||||
|
||||
<td>@{{ product.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="product.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="product.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="removeProduct()"></i>
|
||||
</td>
|
||||
</tr>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
Vue.component('bundle-option-list', {
|
||||
|
||||
template: '#bundle-option-list-template',
|
||||
|
||||
inject: ['$validator'],
|
||||
|
||||
data: function() {
|
||||
return {
|
||||
options: @json($product->bundle_options()->with(['product', 'bundle_option_products', 'bundle_option_products.product'])->get())
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
addOption: function() {
|
||||
this.options.push({
|
||||
label: '',
|
||||
type: 'select',
|
||||
is_required: 1,
|
||||
sort_order: 0,
|
||||
bundle_option_products: []
|
||||
});
|
||||
},
|
||||
|
||||
removeOption: function(option) {
|
||||
let index = this.options.indexOf(option)
|
||||
|
||||
this.options.splice(index, 1)
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
Vue.component('bundle-option-item', {
|
||||
|
||||
template: '#bundle-option-item-template',
|
||||
|
||||
props: ['index', 'option'],
|
||||
|
||||
inject: ['$validator'],
|
||||
|
||||
data: function() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
titleInputName: function () {
|
||||
if (this.option.id)
|
||||
return "bundle_options[" + this.option.id + "]" + '[{{$locale}}]';
|
||||
|
||||
return "bundle_options[option_" + this.index + "]" + '[{{$locale}}]';
|
||||
},
|
||||
|
||||
inputName: function () {
|
||||
if (this.option.id)
|
||||
return "bundle_options[" + this.option.id + "]";
|
||||
|
||||
return "bundle_options[option_" + this.index + "]";
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
removeOption: function() {
|
||||
this.$emit('onRemoveOption', this.option)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Vue.component('bundle-product-list', {
|
||||
|
||||
template: '#bundle-product-list-template',
|
||||
|
||||
inject: ['$validator'],
|
||||
|
||||
props: ['controlName', 'bundleOptionProducts'],
|
||||
|
||||
data: function() {
|
||||
return {
|
||||
search_term: '',
|
||||
|
||||
is_searching: false,
|
||||
|
||||
searched_results: [],
|
||||
|
||||
bundle_option_products: this.bundleOptionProducts
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
'search_term': function(newVal, oldVal) {
|
||||
this.search('products')
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
addProduct: function(item, key) {
|
||||
this.bundle_option_products.push({
|
||||
product: item,
|
||||
qty: 0,
|
||||
sort_order: 0
|
||||
});
|
||||
|
||||
this.search_term = '';
|
||||
|
||||
this.searched_result = [];
|
||||
},
|
||||
|
||||
removeProduct: function(product) {
|
||||
let index = this.bundle_option_products.indexOf(product)
|
||||
|
||||
this.bundle_option_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_simple_product') }}", {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('bundle-product-item', {
|
||||
|
||||
template: '#bundle-product-item-template',
|
||||
|
||||
props: ['controlName', 'index', 'product'],
|
||||
|
||||
inject: ['$validator'],
|
||||
|
||||
computed: {
|
||||
inputName: function () {
|
||||
if (this.product.id)
|
||||
return this.controlName + "[products][" + this.product.id + "]";
|
||||
|
||||
return this.controlName + "[products][product_" + this.index + "]";
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
removeProduct: function () {
|
||||
this.$emit('onRemoveProduct', this.product)
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@endpush
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.categories.before', ['product' => $product]) !!}
|
||||
|
||||
<accordian :title="'{{ __('admin::app.catalog.products.categories') }}'" :active="true">
|
||||
<accordian :title="'{{ __('admin::app.catalog.products.categories') }}'" :active="false">
|
||||
<div slot="body">
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.categories.controls.before', ['product' => $product]) !!}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
])->pluck('channel')->unique()->toArray();
|
||||
?>
|
||||
|
||||
<accordian :title="'{{ __('admin::app.catalog.products.channel') }}'" :active="true">
|
||||
<accordian :title="'{{ __('admin::app.catalog.products.channel') }}'" :active="false">
|
||||
<div slot="body">
|
||||
<div class="control-group" :class="[errors.has('channels[]') ? 'has-error' : '']">
|
||||
<label for="channels" class="required">{{ __('admin::app.catalog.products.channel') }}</label>
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@
|
|||
|
||||
var this_this = this;
|
||||
|
||||
this.$http.get ("{{ route('admin.catalog.products.search_product_for_grouped_association', $product->id) }}", {params: {query: this.search_term}})
|
||||
this.$http.get ("{{ route('admin.catalog.products.search_simple_product') }}", {params: {query: this.search_term}})
|
||||
.then (function(response) {
|
||||
this_this.searched_results = response.data;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.images.before', ['product' => $product]) !!}
|
||||
|
||||
<accordian :title="'{{ __('admin::app.catalog.products.images') }}'" :active="true">
|
||||
<accordian :title="'{{ __('admin::app.catalog.products.images') }}'" :active="false">
|
||||
<div slot="body">
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.images.controls.before', ['product' => $product]) !!}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.inventories.before', ['product' => $product]) !!}
|
||||
|
||||
<accordian :title="'{{ __('admin::app.catalog.products.inventories') }}'" :active="true">
|
||||
<accordian :title="'{{ __('admin::app.catalog.products.inventories') }}'" :active="false">
|
||||
<div slot="body">
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.inventories.controls.before', ['product' => $product]) !!}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.product_links.before', ['product' => $product]) !!}
|
||||
|
||||
<accordian :title="'{{ __('admin::app.catalog.products.product-link') }}'" :active="true">
|
||||
<accordian :title="'{{ __('admin::app.catalog.products.product-link') }}'" :active="false">
|
||||
<div slot="body">
|
||||
|
||||
<linked-products></linked-products>
|
||||
|
|
|
|||
|
|
@ -59,14 +59,14 @@
|
|||
|
||||
<input name="_method" type="hidden" value="PUT">
|
||||
|
||||
@foreach ($product->attribute_family->attribute_groups as $attributeGroup)
|
||||
@foreach ($product->attribute_family->attribute_groups as $index => $attributeGroup)
|
||||
<?php $customAttributes = $product->getEditableAttributes($attributeGroup); ?>
|
||||
|
||||
@if (count($customAttributes))
|
||||
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.' . $attributeGroup->name . '.before', ['product' => $product]) !!}
|
||||
|
||||
<accordian :title="'{{ __($attributeGroup->name) }}'" :active="true">
|
||||
<accordian :title="'{{ __($attributeGroup->name) }}'" :active="{{$index == 0 ? 'true' : 'false'}}">
|
||||
<div slot="body">
|
||||
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.' . $attributeGroup->name . '.controls.before', ['product' => $product]) !!}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@
|
|||
|
||||
namespace Webkul\Product\Contracts;
|
||||
|
||||
interface ProductBundleProduct
|
||||
interface ProductBundleOptionProduct
|
||||
{
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ use Illuminate\Support\Facades\Schema;
|
|||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateProductBundleProductsTable extends Migration
|
||||
class CreateProductBundleOptionProductsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
|
|
@ -13,9 +13,10 @@ class CreateProductBundleProductsTable extends Migration
|
|||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('product_bundle_products', function (Blueprint $table) {
|
||||
Schema::create('product_bundle_option_products', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('qty')->default(0);
|
||||
$table->boolean('is_default')->default(0);
|
||||
$table->integer('sort_order')->default(0);
|
||||
|
||||
$table->integer('product_bundle_option_id')->unsigned();
|
||||
|
|
@ -33,6 +34,6 @@ class CreateProductBundleProductsTable extends Migration
|
|||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('product_bundle_products');
|
||||
Schema::dropIfExists('product_bundle_option_products');
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,6 @@ 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;
|
||||
|
|
@ -70,13 +69,6 @@ class ProductController extends Controller
|
|||
*/
|
||||
protected $inventorySourceRepository;
|
||||
|
||||
/**
|
||||
* ProductGroupedProductRepository object
|
||||
*
|
||||
* @var Object
|
||||
*/
|
||||
protected $productGroupedProductRepository;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
|
|
@ -86,7 +78,6 @@ 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(
|
||||
|
|
@ -95,8 +86,7 @@ class ProductController extends Controller
|
|||
ProductDownloadableLinkRepository $productDownloadableLinkRepository,
|
||||
ProductDownloadableSampleRepository $productDownloadableSampleRepository,
|
||||
AttributeFamilyRepository $attributeFamilyRepository,
|
||||
InventorySourceRepository $inventorySourceRepository,
|
||||
ProductGroupedProductRepository $productGroupedProductRepository
|
||||
InventorySourceRepository $inventorySourceRepository
|
||||
)
|
||||
{
|
||||
$this->_config = request('_config');
|
||||
|
|
@ -112,8 +102,6 @@ class ProductController extends Controller
|
|||
$this->attributeFamilyRepository = $attributeFamilyRepository;
|
||||
|
||||
$this->inventorySourceRepository = $inventorySourceRepository;
|
||||
|
||||
$this->productGroupedProductRepository = $productGroupedProductRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -367,14 +355,14 @@ class ProductController extends Controller
|
|||
}
|
||||
|
||||
/**
|
||||
* Search simple products for grouped product association
|
||||
* Search simple products
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function searchProductForGroupedAssociation()
|
||||
public function searchSimpleProducts()
|
||||
{
|
||||
return response()->json(
|
||||
$this->productGroupedProductRepository->searchSimpleProducts(request('id'), request()->input('query'))
|
||||
$this->productRepository->searchSimpleProducts(request()->input('query'))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -165,6 +165,14 @@ class Product extends Model implements ProductContract
|
|||
return $this->hasMany(ProductGroupedProductProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bundle options that owns the product.
|
||||
*/
|
||||
public function bundle_options()
|
||||
{
|
||||
return $this->hasMany(ProductBundleOptionProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $qty
|
||||
*
|
||||
|
|
|
|||
|
|
@ -20,4 +20,12 @@ class ProductBundleOption extends TranslatableModel implements ProductBundleOpti
|
|||
{
|
||||
return $this->belongsTo(ProductProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bundle option products that owns the bundle option.
|
||||
*/
|
||||
public function bundle_option_products()
|
||||
{
|
||||
return $this->hasMany(ProductBundleOptionProductProxy::modelClass());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Product\Contracts\ProductBundleOptionProduct as ProductBundleOptionProductContract;
|
||||
|
||||
class ProductBundleOptionProduct extends Model implements ProductBundleOptionProductContract
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = ['qty', 'sort_order', 'is_default', 'product_bundle_option_id', 'product_id'];
|
||||
|
||||
/**
|
||||
* Get the product that owns the image.
|
||||
*/
|
||||
public function product()
|
||||
{
|
||||
return $this->belongsTo(ProductProxy::modelClass());
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ namespace Webkul\Product\Models;
|
|||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class ProductBundleProductProxy extends ModelProxy
|
||||
class ProductBundleOptionProductProxy extends ModelProxy
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Product\Contracts\ProductBundleProduct as ProductBundleProductContract;
|
||||
|
||||
class ProductBundleProduct extends Model implements ProductBundleProductContract
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = ['qty', 'sort_order', 'product_bundle_option_id', 'product_id'];
|
||||
|
||||
/**
|
||||
* Get the product that owns the image.
|
||||
*/
|
||||
public function product()
|
||||
{
|
||||
return $this->belongsTo(ProductProxy::modelClass());
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,6 @@ class ModuleServiceProvider extends BaseModuleServiceProvider
|
|||
\Webkul\Product\Models\ProductGroupedProduct::class,
|
||||
\Webkul\Product\Models\ProductBundleOption::class,
|
||||
\Webkul\Product\Models\ProductBundleOptionTranslation::class,
|
||||
\Webkul\Product\Models\ProductBundleProduct::class,
|
||||
\Webkul\Product\Models\ProductBundleOptionProduct::class,
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
/**
|
||||
* ProductBundleOptionProduct Repository
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class ProductBundleOptionProductRepository extends Repository
|
||||
{
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Product\Contracts\ProductBundleOptionProduct';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param ProductBundleOption $productBundleOption
|
||||
* @return void
|
||||
*/
|
||||
public function saveBundleOptonProducts($data, $productBundleOption)
|
||||
{
|
||||
$previousBundleOptionProductIds = $productBundleOption->bundle_option_products()->pluck('id');
|
||||
|
||||
if (isset($data['products'])) {
|
||||
foreach ($data['products'] as $bundleOptionProductId => $bundleOptionProductInputs) {
|
||||
if (str_contains($bundleOptionProductId, 'product_')) {
|
||||
$this->create(array_merge([
|
||||
'product_bundle_option_id' => $productBundleOption->id,
|
||||
], $bundleOptionProductInputs));
|
||||
} else {
|
||||
if (is_numeric($index = $previousBundleOptionProductIds->search($bundleOptionProductId)))
|
||||
$previousBundleOptionProductIds->forget($index);
|
||||
|
||||
$this->update($bundleOptionProductInputs, $bundleOptionProductId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($previousBundleOptionProductIds as $previousBundleOptionProductId) {
|
||||
$this->delete($previousBundleOptionProductId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Webkul\Product\Repositories;
|
||||
|
||||
use Illuminate\Container\Container as App;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
/**
|
||||
|
|
@ -12,8 +13,64 @@ use Webkul\Core\Eloquent\Repository;
|
|||
*/
|
||||
class ProductBundleOptionRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* ProductBundleOptionProductRepository object
|
||||
*
|
||||
* @var ProductBundleOptionProductRepository
|
||||
*/
|
||||
protected $productBundleOptionProductRepository;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @param Webkul\Product\Repositories\ProductBundleOptionProductRepository $productBundleOptionProductRepository
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
ProductBundleOptionProductRepository $productBundleOptionProductRepository,
|
||||
App $app
|
||||
)
|
||||
{
|
||||
$this->productBundleOptionProductRepository = $productBundleOptionProductRepository;
|
||||
|
||||
parent::__construct($app);
|
||||
}
|
||||
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Product\Contracts\ProductBundleOption';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param Product $product
|
||||
* @return void
|
||||
*/
|
||||
public function saveBundleOptons($data, $product)
|
||||
{
|
||||
$previousBundleOptionIds = $product->bundle_options()->pluck('id');
|
||||
|
||||
if (isset($data['bundle_options'])) {
|
||||
foreach ($data['bundle_options'] as $bundleOptionId => $bundleOptionInputs) {
|
||||
if (str_contains($bundleOptionId, 'option_')) {
|
||||
$productBundleOption = $this->create(array_merge([
|
||||
'product_id' => $product->id,
|
||||
], $bundleOptionInputs));
|
||||
} else {
|
||||
$productBundleOption = $this->find($bundleOptionId);
|
||||
|
||||
if (is_numeric($index = $previousBundleOptionIds->search($bundleOptionId)))
|
||||
$previousBundleOptionIds->forget($index);
|
||||
|
||||
$this->update($bundleOptionInputs, $bundleOptionId);
|
||||
}
|
||||
|
||||
$this->productBundleOptionProductRepository->saveBundleOptonProducts($bundleOptionInputs, $productBundleOption);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($previousBundleOptionIds as $previousBundleOptionId) {
|
||||
$this->delete($previousBundleOptionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
/**
|
||||
* ProductBundleProduct Repository
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class ProductBundleProductRepository extends Repository
|
||||
{
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Product\Contracts\ProductBundleProduct';
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,6 @@ namespace Webkul\Product\Repositories;
|
|||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
use Webkul\Product\Repositories\ProductRepository;
|
||||
use Webkul\Product\Repositories\ProductFlatRepository;
|
||||
|
||||
/**
|
||||
* Product Grouped Product Repository
|
||||
|
|
@ -19,39 +18,6 @@ class ProductGroupedProductRepository extends Repository
|
|||
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
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Event;
|
|||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
use Webkul\Product\Repositories\ProductFlatRepository;
|
||||
|
||||
/**
|
||||
* Product Repository
|
||||
|
|
@ -328,4 +329,29 @@ class ProductRepository extends Repository
|
|||
|
||||
return $superAttrbutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search simple products for grouped product association
|
||||
*
|
||||
* @param string $term
|
||||
* @return \Illuminate\Support\Collection
|
||||
*/
|
||||
public function searchSimpleProducts($term)
|
||||
{
|
||||
return app(ProductFlatRepository::class)->scopeQuery(function($query) use($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)
|
||||
->where('product_flat.name', 'like', '%' . urldecode($term) . '%')
|
||||
->orderBy('product_id', 'desc');
|
||||
})->get();
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,14 @@
|
|||
|
||||
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\ProductBundleOptionRepository;
|
||||
use Webkul\Product\Helpers\ProductImage;
|
||||
|
||||
/**
|
||||
* Class Bundle.
|
||||
*
|
||||
|
|
@ -10,6 +18,55 @@ namespace Webkul\Product\Type;
|
|||
*/
|
||||
class Bundle 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;
|
||||
|
||||
/**
|
||||
* ProductBundleOptionRepository instance
|
||||
*
|
||||
* @var ProductBundleOptionRepository
|
||||
*/
|
||||
protected $productBundleOptionRepository;
|
||||
|
||||
/**
|
||||
* Product Image helper instance
|
||||
*
|
||||
* @var ProductImage
|
||||
*/
|
||||
protected $productImageHelper;
|
||||
|
||||
/**
|
||||
* Skip attribute for Bundle product type
|
||||
*
|
||||
|
|
@ -28,4 +85,54 @@ class Bundle extends AbstractType
|
|||
'admin::catalog.products.accordians.bundle-items',
|
||||
'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\ProductBundleOptionRepository $productBundleOptionRepository
|
||||
* @param Webkul\Product\Helpers\ProductImage $productImageHelper
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
AttributeRepository $attributeRepository,
|
||||
ProductRepository $productRepository,
|
||||
ProductAttributeValueRepository $attributeValueRepository,
|
||||
ProductInventoryRepository $productInventoryRepository,
|
||||
productImageRepository $productImageRepository,
|
||||
ProductBundleOptionRepository $productBundleOptionRepository,
|
||||
ProductImage $productImageHelper
|
||||
)
|
||||
{
|
||||
parent::__construct(
|
||||
$attributeRepository,
|
||||
$productRepository,
|
||||
$attributeValueRepository,
|
||||
$productInventoryRepository,
|
||||
$productImageRepository,
|
||||
$productImageHelper
|
||||
);
|
||||
|
||||
$this->productBundleOptionRepository = $productBundleOptionRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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->productBundleOptionRepository->saveBundleOptons($data, $product);
|
||||
|
||||
return $product;
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,6 @@ 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\ProductImage;
|
||||
use Webkul\Checkout\Models\CartItem;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue