Configurable options added

This commit is contained in:
jitendra 2018-09-11 16:00:02 +05:30
parent 4fb084557d
commit 5202729391
11 changed files with 227 additions and 32 deletions

View File

@ -1,10 +1,26 @@
<?php <?php
return [ return [
[ 'flatrate' => [
'code' => 'flatrate', 'code' => 'flatrate',
'name' => 'Flat Rate', 'name' => 'Flat Rate',
'class' => 'Webkul\Shipping\Calculators\FlatRate' 'description' => '',
'default_type' => 'per_order',
'types' => [
'per_unit' => 'Per Unit',
'per_order' => 'Per Order',
],
'price' => 10,
'class' => 'Webkul\Shipping\Calculators\FlatRate',
'status' => 1
],
'fedex' => [
'code' => 'fedex',
'name' => 'Fedex',
'description' => '',
'class' => 'Webkul\Shipping\Calculators\FedexRate',
'status' => 1
] ]
]; ];

View File

@ -90,6 +90,13 @@ class EventServiceProvider extends ServiceProvider
Event::listen('admin.acl.build', function ($acl) { Event::listen('admin.acl.build', function ($acl) {
$acl->add('dashboard', 'Dashboard', 'admin.dashboard.index', 1); $acl->add('dashboard', 'Dashboard', 'admin.dashboard.index', 1);
$acl->add('catalog', 'Catalog', 'admin.catalog.index', 2);
$acl->add('catalog.products', 'Products', 'admin.catalog.products.index', 1);
$acl->add('catalog.categories', 'Categories', 'admin.catalog.categories.index', 1);
$acl->add('configuration', 'Configure', 'admin.account.edit', 5); $acl->add('configuration', 'Configure', 'admin.account.edit', 5);
$acl->add('settings', 'Settings', 'admin.users.index', 6); $acl->add('settings', 'Settings', 'admin.users.index', 6);

View File

@ -82,6 +82,10 @@ class ConfigurableOption extends AbstractProduct
$config = [ $config = [
'attributes' => $this->getAttributesData($product, $options), 'attributes' => $this->getAttributesData($product, $options),
'index' => isset($options['index']) ? $options['index'] : [], 'index' => isset($options['index']) ? $options['index'] : [],
'regular_price' => [
'formated_price' => core()->currency($this->price->getMinimalPrice($product)),
'price' => $this->price->getMinimalPrice($product)
],
'variant_prices' => $this->getVariantPrices($product), 'variant_prices' => $this->getVariantPrices($product),
'variant_images' => $this->getVariantImages($product), 'variant_images' => $this->getVariantImages($product),
'chooseText' => trans('shop::app.products.choose-option') 'chooseText' => trans('shop::app.products.choose-option')
@ -201,8 +205,14 @@ class ConfigurableOption extends AbstractProduct
foreach ($this->getAllowProducts($product) as $variant) { foreach ($this->getAllowProducts($product) as $variant) {
$prices[$variant->id] = [ $prices[$variant->id] = [
'regular_price' => $variant->price, 'regular_price' => [
'final_price' => $this->price->getMinimalPrice($variant), 'formated_price' => core()->currency($variant->price),
'price' => $variant->price
],
'final_price' => [
'formated_price' => core()->currency($this->price->getMinimalPrice($variant)),
'price' => $this->price->getMinimalPrice($variant)
],
]; ];
} }

View File

@ -0,0 +1,21 @@
<?php
use Webkul\Shipping\Contracts\Carrier;
class FlatRate extends Carrier
{
public function calculateRates()
{
return [
'code' => 'flatrate',
'title' => 'Flatrate',
'rates' => [
[
'title' => 'Flat Rate',
'rate' => 10
]
]
];
}
}
?>

View File

@ -0,0 +1,21 @@
<?php
use Webkul\Shipping\Contracts\Carrier;
class PerProduct extends Carrier
{
public function calculeRates()
{
return [
'code' => 'perproduct',
'title' => 'Per Product',
'rates' => [
[
'title' => 'Per Product',
'rate' => 10
]
]
];
}
}
?>

View File

@ -0,0 +1,9 @@
<?php
abstract class Carrier {
abstract public function calculateRates();
}
?>

View File

@ -0,0 +1,26 @@
<?php
use Illuminate\Support\Facades\Config;
class Rates {
public function collectRates()
{
$rates = [];
foreach(Config::get('carriers') as $shippingMethod) {
if(isset($shippingMethod['class'])) {
$object = new $shippingMethod['class'];
if($rate = $object->calculeRates()) {
array_push($rates, $rate);
}
}
}
return $rates;
}
}
?>

View File

@ -6,7 +6,7 @@
<span class="price-label">{{ __('shop::app.products.price-label') }}</span> <span class="price-label">{{ __('shop::app.products.price-label') }}</span>
<span>{{ core()->currency($priceHelper->getMinimalPrice($product)) }}</span> <span class="final-price">{{ core()->currency($priceHelper->getMinimalPrice($product)) }}</span>
@else @else

View File

@ -16,8 +16,6 @@
<input type="hidden" name="product"> <input type="hidden" name="product">
<input type="hidden" name="selected_configurable_option">
@include ('shop::products.view.gallery') @include ('shop::products.view.gallery')
<div class="details"> <div class="details">

View File

@ -2,7 +2,6 @@
@inject ('configurableOptionHelper', 'Webkul\Product\Product\ConfigurableOption') @inject ('configurableOptionHelper', 'Webkul\Product\Product\ConfigurableOption')
<product-options></product-options> <product-options></product-options>
@push('scripts') @push('scripts')
@ -10,39 +9,52 @@
<script type="text/x-template" id="product-options-template"> <script type="text/x-template" id="product-options-template">
<div class="attributes"> <div class="attributes">
<input type="hidden" name="selected_configurable_option" :value="selectedProductId">
<div v-for='(attribute, index) in childAttributes' class="attribute control-group" :class="[errors.has('super_attribute[' + attribute.id + ']') ? 'has-error' : '']"> <div v-for='(attribute, index) in childAttributes' class="attribute control-group" :class="[errors.has('super_attribute[' + attribute.id + ']') ? 'has-error' : '']">
<label class="reqiured">@{{ attribute.label }}</label> <label class="reqiured">@{{ attribute.label }}</label>
<select v-validate="'required'" class="control" :name="['super_attribute[' + attribute.id + ']']" :disabled="attribute.disabled" @change="configure(attribute, $event.target.value)"> <select v-validate="'required'" class="control" :name="['super_attribute[' + attribute.id + ']']" :disabled="attribute.disabled" @change="configure(attribute, $event.target.value)" :id="['attribute_' + attribute.id]">
<option v-for='(option, index) in attribute.options' :value="option.id">@{{ option.label }}</option> <option v-for='(option, index) in attribute.options' :value="option.id">@{{ option.label }}</option>
</select> </select>
<span class="control-error" v-if="errors.has('super_attribute[' + attribute.id + ']')">@{{ errors.first('super_attribute[' + attribute.id + ']') }}</span> <span class="control-error" v-if="errors.has('super_attribute[' + attribute.id + ']')">
@{{ errors.first('super_attribute[' + attribute.id + ']') }}
</span>
</div> </div>
</div> </div>
</script> </script>
<?php $config = $configurableOptionHelper->getConfigurationConfig($product) ?>
<script> <script>
Vue.component('product-options', { Vue.component('product-options', {
template: '#product-options-template', template: '#product-options-template',
data: () => ({ data: () => ({
config: @json($configurableOptionHelper->getConfigurationConfig($product)), config: @json($config),
childAttributes: []
childAttributes: [],
selectedProductId: '',
simpleProduct: null
}), }),
created () { created () {
var config = @json($config);
var childAttributes = this.childAttributes, var childAttributes = this.childAttributes,
attributes = this.config.attributes, attributes = config.attributes.slice(),
index = attributes.length, index = attributes.length,
attribute; attribute;
while (index--) { while (index--) {
// attribute = Object.assign({}, attributes[index]);
attribute = attributes[index]; attribute = attributes[index];
attribute.options = []; attribute.options = [];
@ -65,32 +77,68 @@
methods: { methods: {
configure (attribute, value) { configure (attribute, value) {
// this.simpleProduct = this._getSimpleProductId(attribute); this.simpleProduct = this.getSelectedProductId(attribute, value);
if (value) { if (value) {
attribute.selectedIndex = this.getSelectedIndex(attribute, value);
if (attribute.nextAttribute) { if (attribute.nextAttribute) {
attribute.nextAttribute.disabled = false; attribute.nextAttribute.disabled = false;
this.fillSelect(attribute.nextAttribute); this.fillSelect(attribute.nextAttribute);
this.resetChildren(attribute.nextAttribute); this.resetChildren(attribute.nextAttribute);
} else { } else {
//Set product id hidden value this.selectedProductId = attribute.options[attribute.selectedIndex].allowedProducts[0];
} }
} else { } else {
attribute.selectedIndex = 0;
this.resetChildren(attribute); this.resetChildren(attribute);
this.clearSelect(attribute.nextAttribute)
} }
// this.reloadPrice(); this.reloadPrice();
// this.changeProductImage(); this.changeProductImages();
},
getSelectedIndex (attribute, value) {
var selectedIndex = 0;
attribute.options.forEach(function(option, index) {
if(option.id == value) {
selectedIndex = index;
}
})
return selectedIndex;
},
getSelectedProductId (attribute, value) {
var options = attribute.options,
matchedOptions;
matchedOptions = options.filter(function (option) {
return option.id == value;
});
if(matchedOptions[0] != undefined && matchedOptions[0].allowedProducts != undefined) {
return matchedOptions[0].allowedProducts[0];
}
return undefined;
}, },
fillSelect (attribute) { fillSelect (attribute) {
var options = this.getAttributeOptions(attribute.id), var options = this.getAttributeOptions(attribute.id),
prevOption, prevOption,
index = 1, index = 1,
products, allowedProducts,
i, i,
j; j;
this.clearSelect(attribute)
attribute.options = []; attribute.options = [];
attribute.options[0] = {'id': '', 'label': this.config.chooseText, 'products': []}; attribute.options[0] = {'id': '', 'label': this.config.chooseText, 'products': []};
@ -98,25 +146,23 @@
prevOption = attribute.prevAttribute.options[attribute.prevAttribute.selectedIndex]; prevOption = attribute.prevAttribute.options[attribute.prevAttribute.selectedIndex];
} }
// console.log(attribute)
if (options) { if (options) {
for (i = 0; i < options.length; i++) { for (i = 0; i < options.length; i++) {
products = []; allowedProducts = [];
if (prevOption) { if (prevOption) {
for (j = 0; j < options[i].products.length; j++) { for (j = 0; j < options[i].products.length; j++) {
if (prevOption.products && if (prevOption.products && prevOption.products.indexOf(options[i].products[j]) > -1) {
prevOption.products.indexOf(options[i].products[j]) > -1) { allowedProducts.push(options[i].products[j]);
products.push(options[i].products[j]);
} }
} }
} else { } else {
products = options[i].products.slice(0); allowedProducts = options[i].products.slice(0);
} }
if (products.length > 0) { if (allowedProducts.length > 0) {
options[i].products = products; options[i].allowedProducts = allowedProducts;
attribute.options[index] = options[i]; attribute.options[index] = options[i];
index++; index++;
@ -134,11 +180,21 @@
} }
}, },
clearSelect: function (attribute) {
if(!attribute)
return;
var element = document.getElementById("attribute_" + attribute.id);
if(element) {
element.selectedIndex = "0";
}
},
getAttributeOptions (attributeId) { getAttributeOptions (attributeId) {
var this_this = this, var this_this = this,
options; options;
this.config.attributes.forEach(function(attribute, index) { this.config.attributes.forEach(function(attribute, index) {
if (attribute.id == attributeId) { if (attribute.id == attributeId) {
options = attribute.options; options = attribute.options;
@ -149,11 +205,30 @@
}, },
reloadPrice () { reloadPrice () {
var selectedOptionCount = 0;
this.childAttributes.forEach(function(attribute) {
if(attribute.selectedIndex) {
selectedOptionCount++;
}
});
var priceLabelElement = document.querySelector('.price-label');
var priceElement = document.querySelector('.final-price');
if(this.childAttributes.length == selectedOptionCount) {
priceLabelElement.style.display = 'none';
priceElement.innerHTML = this.config.variant_prices[this.simpleProduct].final_price.formated_price;
} else {
priceLabelElement.style.display = 'inline-block';
priceElement.innerHTML = this.config.regular_price.formated_price;
}
}, },
changeProductImage () { changeProductImages () {
console.log(this.config.variant_images[this.simpleProduct])
}, },
} }

View File

@ -14,3 +14,15 @@
</div> </div>
</div> </div>
@push('scripts')
<script>
Vue.component('product-gallery', {
props: ['images']
});
</script>
@endpush