Added product creation page
This commit is contained in:
parent
8a6f670a4f
commit
ff50784aa8
|
|
@ -128,7 +128,15 @@ class EventServiceProvider extends ServiceProvider
|
|||
});
|
||||
|
||||
Event::listen('admin.catalog.products.accordian.build', function($accordian) {
|
||||
$accordian->add('categories', 'Categories', 'admin::catalog.products.accordians.categories', 1);
|
||||
$accordian->add('images', 'Inventories', 'admin::catalog.products.accordians.inventories', 1);
|
||||
|
||||
$accordian->add('images', 'Images', 'admin::catalog.products.accordians.images', 2);
|
||||
|
||||
$accordian->add('categories', 'Categories', 'admin::catalog.products.accordians.categories', 3);
|
||||
|
||||
$accordian->add('variations', 'Variations', 'admin::catalog.products.accordians.variations', 4);
|
||||
|
||||
// $accordian->add('product-links', 'Linked Products', 'admin::catalog.products.accordians.product-links', 4);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,10 +39,16 @@ $(document).ready(function () {
|
|||
addServerErrors() {
|
||||
var scope = null;
|
||||
for (var key in serverErrors) {
|
||||
var inputName = key;
|
||||
if (key.indexOf(".") !== -1) {
|
||||
inputName = key.replace(".", "[") + "]";
|
||||
}
|
||||
var inputNames = [];
|
||||
key.split('.').forEach(function(chunk, index) {
|
||||
if(index) {
|
||||
inputNames.push('[' + chunk + ']')
|
||||
} else {
|
||||
inputNames.push(chunk)
|
||||
}
|
||||
})
|
||||
|
||||
var inputName = inputNames.join('');
|
||||
|
||||
const field = this.$validator.fields.find({
|
||||
name: inputName,
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
<template>
|
||||
<div class="control-group" :class="[errors.has(name) ? 'has-error' : '']">
|
||||
<label :for="name" :class="[is_required ? 'required' : '']">
|
||||
{{ label }}
|
||||
</label>
|
||||
|
||||
<flat-pickr v-model="finalvalue" class="control" v-validate="'required'" :config="config" :name="name" @on-open="open()"></flat-pickr>
|
||||
|
||||
<span class="control-error" v-if="errors.has(name)">{{ errors.first(name) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import flatPickr from 'vue-flatpickr-component';
|
||||
|
||||
// Vue.use(flatPickr);
|
||||
|
||||
export default {
|
||||
props: {
|
||||
label: String,
|
||||
name: String,
|
||||
required: String,
|
||||
value: String,
|
||||
},
|
||||
|
||||
computed: {
|
||||
is_required () {
|
||||
return Number(this.required)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
open () {
|
||||
console.log(this.$validator)
|
||||
}
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
finalvalue: this.value,
|
||||
|
||||
date: new Date(),
|
||||
|
||||
config: {
|
||||
allowInput: true,
|
||||
altFormat: 'Y-m-d H:i:s',
|
||||
dateFormat: 'Y-m-d H:i:s',
|
||||
enableTime: true
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
@ -202,6 +202,17 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
.control-group {
|
||||
label {
|
||||
width: 70%;
|
||||
|
||||
.locale {
|
||||
float: right;
|
||||
color: #8E8E8E;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//style for dummy datagrid
|
||||
// .page-content {
|
||||
// .table-container {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ return [
|
|||
'all' => 'All'
|
||||
],
|
||||
'users' => [
|
||||
'title' => 'Users',
|
||||
'add-user-title' => 'Add User',
|
||||
'edit-user-title' => 'Edit User',
|
||||
'save-btn-title' => 'Save User',
|
||||
|
|
@ -64,7 +65,7 @@ return [
|
|||
],
|
||||
'catalog' => [
|
||||
'products' => [
|
||||
'products' => 'products',
|
||||
'products' => 'Products',
|
||||
'add-product-btn-title' => 'Add Product',
|
||||
'add-title' => 'Add Product',
|
||||
'edit-title' => 'Edit Product',
|
||||
|
|
@ -79,7 +80,20 @@ return [
|
|||
'attribute-header' => 'Attribute(s)',
|
||||
'attribute-option-header' => 'Attribute Option(s)',
|
||||
'no' => 'No',
|
||||
'yes' => 'Yes'
|
||||
'yes' => 'Yes',
|
||||
'disabled' => 'Disabled',
|
||||
'enabled' => 'Enabled',
|
||||
'add-variant-btn-title' => 'Add Variant',
|
||||
'name' => 'Name',
|
||||
'qty' => 'Qty',
|
||||
'price' => 'Price',
|
||||
'weight' => 'Weight',
|
||||
'status' => 'Status',
|
||||
'enabled' => 'Enabled',
|
||||
'disabled' => 'Disabled',
|
||||
'add-variant-title' => 'Add Variant',
|
||||
'variant-already-exist-message' => 'Variant with same attribute options already exists.',
|
||||
'add-image-btn-title' => 'Add Image'
|
||||
],
|
||||
'attributes' => [
|
||||
'add-title' => 'Add Attribute',
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
<div slot="body">
|
||||
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
|
||||
<label for="code">{{ __('admin::app.catalog.attributes.code') }}</label>
|
||||
<input type="text" v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') }}"/>
|
||||
<input type="text" v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') }}" v-code/>
|
||||
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -131,13 +131,13 @@
|
|||
</select>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<!--<div class="control-group">
|
||||
<label for="value_per_channel">{{ __('admin::app.catalog.attributes.value_per_channel') }}</label>
|
||||
<select class="control" id="value_per_channel" name="value_per_channel">
|
||||
<option value="0">{{ __('admin::app.catalog.attributes.no') }}</option>
|
||||
<option value="1">{{ __('admin::app.catalog.attributes.yes') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>-->
|
||||
|
||||
<div class="control-group">
|
||||
<label for="is_filterable">{{ __('admin::app.catalog.attributes.is_filterable') }}</label>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
{{ __('admin::app.catalog.attributes.edit-title') }}
|
||||
@stop
|
||||
|
||||
|
||||
@section('content')
|
||||
<div class="content">
|
||||
<form method="POST" action="{{ route('admin.catalog.attributes.update', $attribute->id) }}" @submit.prevent="onSubmit">
|
||||
|
|
@ -30,7 +29,7 @@
|
|||
<div slot="body">
|
||||
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
|
||||
<label for="code" class="required">{{ __('admin::app.catalog.attributes.code') }}</label>
|
||||
<input type="text" v-validate="'required'" class="control" id="code" name="code" value="{{ $attribute->code }}" disabled="disabled"/>
|
||||
<input type="text" v-validate="'required'" class="control" id="code" name="code" value="{{ $attribute->code }}" disabled="disabled" v-code/>
|
||||
<input type="hidden" name="code" value="{{ $attribute->code }}"/>
|
||||
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
|
||||
</div>
|
||||
|
|
@ -175,7 +174,7 @@
|
|||
<input type="hidden" name="value_per_locale" value="{{ $attribute->value_per_locale }}"/>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<!--<div class="control-group">
|
||||
<label for="value_per_channel">{{ __('admin::app.catalog.attributes.value_per_channel') }}</label>
|
||||
<select class="control" id="value_per_channel" name="value_per_channel" disabled>
|
||||
<option value="0" {{ $attribute->value_per_channel ? '' : 'selected' }}>
|
||||
|
|
@ -186,7 +185,7 @@
|
|||
</option>
|
||||
</select>
|
||||
<input type="hidden" name="value_per_channel" value="{{ $attribute->value_per_channel }}"/>
|
||||
</div>
|
||||
</div>-->
|
||||
|
||||
<div class="control-group">
|
||||
<label for="is_filterable">{{ __('admin::app.catalog.attributes.is_filterable') }}</label>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
<div class="control-group">
|
||||
<select class="control" id="locale-switcher" onChange="window.location.href = this.value">
|
||||
@foreach(core()->allLocales() as $localeModel)
|
||||
@foreach(core()->getAllLocales() as $localeModel)
|
||||
|
||||
<option value="{{ route('admin.catalog.categories.update', $category->id) . '?locale=' . $localeModel->code }}" {{ ($localeModel->code) == $locale ? 'selected' : '' }}>
|
||||
{{ $localeModel->name }}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
|
||||
<label for="code" class="required">{{ __('admin::app.catalog.families.code') }}</label>
|
||||
<input type="text" v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') }}"/>
|
||||
<input type="text" v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') }}" v-code/>
|
||||
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -101,7 +101,7 @@
|
|||
|
||||
<script type="text/x-template" id="group-list-template">
|
||||
<div>
|
||||
<group-item v-for='(group, index) in groups' :group="group" :attributes="attributes" :key="index" :index="index" @onRemoveGroup="removeGroup($event)" @onAttributeAdd="addAttributes(index, $event)" @onAttributeRemove="removeAttribute(index, $event)"></group-item>
|
||||
<group-item v-for='(group, index) in groups' :group="group" :custom_attributes="custom_attributes" :key="index" :index="index" @onRemoveGroup="removeGroup($event)" @onAttributeAdd="addAttributes(index, $event)" @onAttributeRemove="removeAttribute(index, $event)"></group-item>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
|
@ -118,7 +118,7 @@
|
|||
<input type="hidden" :name="[groupInputName + '[position]']" :value="group.position"/>
|
||||
<input type="hidden" :name="[groupInputName + '[is_user_defined]']" :value="group.is_user_defined"/>
|
||||
|
||||
<div class="table" v-if="group.attributes.length" style="margin-bottom: 20px;">
|
||||
<div class="table" v-if="group.custom_attributes.length" style="margin-bottom: 20px;">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
|
@ -130,9 +130,9 @@
|
|||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr v-for='(attribute, index) in group.attributes'>
|
||||
<tr v-for='(attribute, index) in group.custom_attributes'>
|
||||
<td>
|
||||
<input type="hidden" :name="[groupInputName + '[attributes][][id]']" :value="attribute.id"/>
|
||||
<input type="hidden" :name="[groupInputName + '[custom_attributes][][id]']" :value="attribute.id"/>
|
||||
@{{ attribute.code }}
|
||||
</td>
|
||||
<td>@{{ attribute.admin_name }}</td>
|
||||
|
|
@ -156,7 +156,7 @@
|
|||
|
||||
<div class="dropdown-container">
|
||||
<ul>
|
||||
<li v-for='(attribute, index) in attributes' :data-id="attribute.id">
|
||||
<li v-for='(attribute, index) in custom_attributes' :data-id="attribute.id">
|
||||
<span class="checkbox">
|
||||
<input type="checkbox" :id="attribute.id" :value="attribute.id"/>
|
||||
<label class="checkbox-view" :for="attribute.id"></label>
|
||||
|
|
@ -176,7 +176,7 @@
|
|||
|
||||
<script>
|
||||
var groups = @json($attributeFamily ? $attributeFamily->attribute_groups : []);
|
||||
var attributes = @json($attributes);
|
||||
var custom_attributes = @json($custom_attributes);
|
||||
|
||||
Vue.component('group-form', {
|
||||
|
||||
|
|
@ -185,7 +185,7 @@
|
|||
'groupName': '',
|
||||
'position': '',
|
||||
'is_user_defined': 1,
|
||||
'attributes': []
|
||||
'custom_attributes': []
|
||||
}
|
||||
}),
|
||||
|
||||
|
|
@ -217,7 +217,7 @@
|
|||
|
||||
groups = this.sortGroups();
|
||||
|
||||
this.group = {'groupName': '', 'position': '', 'is_user_defined': 1, 'attributes': []};
|
||||
this.group = {'groupName': '', 'position': '', 'is_user_defined': 1, 'custom_attributes': []};
|
||||
|
||||
this.$parent.closeModal();
|
||||
}
|
||||
|
|
@ -239,18 +239,18 @@
|
|||
|
||||
data: () => ({
|
||||
groups: groups,
|
||||
attributes: attributes
|
||||
custom_attributes: custom_attributes
|
||||
}),
|
||||
|
||||
created () {
|
||||
this.groups.forEach(function(group) {
|
||||
group.attributes.forEach(function(attribute) {
|
||||
var attribute = this.attributes.filter(attributeTemp => attributeTemp.id == attribute.id)
|
||||
group.custom_attributes.forEach(function(attribute) {
|
||||
var attribute = this.custom_attributes.filter(attributeTemp => attributeTemp.id == attribute.id)
|
||||
|
||||
if(attribute.length) {
|
||||
let index = this.attributes.indexOf(attribute[0])
|
||||
let index = this.custom_attributes.indexOf(attribute[0])
|
||||
|
||||
this.attributes.splice(index, 1)
|
||||
this.custom_attributes.splice(index, 1)
|
||||
}
|
||||
|
||||
});
|
||||
|
|
@ -259,11 +259,11 @@
|
|||
|
||||
methods: {
|
||||
removeGroup (group) {
|
||||
group.attributes.forEach(function(attribute) {
|
||||
this.attributes.push(attribute);
|
||||
group.custom_attributes.forEach(function(attribute) {
|
||||
this.custom_attributes.push(attribute);
|
||||
})
|
||||
|
||||
this.attributes = this.sortAttributes();
|
||||
this.custom_attributes = this.sortAttributes();
|
||||
|
||||
let index = groups.indexOf(group)
|
||||
|
||||
|
|
@ -272,28 +272,28 @@
|
|||
|
||||
addAttributes (groupIndex, attributeIds) {
|
||||
attributeIds.forEach(function(attributeId) {
|
||||
var attribute = this.attributes.filter(attribute => attribute.id == attributeId)
|
||||
var attribute = this.custom_attributes.filter(attribute => attribute.id == attributeId)
|
||||
|
||||
this.groups[groupIndex].attributes.push(attribute[0]);
|
||||
this.groups[groupIndex].custom_attributes.push(attribute[0]);
|
||||
|
||||
let index = this.attributes.indexOf(attribute[0])
|
||||
let index = this.custom_attributes.indexOf(attribute[0])
|
||||
|
||||
this.attributes.splice(index, 1)
|
||||
this.custom_attributes.splice(index, 1)
|
||||
})
|
||||
},
|
||||
|
||||
removeAttribute (groupIndex, attribute) {
|
||||
let index = this.groups[groupIndex].attributes.indexOf(attribute)
|
||||
let index = this.groups[groupIndex].custom_attributes.indexOf(attribute)
|
||||
|
||||
this.groups[groupIndex].attributes.splice(index, 1)
|
||||
this.groups[groupIndex].custom_attributes.splice(index, 1)
|
||||
|
||||
this.attributes.push(attribute);
|
||||
this.custom_attributes.push(attribute);
|
||||
|
||||
this.attributes = this.sortAttributes();
|
||||
this.custom_attributes = this.sortAttributes();
|
||||
},
|
||||
|
||||
sortAttributes () {
|
||||
return this.attributes.sort(function(a, b) {
|
||||
return this.custom_attributes.sort(function(a, b) {
|
||||
return a.id - b.id;
|
||||
});
|
||||
}
|
||||
|
|
@ -301,7 +301,7 @@
|
|||
})
|
||||
|
||||
Vue.component('group-item', {
|
||||
props: ['index', 'group', 'attributes'],
|
||||
props: ['index', 'group', 'custom_attributes'],
|
||||
|
||||
template: "#group-item-template",
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
<div slot="body">
|
||||
|
||||
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
|
||||
<input type="text" v-validate="'required'" name="code" class="control" id="code" value="{{ $attributeFamily->code }}" disabled="disabled"/>
|
||||
<input type="text" v-validate="'required'" name="code" class="control" id="code" value="{{ $attributeFamily->code }}" disabled="disabled" v-code/>
|
||||
<input type="hidden" name="code" value="{{ $attributeFamily->code }}"/>
|
||||
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
|
||||
</div>
|
||||
|
|
@ -102,7 +102,7 @@
|
|||
|
||||
<script type="text/x-template" id="group-list-template">
|
||||
<div style="margin-top: 20px">
|
||||
<group-item v-for='(group, index) in groups' :group="group" :attributes="attributes" :key="index" :index="index" @onRemoveGroup="removeGroup($event)" @onAttributeAdd="addAttributes(index, $event)" @onAttributeRemove="removeAttribute(index, $event)"></group-item>
|
||||
<group-item v-for='(group, index) in groups' :group="group" :custom_attributes="custom_attributes" :key="index" :index="index" @onRemoveGroup="removeGroup($event)" @onAttributeAdd="addAttributes(index, $event)" @onAttributeRemove="removeAttribute(index, $event)"></group-item>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
|
|
@ -118,7 +118,7 @@
|
|||
<input type="hidden" :name="[groupInputName + '[name]']" :value="group.name ? group.name : group.groupName"/>
|
||||
<input type="hidden":name="[groupInputName + '[position]']" :value="group.position"/>
|
||||
|
||||
<div class="table" v-if="group.attributes.length" style="margin-bottom: 20px;">
|
||||
<div class="table" v-if="group.custom_attributes.length" style="margin-bottom: 20px;">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
|
@ -130,9 +130,9 @@
|
|||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr v-for='(attribute, index) in group.attributes'>
|
||||
<tr v-for='(attribute, index) in group.custom_attributes'>
|
||||
<td>
|
||||
<input type="hidden" :name="[groupInputName + '[attributes][][id]']" :value="attribute.id"/>
|
||||
<input type="hidden" :name="[groupInputName + '[custom_attributes][][id]']" :value="attribute.id"/>
|
||||
@{{ attribute.code }}
|
||||
</td>
|
||||
<td>@{{ attribute.admin_name }}</td>
|
||||
|
|
@ -156,7 +156,7 @@
|
|||
|
||||
<div class="dropdown-container">
|
||||
<ul>
|
||||
<li v-for='(attribute, index) in attributes' :data-id="attribute.id">
|
||||
<li v-for='(attribute, index) in custom_attributes' :data-id="attribute.id">
|
||||
<span class="checkbox">
|
||||
<input type="checkbox" :id="attribute.id" :value="attribute.id"/>
|
||||
<label class="checkbox-view" :for="attribute.id"></label>
|
||||
|
|
@ -176,7 +176,7 @@
|
|||
|
||||
<script>
|
||||
var groups = @json($attributeFamily->attribute_groups);
|
||||
var attributes = @json($attributes);
|
||||
var custom_attributes = @json($custom_attributes);
|
||||
|
||||
Vue.component('group-form', {
|
||||
|
||||
|
|
@ -184,7 +184,7 @@
|
|||
group: {
|
||||
'groupName': '',
|
||||
'position': '',
|
||||
'attributes': []
|
||||
'custom_attributes': []
|
||||
}
|
||||
}),
|
||||
|
||||
|
|
@ -216,7 +216,7 @@
|
|||
|
||||
groups = this.sortGroups();
|
||||
|
||||
this.group = {'groupName': '', 'position': '', 'attributes': []};
|
||||
this.group = {'groupName': '', 'position': '', 'custom_attributes': []};
|
||||
|
||||
this.$parent.closeModal();
|
||||
}
|
||||
|
|
@ -238,18 +238,18 @@
|
|||
|
||||
data: () => ({
|
||||
groups: groups,
|
||||
attributes: attributes
|
||||
custom_attributes: custom_attributes
|
||||
}),
|
||||
|
||||
created () {
|
||||
this.groups.forEach(function(group) {
|
||||
group.attributes.forEach(function(attribute) {
|
||||
var attribute = this.attributes.filter(attributeTemp => attributeTemp.id == attribute.id)
|
||||
group.custom_attributes.forEach(function(attribute) {
|
||||
var attribute = this.custom_attributes.filter(attributeTemp => attributeTemp.id == attribute.id)
|
||||
|
||||
if(attribute.length) {
|
||||
let index = this.attributes.indexOf(attribute[0])
|
||||
let index = this.custom_attributes.indexOf(attribute[0])
|
||||
|
||||
this.attributes.splice(index, 1)
|
||||
this.custom_attributes.splice(index, 1)
|
||||
}
|
||||
|
||||
});
|
||||
|
|
@ -258,11 +258,11 @@
|
|||
|
||||
methods: {
|
||||
removeGroup (group) {
|
||||
group.attributes.forEach(function(attribute) {
|
||||
this.attributes.push(attribute);
|
||||
group.custom_attributes.forEach(function(attribute) {
|
||||
this.custom_attributes.push(attribute);
|
||||
})
|
||||
|
||||
this.attributes = this.sortAttributes();
|
||||
this.custom_attributes = this.sortAttributes();
|
||||
|
||||
let index = groups.indexOf(group)
|
||||
|
||||
|
|
@ -271,28 +271,28 @@
|
|||
|
||||
addAttributes (groupIndex, attributeIds) {
|
||||
attributeIds.forEach(function(attributeId) {
|
||||
var attribute = this.attributes.filter(attribute => attribute.id == attributeId)
|
||||
var attribute = this.custom_attributes.filter(attribute => attribute.id == attributeId)
|
||||
|
||||
this.groups[groupIndex].attributes.push(attribute[0]);
|
||||
this.groups[groupIndex].custom_attributes.push(attribute[0]);
|
||||
|
||||
let index = this.attributes.indexOf(attribute[0])
|
||||
let index = this.custom_attributes.indexOf(attribute[0])
|
||||
|
||||
this.attributes.splice(index, 1)
|
||||
this.custom_attributes.splice(index, 1)
|
||||
})
|
||||
},
|
||||
|
||||
removeAttribute (groupIndex, attribute) {
|
||||
let index = this.groups[groupIndex].attributes.indexOf(attribute)
|
||||
let index = this.groups[groupIndex].custom_attributes.indexOf(attribute)
|
||||
|
||||
this.groups[groupIndex].attributes.splice(index, 1)
|
||||
this.groups[groupIndex].custom_attributes.splice(index, 1)
|
||||
|
||||
this.attributes.push(attribute);
|
||||
this.custom_attributes.push(attribute);
|
||||
|
||||
this.attributes = this.sortAttributes();
|
||||
this.custom_attributes = this.sortAttributes();
|
||||
},
|
||||
|
||||
sortAttributes () {
|
||||
return this.attributes.sort(function(a, b) {
|
||||
return this.custom_attributes.sort(function(a, b) {
|
||||
return a.id - b.id;
|
||||
});
|
||||
}
|
||||
|
|
@ -300,7 +300,7 @@
|
|||
})
|
||||
|
||||
Vue.component('group-item', {
|
||||
props: ['index', 'group', 'attributes'],
|
||||
props: ['index', 'group', 'custom_attributes'],
|
||||
|
||||
template: "#group-item-template",
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
@if($categories->count())
|
||||
<accordian :title="'{{ __($accordian['name']) }}'" :active="true">
|
||||
<div slot="body">
|
||||
|
||||
|
||||
<tree-view behavior="normal" value-field="id" name-field="categories" input-type="checkbox" items='@json($categories)' value='@json($product->categories->pluck("id"))'></tree-view>
|
||||
|
||||
</div>
|
||||
</accordian>
|
||||
</accordian>
|
||||
@endif
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<accordian :title="'{{ __($accordian['name']) }}'" :active="true">
|
||||
<div slot="body">
|
||||
|
||||
<image-wrapper :button-label="'{{ __('admin::app.catalog.products.add-image-btn-title') }}'" input-name="images" multiple="true"></image-wrapper>
|
||||
|
||||
</div>
|
||||
</accordian>
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
@if ($product->type != 'configurable')
|
||||
<accordian :title="'{{ __($accordian['name']) }}'" :active="true">
|
||||
<div slot="body">
|
||||
|
||||
@foreach ($inventorySources as $inventorySource)
|
||||
<?php
|
||||
|
||||
$qty = 0;
|
||||
foreach ($product->inventories as $inventory) {
|
||||
if($inventory->inventory_source_id == $inventorySource->id) {
|
||||
$qty = $inventory->qty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$qty = old('inventories[' . $inventorySource->id . ']') ?: $qty;
|
||||
|
||||
?>
|
||||
<div class="control-group" :class="[errors.has('inventories[{{ $inventorySource->id }}]') ? 'has-error' : '']">
|
||||
<label>{{ $inventorySource->name }}</label>
|
||||
<input type="text" v-validate="'numeric|min:0'" name="inventories[{{ $inventorySource->id }}]" class="control" value="{{ $qty }}"/>
|
||||
<span class="control-error" v-if="errors.has('inventories[{{ $inventorySource->id }}]')">@{{ errors.first('inventories[{!! $inventorySource->id !!}]') }}</span>
|
||||
</div>
|
||||
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
</accordian>
|
||||
@endif
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<accordian :title="'{{ __($accordian['name']) }}'" :active="true">
|
||||
<div slot="body">
|
||||
|
||||
|
||||
</div>
|
||||
</accordian>
|
||||
|
|
@ -0,0 +1,347 @@
|
|||
@if ($product->type == 'configurable')
|
||||
@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
|
||||
|
||||
<accordian :title="'{{ __($accordian['name']) }}'" :active="true">
|
||||
<div slot="body">
|
||||
|
||||
<button type="button" class="btn btn-md btn-primary" @click="showModal('addVariant')">
|
||||
{{ __('admin::app.catalog.products.add-variant-btn-title') }}
|
||||
</button>
|
||||
|
||||
<variant-list></variant-list>
|
||||
|
||||
</div>
|
||||
</accordian>
|
||||
|
||||
<modal id="addVariant" :is-open="modalIds.addVariant">
|
||||
<h3 slot="header">{{ __('admin::app.catalog.products.add-variant-title') }}</h3>
|
||||
|
||||
<div slot="body">
|
||||
<variant-form></variant-form>
|
||||
</div>
|
||||
</modal>
|
||||
|
||||
@section('javascript')
|
||||
@parent
|
||||
|
||||
<script type="text/x-template" id="variant-form-template">
|
||||
<form method="POST" action="{{ route('admin.catalog.products.store') }}" data-vv-scope="add-variant-form" @submit.prevent="addVariant('add-variant-form')">
|
||||
|
||||
<div class="page-content">
|
||||
<div class="form-container">
|
||||
|
||||
<div v-for='(attribute, index) in super_attributes' class="control-group" :class="[errors.has('add-variant-form.' + attribute.code) ? 'has-error' : '']">
|
||||
<label :for="attribute.code" class="required">@{{ attribute.admin_name }}</label>
|
||||
<select v-validate="'required'" v-model="variant[attribute.code]" class="control" :id="attribute.code" :name="attribute.code">
|
||||
<option v-for='(option, index) in attribute.options' :value="option.id">@{{ option.admin_name }}</option>
|
||||
</select>
|
||||
<span class="control-error" v-if="errors.has('add-variant-form.' + attribute.code)">@{{ errors.first('add-variant-form.' + attribute.code) }}</span>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-lg btn-primary">
|
||||
{{ __('admin::app.catalog.products.add-variant-title') }}
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="variant-list-template">
|
||||
<div class="table" style="margin-top: 20px; overflow-x: unset;">
|
||||
<table>
|
||||
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sku">{{ __('admin::app.catalog.products.sku') }}</th>
|
||||
<th>{{ __('admin::app.catalog.products.name') }}</th>
|
||||
|
||||
@foreach ($product->super_attributes as $attribute)
|
||||
<th class="{{ $attribute->code }}" style="width: 150px">{{ $attribute->admin_name }}</th>
|
||||
@endforeach
|
||||
|
||||
<th class="qty">{{ __('admin::app.catalog.products.qty') }}</th>
|
||||
<th class="price">{{ __('admin::app.catalog.products.price') }}</th>
|
||||
<th class="weight">{{ __('admin::app.catalog.products.weight') }}</th>
|
||||
<th class="status">{{ __('admin::app.catalog.products.status') }}</th>
|
||||
<th class="actions"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
|
||||
<variant-item v-for='(variant, index) in variants' :variant="variant" :key="index" :index="index" @onRemoveVariant="removeVariant($event)"></variant-item>
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/x-template" id="variant-item-template">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="control-group" :class="[errors.has(variantInputName + '[sku]') ? 'has-error' : '']">
|
||||
<input type="text" v-validate="'required'" v-model="variant.sku" :name="[variantInputName + '[sku]']" class="control" v-slugify/>
|
||||
<span class="control-error" v-if="errors.has(variantInputName + '[sku]')">@{{ errors.first(variantInputName + '[sku]') }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div class="control-group" :class="[errors.has(variantInputName + '[name]') ? 'has-error' : '']">
|
||||
<input type="text" v-validate="'required'" v-model="variant.name" :name="[variantInputName + '[name]']" class="control"/>
|
||||
<span class="control-error" v-if="errors.has(variantInputName + '[name]')">@{{ errors.first(variantInputName + '[name]') }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td v-for='(attribute, index) in superAttributes'>
|
||||
<div class="control-group">
|
||||
<input type="hidden" :name="[variantInputName + '[' + attribute.code + ']']" :value="variant[attribute.code]"/>
|
||||
<input type="text" class="control" :value="optionName(variant[attribute.code])" readonly/>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<button style="width: 100%;" type="button" class="dropdown-btn dropdown-toggle">
|
||||
@{{ totalQty }}
|
||||
<i class="icon arrow-down-icon"></i>
|
||||
</button>
|
||||
|
||||
<div class="dropdown-list">
|
||||
<div class="dropdown-container">
|
||||
<ul>
|
||||
<li v-for='(inventorySource, index) in inventorySources'>
|
||||
<div class="control-group" :class="[errors.has(variantInputName + '[inventories][' + inventorySource.id + ']') ? 'has-error' : '']">
|
||||
<label>@{{ inventorySource.name }}</label>
|
||||
<input type="text" v-validate="'numeric|min:0'" :name="[variantInputName + '[inventories][' + inventorySource.id + ']']" v-model="inventories[inventorySource.id]" class="control" v-on:keyup="updateTotalQty()"/>
|
||||
<span class="control-error" v-if="errors.has(variantInputName + '[inventories][' + inventorySource.id + ']')">@{{ errors.first(variantInputName + '[inventories][' + inventorySource.id + ']') }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div class="control-group" :class="[errors.has(variantInputName + '[price]') ? 'has-error' : '']">
|
||||
<input type="text" v-validate="'required'" v-model="variant.price" :name="[variantInputName + '[price]']" class="control"/>
|
||||
<span class="control-error" v-if="errors.has(variantInputName + '[price]')">@{{ errors.first(variantInputName + '[price]') }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div class="control-group" :class="[errors.has(variantInputName + '[price]') ? 'has-error' : '']">
|
||||
<input type="text" v-validate="'required'" v-model="variant.weight" :name="[variantInputName + '[weight]']" class="control"/>
|
||||
<span class="control-error" v-if="errors.has(variantInputName + '[weight]')">@{{ errors.first(variantInputName + '[weight]') }}</span>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div class="control-group">
|
||||
<select type="text" v-model="variant.status" :name="[variantInputName + '[status]']" class="control">
|
||||
<option value="1" :selected="variant.status">{{ __('admin::app.catalog.products.enabled') }}</option>
|
||||
<option value="0" :selected="!variant.status">{{ __('admin::app.catalog.products.disabled') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td class="actions">
|
||||
<a :href="['{{ route('admin.catalog.products.index') }}/edit/' + variant.id]"><i class="icon pencil-lg-icon"></i></a>
|
||||
<i class="icon remove-icon" @click="removeVariant()"></i>
|
||||
</td>
|
||||
</tr>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
Vue.config.ignoredElements = [
|
||||
'variant-form',
|
||||
'variant-list',
|
||||
'variant-item'
|
||||
];
|
||||
});
|
||||
|
||||
var super_attributes = @json($product->super_attributes);
|
||||
var variants = @json($product->variants);
|
||||
|
||||
Vue.component('variant-form', {
|
||||
|
||||
data: () => ({
|
||||
variant: {},
|
||||
super_attributes: super_attributes
|
||||
}),
|
||||
|
||||
template: '#variant-form-template',
|
||||
|
||||
created () {
|
||||
this.resetModel();
|
||||
},
|
||||
|
||||
methods: {
|
||||
addVariant (formScope) {
|
||||
this.$validator.validateAll(formScope).then((result) => {
|
||||
if (result) {
|
||||
var this_this = this;
|
||||
|
||||
var filteredVariants = variants.filter(function(variant) {
|
||||
var matchCount = 0;
|
||||
|
||||
for (var key in this_this.variant) {
|
||||
if(variant[key] == this_this.variant[key]) {
|
||||
matchCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return matchCount == this_this.super_attributes.length;
|
||||
})
|
||||
|
||||
if(filteredVariants.length) {
|
||||
this.$parent.closeModal();
|
||||
|
||||
window.flashMessages = [{'type': 'alert-error', 'message': "{{ __('admin::app.catalog.products.variant-already-exist-message') }}" }];
|
||||
|
||||
this.$root.addFlashMessages()
|
||||
} else {
|
||||
var optionIds = [];
|
||||
for (var key in this_this.variant) {
|
||||
optionIds.push(this_this.variant[key]);
|
||||
}
|
||||
|
||||
variants.push(Object.assign({
|
||||
sku: '{{ $product->sku }}' + '-variant-' + optionIds.join('-'),
|
||||
name: '',
|
||||
price: 0,
|
||||
weight: 0,
|
||||
status: 1
|
||||
}, this.variant));
|
||||
|
||||
this.resetModel();
|
||||
|
||||
this.$parent.closeModal();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
resetModel () {
|
||||
var this_this = this;
|
||||
|
||||
this.super_attributes.forEach(function(attribute) {
|
||||
this_this.variant[attribute.code] = '';
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Vue.component('variant-list', {
|
||||
|
||||
template: '#variant-list-template',
|
||||
|
||||
inject: ['$validator'],
|
||||
|
||||
data: () => ({
|
||||
variants: variants,
|
||||
superAttributes: super_attributes
|
||||
}),
|
||||
|
||||
methods: {
|
||||
removeVariant(variant) {
|
||||
let index = this.variants.indexOf(variant)
|
||||
|
||||
this.variants.splice(index, 1)
|
||||
},
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Vue.component('variant-item', {
|
||||
|
||||
template: '#variant-item-template',
|
||||
|
||||
props: ['index', 'variant'],
|
||||
|
||||
inject: ['$validator'],
|
||||
|
||||
data: () => ({
|
||||
inventorySources: @json($inventorySources),
|
||||
inventories: {},
|
||||
totalQty: 0,
|
||||
superAttributes: super_attributes
|
||||
}),
|
||||
|
||||
created () {
|
||||
var this_this = this;
|
||||
this.inventorySources.forEach(function(inventorySource) {
|
||||
this_this.inventories[inventorySource.id] = this_this.sourceInventoryQty(inventorySource.id)
|
||||
this_this.totalQty += parseInt(this_this.inventories[inventorySource.id]);
|
||||
})
|
||||
},
|
||||
|
||||
computed: {
|
||||
variantInputName () {
|
||||
if(this.variant.id)
|
||||
return "variants[" + this.variant.id + "]";
|
||||
|
||||
return "variants[variant_" + this.index + "]";
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
removeVariant () {
|
||||
this.$emit('onRemoveVariant', this.variant)
|
||||
},
|
||||
|
||||
optionName (optionId) {
|
||||
var optionName = '';
|
||||
|
||||
this.superAttributes.forEach(function(attribute) {
|
||||
attribute.options.forEach(function(option) {
|
||||
if(optionId == option.id) {
|
||||
optionName = option.admin_name;
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
return optionName;
|
||||
},
|
||||
|
||||
sourceInventoryQty (inventorySourceId) {
|
||||
var inventories = this.variant.inventories.filter(function(inventory) {
|
||||
return inventorySourceId === inventory.inventory_source_id;
|
||||
})
|
||||
|
||||
if(inventories.length)
|
||||
return inventories[0]['qty'];
|
||||
|
||||
return 0;
|
||||
},
|
||||
|
||||
updateTotalQty () {
|
||||
this.totalQty = 0;
|
||||
for (var key in this.inventories) {
|
||||
this.totalQty += parseInt(this.inventories[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
@stop
|
||||
@endif
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
@extends('admin::layouts.content')
|
||||
|
||||
@section('page_title')
|
||||
{{ __('admin::app.catalog.products.add-title') }}
|
||||
@stop
|
||||
|
||||
@section('css')
|
||||
<style>
|
||||
.table td .label {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,44 @@
|
|||
@extends('admin::layouts.content')
|
||||
|
||||
@section('page_title')
|
||||
{{ __('admin::app.catalog.products.edit-title') }}
|
||||
@stop
|
||||
|
||||
@section('content')
|
||||
<div class="content">
|
||||
<form method="POST" action="{{ route('admin.catalog.products.update', $product->id) }}" @submit.prevent="onSubmit">
|
||||
<?php $locale = request()->get('locale') ?: app()->getLocale(); ?>
|
||||
<?php $channel = request()->get('channel') ?: channel()->getChannel(); ?>
|
||||
|
||||
<form method="POST" action="" @submit.prevent="onSubmit">
|
||||
|
||||
<div class="page-header">
|
||||
|
||||
<div class="page-title">
|
||||
<h1>{{ __('admin::app.catalog.products.edit-title') }}</h1>
|
||||
|
||||
<div class="control-group">
|
||||
<select class="control" id="channel-switcher" name="channel">
|
||||
@foreach(channel()->getAllChannels() as $channelModel)
|
||||
|
||||
<option value="{{ $channelModel->code }}" {{ ($channelModel->code) == $channel ? 'selected' : '' }}>
|
||||
{{ $channelModel->name }}
|
||||
</option>
|
||||
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<select class="control" id="locale-switcher" name="locale">
|
||||
@foreach(core()->getAllLocales() as $localeModel)
|
||||
|
||||
<option value="{{ $localeModel->code }}" {{ ($localeModel->code) == $locale ? 'selected' : '' }}>
|
||||
{{ $localeModel->name }}
|
||||
</option>
|
||||
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-action">
|
||||
|
|
@ -19,29 +51,62 @@
|
|||
<div class="page-content">
|
||||
@csrf()
|
||||
|
||||
<input name="_method" type="hidden" value="PUT">
|
||||
|
||||
@foreach($product->attribute_family->attribute_groups as $attributeGroup)
|
||||
@if(count($attributeGroup->attributes))
|
||||
@if(count($attributeGroup->custom_attributes))
|
||||
<accordian :title="'{{ __($attributeGroup->name) }}'" :active="true">
|
||||
<div slot="body">
|
||||
|
||||
@foreach($attributeGroup->attributes as $attribute)
|
||||
@foreach($attributeGroup->custom_attributes as $attribute)
|
||||
|
||||
@if(!$product->super_attributes->contains($attribute))
|
||||
|
||||
<?php
|
||||
$validations = [];
|
||||
if($attribute->is_required) {
|
||||
array_push($validations, 'required');
|
||||
}
|
||||
$disabled = false;
|
||||
if($product->type == 'configurable' && in_array($attribute->code, ['price', 'cost', 'special_price', 'special_price_from', 'special_price_to', 'width', 'height', 'depth', 'weight'])) {
|
||||
if(!$attribute->is_required)
|
||||
continue;
|
||||
|
||||
array_push($validations, $attribute->validation);
|
||||
$disabled = true;
|
||||
} else {
|
||||
if($attribute->is_required) {
|
||||
array_push($validations, 'required');
|
||||
}
|
||||
|
||||
array_push($validations, $attribute->validation);
|
||||
}
|
||||
|
||||
$validations = implode('|', array_filter($validations));
|
||||
?>
|
||||
|
||||
@if(view()->exists($typeView = 'admin::catalog.products.field-types.' . $attribute->type))
|
||||
|
||||
@include ($typeView)
|
||||
<div class="control-group" :class="[errors.has('{{ $attribute->code }}') ? 'has-error' : '']">
|
||||
<label for="{{ $attribute->code }}" {{ $attribute->is_required ? 'class=required' : '' }}>
|
||||
{{ $attribute->admin_name }}
|
||||
|
||||
<?php
|
||||
$channel_locale = [];
|
||||
if($attribute->value_per_channel) {
|
||||
array_push($channel_locale, $channel);
|
||||
}
|
||||
|
||||
if($attribute->value_per_locale) {
|
||||
array_push($channel_locale, $locale);
|
||||
}
|
||||
?>
|
||||
|
||||
@if(count($channel_locale))
|
||||
<span class="locale">[{{ implode(' - ', $channel_locale) }}]</span>
|
||||
@endif
|
||||
</label>
|
||||
|
||||
@include ($typeView)
|
||||
|
||||
<span class="control-error" v-if="errors.has('{{ $attribute->code }}')">@{{ errors.first('{!! $attribute->code !!}') }}</span>
|
||||
</div>
|
||||
|
||||
@endif
|
||||
|
||||
|
|
@ -59,8 +124,22 @@
|
|||
@include ($accordian['view'])
|
||||
|
||||
@endforeach
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
@stop
|
||||
|
||||
@section('javascript')
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('#channel-switcher, #locale-switcher').on('change', function (e) {
|
||||
$('#channel-switcher').val()
|
||||
var query = '?channel=' + $('#channel-switcher').val() + '&locale=' + $('#locale-switcher').val();
|
||||
|
||||
window.location.href = "{{ route('admin.catalog.products.edit', $product->id) }}" + query;
|
||||
})
|
||||
});
|
||||
</script>
|
||||
@stop
|
||||
|
|
@ -1,16 +1,12 @@
|
|||
<div class="control-group" :class="[errors.has('{{ $attribute->code }}') ? 'has-error' : '']">
|
||||
<label for="{{ $attribute->code }}" {{ $attribute->is_required ? 'class=required' : '' }}>
|
||||
{{ $attribute->admin_name }}
|
||||
</label>
|
||||
<select v-validate="'{{$validations}}'" class="control" id="{{ $attribute->code }}" name="{{ $attribute->code }}" {{ $disabled ? 'disabled' : '' }}>
|
||||
|
||||
<select v-validate="'{{$validations}}'" class="control" id="{{ $attribute->code }}" name="{{ $attribute->code }}">
|
||||
<option value="0" {{ !$product[$attribute->code] ? 'selected' : ''}}>
|
||||
{{ __('admin::app.catalog.products.no') }}
|
||||
</option>
|
||||
<option value="1" {{ $product[$attribute->code] ? 'selected' : ''}}>
|
||||
{{ __('admin::app.catalog.products.yes') }}
|
||||
</option>
|
||||
</select>
|
||||
<?php $selectedOption = old($attribute->code) ?: $product[$attribute->code] ?>
|
||||
|
||||
<span class="control-error" v-if="errors.has('{{ $attribute->code }}')">@{{ errors.first('{!! $attribute->code !!}') }}</span>
|
||||
</div>
|
||||
<option value="0" {{ $selectedOption ? '' : 'selected'}}>
|
||||
{{ $attribute->code == 'status' ? __('admin::app.catalog.products.disabled') : __('admin::app.catalog.products.no') }}
|
||||
</option>
|
||||
<option value="1" {{ $selectedOption ? 'selected' : ''}}>
|
||||
{{ $attribute->code == 'status' ? __('admin::app.catalog.products.enabled') : __('admin::app.catalog.products.yes') }}
|
||||
</option>
|
||||
|
||||
</select>
|
||||
|
|
@ -1,11 +1,3 @@
|
|||
<div class="control-group" :class="[errors.has('{{ $attribute->code }}') ? 'has-error' : '']">
|
||||
<label for="{{ $attribute->code }}" {{ $attribute->is_required ? 'class=required' : '' }}>
|
||||
{{ $attribute->admin_name }}
|
||||
</label>
|
||||
|
||||
<date>
|
||||
<input type="text" name="{{ $attribute->code }}" class="control" v-validate="'required'" value="{{ $product[$attribute->code]}}" data-input>
|
||||
</date>
|
||||
|
||||
<span class="control-error" v-if="errors.has('{{ $attribute->code }}')">@{{ errors.first('{!! $attribute->code !!}') }}</span>
|
||||
</div>
|
||||
<date>
|
||||
<input type="text" name="{{ $attribute->code }}" class="control" {{ $attribute->is_required ? "v-validate='required'" : '' }} value="{{ old($attribute->code) ?: $product[$attribute->code] }}" {{ $disabled ? 'disabled' : '' }}/>
|
||||
</date>
|
||||
|
|
@ -1,11 +1,3 @@
|
|||
<div class="control-group" :class="[errors.has('{{ $attribute->code }}') ? 'has-error' : '']">
|
||||
<label for="{{ $attribute->code }}" {{ $attribute->is_required ? 'class=required' : '' }}>
|
||||
{{ $attribute->admin_name }}
|
||||
</label>
|
||||
|
||||
<datetime>
|
||||
<input type="text" name="{{ $attribute->code }}" class="control" v-validate="'required'" value="{{ $product[$attribute->code]}}" data-input>
|
||||
</datetime>
|
||||
|
||||
<span class="control-error" v-if="errors.has('{{ $attribute->code }}')">@{{ errors.first('{!! $attribute->code !!}') }}</span>
|
||||
</div>
|
||||
<datetime>
|
||||
<input type="text" name="{{ $attribute->code }}" class="control" {{ $attribute->is_required ? "v-validate='required'" : '' }} value="{{ old($attribute->code) ?: $product[$attribute->code]}}" {{ $disabled ? 'disabled' : '' }}>
|
||||
</datetime>
|
||||
|
|
@ -1,17 +1,9 @@
|
|||
<div class="control-group" :class="[errors.has('{{ $attribute->code }}') ? 'has-error' : '']">
|
||||
<label for="{{ $attribute->code }}" {{ $attribute->is_required ? 'class=required' : '' }}>
|
||||
{{ $attribute->admin_name }}
|
||||
</label>
|
||||
<select v-validate="'{{$validations}}'" class="control" id="{{ $attribute->code }}" name="{{ $attribute->code }}" multiple {{ $disabled ? 'disabled' : '' }}>
|
||||
|
||||
<select v-validate="'{{$validations}}'" class="control" id="{{ $attribute->code }}" name="{{ $attribute->code }}" multiple>
|
||||
@foreach($attribute->options as $option)
|
||||
<option value="{{ $option->id }}" {{ in_array($option->id, explode(',', $attribute[$attribute->code])) ? 'selected' : ''}}>
|
||||
{{ $option->admin_name }}
|
||||
</option>
|
||||
@endforeach
|
||||
|
||||
@foreach($attribute->options as $option)
|
||||
<option value="{{ $option->id }}" {{ in_array($option->id, explode(',', $attribute[$attribute->code])) ? 'selected' : ''}}>
|
||||
{{ $option->admin_name }}
|
||||
</option>
|
||||
@endforeach
|
||||
|
||||
</select>
|
||||
|
||||
<span class="control-error" v-if="errors.has('{{ $attribute->code }}')">@{{ errors.first('{!! $attribute->code !!}') }}</span>
|
||||
</div>
|
||||
</select>
|
||||
|
|
@ -1,9 +1 @@
|
|||
<div class="control-group" :class="[errors.has('{{ $attribute->code }}') ? 'has-error' : '']">
|
||||
<label for="{{ $attribute->code }}" {{ $attribute->is_required ? 'class=required' : '' }}>
|
||||
{{ $attribute->admin_name }}
|
||||
</label>
|
||||
|
||||
<input type="text" v-validate="'{{$validations}}'" class="control" id="{{ $attribute->code }}" name="{{ $attribute->code }}" value="{{ $product[$attribute->code]}}"/>
|
||||
|
||||
<span class="control-error" v-if="errors.has('{{ $attribute->code }}')">@{{ errors.first('{!! $attribute->code !!}') }}</span>
|
||||
</div>
|
||||
<input type="text" v-validate="'{{$validations}}'" class="control" id="{{ $attribute->code }}" name="{{ $attribute->code }}" value="{{ old($attribute->code) ?: $product[$attribute->code]}}" {{ $disabled ? 'disabled' : '' }}/>
|
||||
|
|
@ -1,17 +1,11 @@
|
|||
<div class="control-group" :class="[errors.has('{{ $attribute->code }}') ? 'has-error' : '']">
|
||||
<label for="{{ $attribute->code }}" {{ $attribute->is_required ? 'class=required' : '' }}>
|
||||
{{ $attribute->admin_name }}
|
||||
</label>
|
||||
<select v-validate="'{{$validations}}'" class="control" id="{{ $attribute->code }}" name="{{ $attribute->code }}" {{ $disabled ? 'disabled' : '' }}>
|
||||
|
||||
<select v-validate="'{{$validations}}'" class="control" id="{{ $attribute->code }}" name="{{ $attribute->code }}">
|
||||
<?php $selectedOption = old($attribute->code) ?: $product[$attribute->code] ?>
|
||||
|
||||
@foreach($attribute->options as $option)
|
||||
<option value="{{ $option->id }}" {{ $option->id == $attribute[$attribute->code] ? 'selected' : ''}}>
|
||||
{{ $option->admin_name }}
|
||||
</option>
|
||||
@endforeach
|
||||
@foreach($attribute->options as $option)
|
||||
<option value="{{ $option->id }}" {{ $option->id == $selectedOption ? 'selected' : ''}}>
|
||||
{{ $option->admin_name }}
|
||||
</option>
|
||||
@endforeach
|
||||
|
||||
</select>
|
||||
|
||||
<span class="control-error" v-if="errors.has('{{ $attribute->code }}')">@{{ errors.first('{!! $attribute->code !!}') }}</span>
|
||||
</div>
|
||||
</select>
|
||||
|
|
@ -1,9 +1 @@
|
|||
<div class="control-group" :class="[errors.has('{{ $attribute->code }}') ? 'has-error' : '']">
|
||||
<label for="{{ $attribute->code }}" {{ $attribute->is_required ? 'class=required' : '' }}>
|
||||
{{ $attribute->admin_name }}
|
||||
</label>
|
||||
|
||||
<input type="text" v-validate="'{{$validations}}'" class="control" id="{{ $attribute->code }}" name="{{ $attribute->code }}" value="{{ $product[$attribute->code]}}"/>
|
||||
|
||||
<span class="control-error" v-if="errors.has('{{ $attribute->code }}')">@{{ errors.first('{!! $attribute->code !!}') }}</span>
|
||||
</div>
|
||||
<input type="text" v-validate="'{{$validations}}'" class="control" id="{{ $attribute->code }}" name="{{ $attribute->code }}" value="{{ old($attribute->code) ?: $product[$attribute->code] }}" {{ $disabled ? 'disabled' : '' }} {{ in_array($attribute->code, ['sku', 'url_key']) ? 'v-slugify' : '' }}/>
|
||||
|
|
@ -1,11 +1 @@
|
|||
<div class="control-group" :class="[errors.has('{{ $attribute->code }}') ? 'has-error' : '']">
|
||||
<label for="{{ $attribute->code }}" {{ $attribute->is_required ? 'class=required' : '' }}>
|
||||
{{ $attribute->admin_name }}
|
||||
</label>
|
||||
|
||||
<textarea v-validate="'{{$validations}}'" class="control" id="{{ $attribute->code }}" name="{{ $attribute->code }}">
|
||||
{{ $product[$attribute->code]}}
|
||||
</textarea>
|
||||
|
||||
<span class="control-error" v-if="errors.has('{{ $attribute->code }}')">@{{ errors.first('{!! $attribute->code !!}') }}</span>
|
||||
</div>
|
||||
<textarea v-validate="'{{$validations}}'" class="control" id="{{ $attribute->code }}" name="{{ $attribute->code }}" {{ $disabled ? 'disabled' : '' }}>{{ old($attribute->code) ?: $product[$attribute->code]}}</textarea>
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
|
||||
<label for="code" class="required">{{ __('admin::app.settings.channels.code') }}</label>
|
||||
<input v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') }}"/>
|
||||
<input v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') }}" v-code/>
|
||||
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -54,7 +54,7 @@
|
|||
<div class="control-group" :class="[errors.has('locales[]') ? 'has-error' : '']">
|
||||
<label for="locales" class="required">{{ __('admin::app.settings.channels.locales') }}</label>
|
||||
<select v-validate="'required'" class="control" id="locales" name="locales[]" multiple>
|
||||
@foreach(core()->allLocales() as $locale)
|
||||
@foreach(core()->getAllLocales() as $locale)
|
||||
<option value="{{ $locale->id }}" {{ old('locales') && in_array($locale->id, old('locales')) ? 'selected' : '' }}>
|
||||
{{ $locale->name }}
|
||||
</option>
|
||||
|
|
@ -66,7 +66,7 @@
|
|||
<div class="control-group" :class="[errors.has('default_locale') ? 'has-error' : '']">
|
||||
<label for="default_locale" class="required">{{ __('admin::app.settings.channels.default-locale') }}</label>
|
||||
<select v-validate="'required'" class="control" id="default_locale" name="default_locale">
|
||||
@foreach(core()->allLocales() as $locale)
|
||||
@foreach(core()->getAllLocales() as $locale)
|
||||
<option value="{{ $locale->id }}" {{ old('default_locale') == $locale->id ? 'selected' : '' }}>
|
||||
{{ $locale->name }}
|
||||
</option>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
|
||||
<label for="code" class="required">{{ __('admin::app.settings.channels.code') }}</label>
|
||||
<input v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') ?: $channel->code }}"/>
|
||||
<input v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') ?: $channel->code }}" v-code/>
|
||||
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -56,7 +56,7 @@
|
|||
<label for="locales" class="required">{{ __('admin::app.settings.channels.locales') }}</label>
|
||||
<?php $selectedOptionIds = old('locales') ?: $channel->locales->pluck('id')->toArray() ?>
|
||||
<select v-validate="'required'" class="control" id="locales" name="locales[]" multiple>
|
||||
@foreach(core()->allLocales() as $locale)
|
||||
@foreach(core()->getAllLocales() as $locale)
|
||||
<option value="{{ $locale->id }}" {{ in_array($locale->id, $selectedOptionIds) ? 'selected' : '' }}>
|
||||
{{ $locale->name }}
|
||||
</option>
|
||||
|
|
@ -69,7 +69,7 @@
|
|||
<label for="default_locale" class="required">{{ __('admin::app.settings.channels.default-locale') }}</label>
|
||||
<?php $selectedOption = old('default_locale') ?: $channel->default_locale ?>
|
||||
<select v-validate="'required'" class="control" id="default_locale" name="default_locale">
|
||||
@foreach(core()->allLocales() as $locale)
|
||||
@foreach(core()->getAllLocales() as $locale)
|
||||
<option value="{{ $locale->id }}" {{ $selectedOption == $locale->id ? 'selected' : '' }}>
|
||||
{{ $locale->name }}
|
||||
</option>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
<div slot="body">
|
||||
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
|
||||
<label for="code" class="required">{{ __('admin::app.settings.countries.code') }}</label>
|
||||
<input v-validate="'required'" class="control" id="code" name="code"/>
|
||||
<input v-validate="'required'" class="control" id="code" name="code" v-code/>
|
||||
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
<div slot="body">
|
||||
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
|
||||
<label for="code" class="required">{{ __('admin::app.settings.currencies.code') }}</label>
|
||||
<input v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') }}"/>
|
||||
<input v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') }}" v-code/>
|
||||
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
<div slot="body">
|
||||
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
|
||||
<label for="code" class="required">{{ __('admin::app.settings.currencies.code') }}</label>
|
||||
<input v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') ?: $currency->code }}"/>
|
||||
<input v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') ?: $currency->code }}" v-code/>
|
||||
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
|
||||
<label for="code" class="required">{{ __('admin::app.settings.inventory_sources.code') }}</label>
|
||||
<input v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') }}"/>
|
||||
<input v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') }}" v-code/>
|
||||
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
|
||||
<label for="code" class="required">{{ __('admin::app.settings.inventory_sources.code') }}</label>
|
||||
<input v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') ?: $inventorySource->code }}"/>
|
||||
<input v-validate="'required'" class="control" id="code" name="code" value="{{ old('code') ?: $inventorySource->code }}" v-code/>
|
||||
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
<div slot="body">
|
||||
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
|
||||
<label for="code">{{ __('admin::app.settings.locales.code') }}</label>
|
||||
<input v-validate="'required'" class="control" id="code" name="code"/>
|
||||
<input v-validate="'required'" class="control" id="code" name="code" v-code/>
|
||||
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -37,8 +37,11 @@ class AttributeFamilyTableSeeder extends Seeder
|
|||
'code' => 'new_to',
|
||||
'position' => 5
|
||||
], [
|
||||
'code' => 'status',
|
||||
'code' => 'visible_individually',
|
||||
'position' => 6
|
||||
], [
|
||||
'code' => 'status',
|
||||
'position' => 7
|
||||
]
|
||||
]
|
||||
], [
|
||||
|
|
|
|||
|
|
@ -83,6 +83,20 @@ class AttributeTableSeeder extends Seeder
|
|||
'is_filterable' => 0,
|
||||
'is_configurable' => 0,
|
||||
'is_user_defined' => 0
|
||||
], [
|
||||
'code' => 'visible_individually',
|
||||
'admin_name' => 'Visible Individually',
|
||||
'en' => [
|
||||
'name' => 'Visible Individually'
|
||||
],
|
||||
'type' => 'boolean',
|
||||
'position' => 6,
|
||||
'is_required' => 1,
|
||||
'value_per_locale' => 0,
|
||||
'value_per_channel' => 0,
|
||||
'is_filterable' => 0,
|
||||
'is_configurable' => 0,
|
||||
'is_user_defined' => 0
|
||||
], [
|
||||
'code' => 'status',
|
||||
'admin_name' => 'Status',
|
||||
|
|
@ -90,7 +104,7 @@ class AttributeTableSeeder extends Seeder
|
|||
'name' => 'Status'
|
||||
],
|
||||
'type' => 'boolean',
|
||||
'position' => 6,
|
||||
'position' => 7,
|
||||
'is_required' => 1,
|
||||
'value_per_locale' => 0,
|
||||
'value_per_channel' => 0,
|
||||
|
|
@ -104,7 +118,7 @@ class AttributeTableSeeder extends Seeder
|
|||
'name' => 'Short Description'
|
||||
],
|
||||
'type' => 'textarea',
|
||||
'position' => 7,
|
||||
'position' => 8,
|
||||
'is_required' => 1,
|
||||
'value_per_locale' => 1,
|
||||
'value_per_channel' => 1,
|
||||
|
|
@ -118,7 +132,7 @@ class AttributeTableSeeder extends Seeder
|
|||
'name' => 'Description'
|
||||
],
|
||||
'type' => 'textarea',
|
||||
'position' => 8,
|
||||
'position' => 9,
|
||||
'is_required' => 1,
|
||||
'value_per_locale' => 1,
|
||||
'value_per_channel' => 1,
|
||||
|
|
@ -132,10 +146,10 @@ class AttributeTableSeeder extends Seeder
|
|||
'name' => 'Price'
|
||||
],
|
||||
'type' => 'price',
|
||||
'position' => 9,
|
||||
'position' => 10,
|
||||
'is_required' => 1,
|
||||
'value_per_locale' => 0,
|
||||
'value_per_channel' => 0,
|
||||
'value_per_channel' => 1,
|
||||
'is_filterable' => 1,
|
||||
'is_configurable' => 0,
|
||||
'is_user_defined' => 0
|
||||
|
|
@ -146,10 +160,10 @@ class AttributeTableSeeder extends Seeder
|
|||
'name' => 'Cost'
|
||||
],
|
||||
'type' => 'price',
|
||||
'position' => 10,
|
||||
'position' => 11,
|
||||
'is_required' => 0,
|
||||
'value_per_locale' => 0,
|
||||
'value_per_channel' => 0,
|
||||
'value_per_channel' => 1,
|
||||
'is_filterable' => 0,
|
||||
'is_configurable' => 0,
|
||||
'is_user_defined' => 1
|
||||
|
|
@ -160,10 +174,10 @@ class AttributeTableSeeder extends Seeder
|
|||
'name' => 'Special Price'
|
||||
],
|
||||
'type' => 'price',
|
||||
'position' => 11,
|
||||
'position' => 12,
|
||||
'is_required' => 0,
|
||||
'value_per_locale' => 0,
|
||||
'value_per_channel' => 0,
|
||||
'value_per_channel' => 1,
|
||||
'is_filterable' => 0,
|
||||
'is_configurable' => 0,
|
||||
'is_user_defined' => 0
|
||||
|
|
@ -174,10 +188,10 @@ class AttributeTableSeeder extends Seeder
|
|||
'name' => 'Special Price From'
|
||||
],
|
||||
'type' => 'datetime',
|
||||
'position' => 12,
|
||||
'position' => 13,
|
||||
'is_required' => 0,
|
||||
'value_per_locale' => 0,
|
||||
'value_per_channel' => 0,
|
||||
'value_per_channel' => 1,
|
||||
'is_filterable' => 0,
|
||||
'is_configurable' => 0,
|
||||
'is_user_defined' => 0
|
||||
|
|
@ -188,10 +202,10 @@ class AttributeTableSeeder extends Seeder
|
|||
'name' => 'Special Price To'
|
||||
],
|
||||
'type' => 'datetime',
|
||||
'position' => 13,
|
||||
'position' => 14,
|
||||
'is_required' => 0,
|
||||
'value_per_locale' => 0,
|
||||
'value_per_channel' => 0,
|
||||
'value_per_channel' => 1,
|
||||
'is_filterable' => 0,
|
||||
'is_configurable' => 0,
|
||||
'is_user_defined' => 0
|
||||
|
|
@ -202,7 +216,7 @@ class AttributeTableSeeder extends Seeder
|
|||
'name' => 'Meta Description'
|
||||
],
|
||||
'type' => 'textarea',
|
||||
'position' => 14,
|
||||
'position' => 15,
|
||||
'is_required' => 0,
|
||||
'value_per_locale' => 1,
|
||||
'value_per_channel' => 1,
|
||||
|
|
@ -216,7 +230,7 @@ class AttributeTableSeeder extends Seeder
|
|||
'name' => 'Meta Keywords'
|
||||
],
|
||||
'type' => 'textarea',
|
||||
'position' => 15,
|
||||
'position' => 16,
|
||||
'is_required' => 0,
|
||||
'value_per_locale' => 1,
|
||||
'value_per_channel' => 1,
|
||||
|
|
@ -230,7 +244,7 @@ class AttributeTableSeeder extends Seeder
|
|||
'name' => 'Meta Description'
|
||||
],
|
||||
'type' => 'textarea',
|
||||
'position' => 16,
|
||||
'position' => 17,
|
||||
'is_required' => 0,
|
||||
'value_per_locale' => 1,
|
||||
'value_per_channel' => 1,
|
||||
|
|
@ -245,7 +259,7 @@ class AttributeTableSeeder extends Seeder
|
|||
],
|
||||
'type' => 'text',
|
||||
'validation' => 'number',
|
||||
'position' => 17,
|
||||
'position' => 18,
|
||||
'is_required' => 0,
|
||||
'value_per_locale' => 0,
|
||||
'value_per_channel' => 0,
|
||||
|
|
@ -260,7 +274,7 @@ class AttributeTableSeeder extends Seeder
|
|||
],
|
||||
'type' => 'text',
|
||||
'validation' => 'number',
|
||||
'position' => 18,
|
||||
'position' => 19,
|
||||
'is_required' => 0,
|
||||
'value_per_locale' => 0,
|
||||
'value_per_channel' => 0,
|
||||
|
|
@ -275,7 +289,7 @@ class AttributeTableSeeder extends Seeder
|
|||
],
|
||||
'type' => 'text',
|
||||
'validation' => 'number',
|
||||
'position' => 19,
|
||||
'position' => 20,
|
||||
'is_required' => 0,
|
||||
'value_per_locale' => 0,
|
||||
'value_per_channel' => 0,
|
||||
|
|
@ -290,7 +304,7 @@ class AttributeTableSeeder extends Seeder
|
|||
],
|
||||
'type' => 'text',
|
||||
'validation' => 'number',
|
||||
'position' => 20,
|
||||
'position' => 21,
|
||||
'is_required' => 1,
|
||||
'value_per_locale' => 0,
|
||||
'value_per_channel' => 0,
|
||||
|
|
@ -304,7 +318,7 @@ class AttributeTableSeeder extends Seeder
|
|||
'name' => 'Color'
|
||||
],
|
||||
'type' => 'select',
|
||||
'position' => 21,
|
||||
'position' => 22,
|
||||
'is_required' => 0,
|
||||
'value_per_locale' => 0,
|
||||
'value_per_channel' => 0,
|
||||
|
|
@ -346,7 +360,7 @@ class AttributeTableSeeder extends Seeder
|
|||
'name' => 'Size'
|
||||
],
|
||||
'type' => 'select',
|
||||
'position' => 22,
|
||||
'position' => 23,
|
||||
'is_required' => 0,
|
||||
'value_per_locale' => 0,
|
||||
'value_per_channel' => 0,
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ class AttributeController extends Controller
|
|||
public function store()
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'code' => ['required', 'unique:attributes,code', new \Webkul\Core\Contracts\Validations\Slug],
|
||||
'code' => ['required', 'unique:attributes,code', new \Webkul\Core\Contracts\Validations\Code],
|
||||
'admin_name' => 'required',
|
||||
'type' => 'required'
|
||||
]);
|
||||
|
|
@ -105,7 +105,7 @@ class AttributeController extends Controller
|
|||
public function update(Request $request, $id)
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'code' => ['required', 'unique:attributes,code,' . $id, new \Webkul\Core\Contracts\Validations\Slug],
|
||||
'code' => ['required', 'unique:attributes,code,' . $id, new \Webkul\Core\Contracts\Validations\Code],
|
||||
'admin_name' => 'required',
|
||||
'type' => 'required'
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -61,11 +61,11 @@ class AttributeFamilyController extends Controller
|
|||
*/
|
||||
public function create(Attribute $attribute)
|
||||
{
|
||||
$attributeFamily = $this->attributeFamily->findBy('code', 'default', ['*'], ['attribute_groups.attributes']);
|
||||
$attributeFamily = $this->attributeFamily->findBy('code', 'default', ['*'], ['attribute_groups.custom_attributes']);
|
||||
|
||||
$attributes = $attribute->all(['id', 'code', 'admin_name', 'type']);
|
||||
$custom_attributes = $attribute->all(['id', 'code', 'admin_name', 'type']);
|
||||
|
||||
return view($this->_config['view'], compact('attributes', 'attributeFamily'));
|
||||
return view($this->_config['view'], compact('custom_attributes', 'attributeFamily'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -76,7 +76,7 @@ class AttributeFamilyController extends Controller
|
|||
public function store()
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'code' => ['required', 'unique:attribute_families,code', new \Webkul\Core\Contracts\Validations\Slug],
|
||||
'code' => ['required', 'unique:attribute_families,code', new \Webkul\Core\Contracts\Validations\Code],
|
||||
'name' => 'required'
|
||||
]);
|
||||
|
||||
|
|
@ -96,11 +96,11 @@ class AttributeFamilyController extends Controller
|
|||
*/
|
||||
public function edit(Attribute $attribute, $id)
|
||||
{
|
||||
$attributeFamily = $this->attributeFamily->findOrFail($id, ['*'], ['attribute_groups.attributes']);
|
||||
$attributeFamily = $this->attributeFamily->findOrFail($id, ['*'], ['attribute_groups.custom_attributes']);
|
||||
|
||||
$attributes = $attribute->all(['id', 'code', 'admin_name', 'type']);
|
||||
$custom_attributes = $attribute->all(['id', 'code', 'admin_name', 'type']);
|
||||
|
||||
return view($this->_config['view'], compact('attributeFamily', 'attributes'));
|
||||
return view($this->_config['view'], compact('attributeFamily', 'custom_attributes'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -113,7 +113,7 @@ class AttributeFamilyController extends Controller
|
|||
public function update(Request $request, $id)
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'code' => ['required', 'unique:attribute_families,code,' . $id, new \Webkul\Core\Contracts\Validations\Slug],
|
||||
'code' => ['required', 'unique:attribute_families,code,' . $id, new \Webkul\Core\Contracts\Validations\Code],
|
||||
'name' => 'required'
|
||||
]);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class AttributeFamily extends Model
|
|||
/**
|
||||
* Get all of the attributes for the attribute groups.
|
||||
*/
|
||||
public function attributes()
|
||||
public function custom_attributes()
|
||||
{
|
||||
return Attribute::join('attribute_group_mappings', 'attributes.id', '=', 'attribute_group_mappings.attribute_id')
|
||||
->join('attribute_groups', 'attribute_group_mappings.attribute_group_id', '=', 'attribute_groups.id')
|
||||
|
|
@ -26,9 +26,9 @@ class AttributeFamily extends Model
|
|||
/**
|
||||
* Get all of the attributes for the attribute groups.
|
||||
*/
|
||||
public function getAttributesAttribute()
|
||||
public function getCustomAttributesAttribute()
|
||||
{
|
||||
return $this->attributes()->get();
|
||||
return $this->custom_attributes()->get();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -44,6 +44,6 @@ class AttributeFamily extends Model
|
|||
*/
|
||||
public function getConfigurableAttributesAttribute()
|
||||
{
|
||||
return $this->attributes()->where('attributes.is_configurable', 1)->where('attributes.type', 'select')->get();
|
||||
return $this->custom_attributes()->where('attributes.is_configurable', 1)->where('attributes.type', 'select')->get();
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ class AttributeGroup extends Model
|
|||
/**
|
||||
* Get the attributes that owns the attribute group.
|
||||
*/
|
||||
public function attributes()
|
||||
public function custom_attributes()
|
||||
{
|
||||
return $this->belongsToMany(Attribute::class, 'attribute_group_mappings')
|
||||
->withPivot('position')
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class AttributeOption extends TranslatableModel
|
|||
|
||||
public $translatedAttributes = ['label'];
|
||||
|
||||
protected $fillable = ['sort_order'];
|
||||
protected $fillable = ['admin_name', 'sort_order'];
|
||||
|
||||
/**
|
||||
* Get the attribute that owns the attribute option.
|
||||
|
|
|
|||
|
|
@ -66,16 +66,16 @@ class AttributeFamilyRepository extends Repository
|
|||
$family = $this->model->create($data);
|
||||
|
||||
foreach ($attributeGroups as $group) {
|
||||
$attributes = isset($group['attributes']) ? $group['attributes'] : [];
|
||||
unset($group['attributes']);
|
||||
$custom_attributes = isset($group['custom_attributes']) ? $group['custom_attributes'] : [];
|
||||
unset($group['custom_attributes']);
|
||||
$attributeGroup = $family->attribute_groups()->create($group);
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
foreach ($custom_attributes as $attribute) {
|
||||
if(isset($attribute['id'])) {
|
||||
$attributeGroup->attributes()->attach($attribute['id']);
|
||||
$attributeGroup->custom_attributes()->attach($attribute['id']);
|
||||
} else {
|
||||
$attributeModel = $this->attribute->findBy('code', $attribute['code']);
|
||||
$attributeGroup->attributes()->save($attributeModel, ['position' => $attribute['position']]);
|
||||
$attributeGroup->custom_attributes()->save($attributeModel, ['position' => $attribute['position']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -102,9 +102,9 @@ class AttributeFamilyRepository extends Repository
|
|||
if (str_contains($attributeGroupId, 'group_')) {
|
||||
$attributeGroup = $family->attribute_groups()->create($attributeGroupInputs);
|
||||
|
||||
if(isset($attributeGroupInputs['attributes'])) {
|
||||
foreach ($attributeGroupInputs['attributes'] as $attribute) {
|
||||
$attributeGroup->attributes()->attach($attribute['id']);
|
||||
if(isset($attributeGroupInputs['custom_attributes'])) {
|
||||
foreach ($attributeGroupInputs['custom_attributes'] as $attribute) {
|
||||
$attributeGroup->custom_attributes()->attach($attribute['id']);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -115,20 +115,20 @@ class AttributeFamilyRepository extends Repository
|
|||
$attributeGroup = $this->attributeGroup->findOrFail($attributeGroupId);
|
||||
$attributeGroup->update($attributeGroupInputs);
|
||||
|
||||
$attributeIds = $attributeGroup->attributes()->get()->pluck('id');
|
||||
$attributeIds = $attributeGroup->custom_attributes()->get()->pluck('id');
|
||||
|
||||
if(isset($attributeGroupInputs['attributes'])) {
|
||||
foreach ($attributeGroupInputs['attributes'] as $attribute) {
|
||||
if(isset($attributeGroupInputs['custom_attributes'])) {
|
||||
foreach ($attributeGroupInputs['custom_attributes'] as $attribute) {
|
||||
if(is_numeric($index = $attributeIds->search($attribute['id']))) {
|
||||
$attributeIds->forget($index);
|
||||
} else {
|
||||
$attributeGroup->attributes()->attach($attribute['id']);
|
||||
$attributeGroup->custom_attributes()->attach($attribute['id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($attributeIds->count()) {
|
||||
$attributeGroup->attributes()->detach($attributeIds);
|
||||
$attributeGroup->custom_attributes()->detach($attributeIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ class AttributeRepository extends Repository
|
|||
|
||||
$previousOptionIds = $attribute->options()->pluck('id');
|
||||
|
||||
if(in_array($attribute->code, ['select', 'multiselect', 'checkbox'])) {
|
||||
if(in_array($attribute->type, ['select', 'multiselect', 'checkbox'])) {
|
||||
if(isset($data['options'])) {
|
||||
foreach ($data['options'] as $optionId => $optionInputs) {
|
||||
if (str_contains($optionId, 'option_')) {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ class CategoryController extends Controller
|
|||
public function store()
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'slug' => ['required', 'unique:category_translations,slug', new \Webkul\Core\Contracts\Validations\Slug],
|
||||
'slug' => ['required', 'unique:category_translations,slug', new \Webkul\Core\Contracts\Validations\Code],
|
||||
'name' => 'required'
|
||||
]);
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class CategoryRepository extends Repository
|
|||
if(isset($data['locale']) && $data['locale'] == 'all') {
|
||||
$model = app()->make($this->model());
|
||||
|
||||
foreach(core()->allLocales() as $locale) {
|
||||
foreach(core()->getAllLocales() as $locale) {
|
||||
foreach ($model->translatedAttributes as $attribute) {
|
||||
if(isset($data[$attribute])) {
|
||||
$data[$locale->code][$attribute] = $data[$attribute];
|
||||
|
|
|
|||
|
|
@ -6,22 +6,16 @@ use Webkul\Channel\Models\Channel as ChannelModel;
|
|||
|
||||
class Channel
|
||||
{
|
||||
public function getDefaultChannelLocaleCode() {
|
||||
public function getAllChannels() {
|
||||
return ChannelModel::all();
|
||||
}
|
||||
|
||||
public function getChannel() {
|
||||
$channel = ChannelModel::first();
|
||||
|
||||
if(!$channel || !$channel->locales()->count())
|
||||
if(!$channel)
|
||||
return;
|
||||
|
||||
return $channel->code . '-' . $channel->locales()->first()->code;
|
||||
}
|
||||
|
||||
public function getDefaultChannelLocale() {
|
||||
$channel = ChannelModel::first();
|
||||
|
||||
return $channel->locales()->first();
|
||||
}
|
||||
|
||||
public function getChannelWithLocales() {
|
||||
return ChannelModel::with('locales')->get();
|
||||
return $channel->code;
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ class Code implements Rule
|
|||
*/
|
||||
public function passes($attribute, $value)
|
||||
{
|
||||
return preg_match('/^[a-zA-Z0-9_]*$/', $value);
|
||||
return preg_match('/^[a-z]+[a-z0-9_]+$/', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use Webkul\Core\Models\Currency as CurrencyModel;
|
|||
|
||||
class Core
|
||||
{
|
||||
public function allLocales() {
|
||||
public function getAllLocales() {
|
||||
return LocaleModel::all();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -123,6 +123,28 @@ abstract class Repository implements RepositoryInterface {
|
|||
return $this->resetScope()->model->with($with)->where($attribute, '=', $value)->first($columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $conditions
|
||||
* @param array $columns
|
||||
* @return mixed
|
||||
*/
|
||||
public function findWhere($conditions, $columns = ['*'], $with = [])
|
||||
{
|
||||
$model = $this->resetScope()->model;
|
||||
|
||||
foreach ($conditions as $column => $value) {
|
||||
if(is_array($value)) {
|
||||
list($column, $condition, $val) = $value;
|
||||
$this->model = $this->model->where($column, $condition, $val);
|
||||
} else {
|
||||
$model->where($column, $value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $model->with($with)->get($columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
* @throws RepositoryException
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@ class CreateInventorySourcesTable extends Migration
|
|||
$table->string('street')->nullable();
|
||||
$table->string('postcode');
|
||||
$table->integer('priority')->default(0);
|
||||
$table->decimal('latitude', 10, 5);
|
||||
$table->decimal('longitude', 10, 5);
|
||||
$table->decimal('latitude', 10, 5)->nullable();
|
||||
$table->decimal('longitude', 10, 5)->nullable();
|
||||
$table->boolean('status')->default(0);
|
||||
$table->timestamps();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,13 +27,6 @@ class CreateProductsTable extends Migration
|
|||
$table->foreign('parent_id')->references('id')->on('products')->onDelete('cascade');
|
||||
});
|
||||
|
||||
Schema::create('product_inventories', function (Blueprint $table) {
|
||||
$table->integer('product_id')->unsigned();
|
||||
$table->integer('inventory_source_id')->unsigned();
|
||||
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
|
||||
$table->foreign('inventory_source_id')->references('id')->on('inventory_sources')->onDelete('cascade');
|
||||
});
|
||||
|
||||
Schema::create('product_categories', function (Blueprint $table) {
|
||||
$table->integer('product_id')->unsigned();
|
||||
$table->integer('category_id')->unsigned();
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ class CreateProductAttributeValuesTable extends Migration
|
|||
Schema::create('product_attribute_values', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('locale')->nullable();
|
||||
$table->string('channel')->nullable();
|
||||
$table->text('text_value')->nullable();
|
||||
$table->boolean('boolean_value')->nullable();
|
||||
$table->integer('integer_value')->nullable();
|
||||
|
|
@ -25,11 +26,9 @@ class CreateProductAttributeValuesTable extends Migration
|
|||
$table->json('json_value')->nullable();
|
||||
$table->integer('product_id')->unsigned();
|
||||
$table->integer('attribute_id')->unsigned();
|
||||
$table->integer('channel_id')->nullable()->unsigned();
|
||||
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
|
||||
$table->foreign('attribute_id')->references('id')->on('attributes')->onDelete('cascade');
|
||||
$table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade');
|
||||
$table->unique(['channel_id', 'locale', 'attribute_id', 'product_id'], 'chanel_locale_attribute_value_index_unique');
|
||||
$table->unique(['channel', 'locale', 'attribute_id', 'product_id'], 'chanel_locale_attribute_value_index_unique');
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateProductInventoriesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('product_inventories', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('qty')->default(0);
|
||||
$table->integer('product_id')->unsigned();
|
||||
$table->integer('inventory_source_id')->unsigned();
|
||||
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
|
||||
$table->foreign('inventory_source_id')->references('id')->on('inventory_sources')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('product_inventories');
|
||||
}
|
||||
}
|
||||
|
|
@ -4,8 +4,11 @@ namespace Webkul\Product\Http\Controllers;
|
|||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Webkul\Product\Http\Requests\ProductForm;
|
||||
use Webkul\Product\Repositories\ProductRepository as Product;
|
||||
use Webkul\Attribute\Repositories\AttributeFamilyRepository as AttributeFamily;
|
||||
use Webkul\Category\Repositories\CategoryRepository as Category;
|
||||
use Webkul\Inventory\Repositories\InventorySourceRepository as InventorySource;
|
||||
|
||||
/**
|
||||
* Product controller
|
||||
|
|
@ -29,6 +32,20 @@ class ProductController extends Controller
|
|||
*/
|
||||
protected $attributeFamily;
|
||||
|
||||
/**
|
||||
* CategoryRepository object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $category;
|
||||
|
||||
/**
|
||||
* InventorySourceRepository object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $inventorySource;
|
||||
|
||||
/**
|
||||
* ProductRepository object
|
||||
*
|
||||
|
|
@ -40,13 +57,23 @@ class ProductController extends Controller
|
|||
* Create a new controller instance.
|
||||
*
|
||||
* @param Webkul\Attribute\Repositories\AttributeFamilyRepository $attributeFamily
|
||||
* @param Webkul\Category\Repositories\CategoryRepository $category
|
||||
* @param Webkul\Inventory\Repositories\InventorySourceRepository $inventorySource
|
||||
* @param Webkul\Product\Repositories\ProductRepository $product
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(AttributeFamily $attributeFamily, Product $product)
|
||||
public function __construct(
|
||||
AttributeFamily $attributeFamily,
|
||||
Category $category,
|
||||
InventorySource $inventorySource,
|
||||
Product $product)
|
||||
{
|
||||
$this->attributeFamily = $attributeFamily;
|
||||
|
||||
$this->category = $category;
|
||||
|
||||
$this->inventorySource = $inventorySource;
|
||||
|
||||
$this->product = $product;
|
||||
|
||||
$this->_config = request('_config');
|
||||
|
|
@ -98,7 +125,7 @@ class ProductController extends Controller
|
|||
$this->validate(request(), [
|
||||
'type' => 'required',
|
||||
'attribute_family_id' => 'required',
|
||||
'sku' => ['required', 'unique:products,sku', new \Webkul\Core\Contracts\Validations\Slug]
|
||||
'sku' => ['required', 'unique:products,sku', new \Webkul\Core\Contracts\Validations\Code]
|
||||
]);
|
||||
|
||||
$product = $this->product->create(request()->all());
|
||||
|
|
@ -118,22 +145,24 @@ class ProductController extends Controller
|
|||
{
|
||||
$product = $this->product->findOrFail($id);
|
||||
|
||||
return view($this->_config['view'], compact('product'));
|
||||
$categories = $this->category->getCategoryTree();
|
||||
|
||||
$inventorySources = $this->inventorySource->all();
|
||||
|
||||
return view($this->_config['view'], compact('product', 'categories', 'inventorySources'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Webkul\Product\Http\Requests\ProductForm $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
public function update(ProductForm $request, $id)
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'name' => 'required',
|
||||
]);
|
||||
|
||||
dd(request()->all());
|
||||
|
||||
$this->product->update(request()->all(), $id);
|
||||
|
||||
session()->flash('success', 'Product updated successfully.');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Webkul\Attribute\Repositories\AttributeFamilyRepository as AttributeFamily;
|
||||
use Webkul\Product\Repositories\ProductRepository as Product;
|
||||
use Webkul\Product\Repositories\ProductAttributeValueRepository as AttributeValue;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
|
||||
class ProductForm extends FormRequest
|
||||
{
|
||||
/**
|
||||
* AttributeFamilyRepository object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributeFamily;
|
||||
|
||||
/**
|
||||
* ProductRepository object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $product;
|
||||
|
||||
/**
|
||||
* ProductAttributeValueRepository object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributeValue;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @param Webkul\Attribute\Repositories\AttributeFamilyRepository $attributeFamily
|
||||
* @param Webkul\Product\Repositories\ProductRepository $product
|
||||
* @param Webkul\Product\Repositories\ProductAttributeValueRepository $attributeValue
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(AttributeFamily $attributeFamily, Product $product, AttributeValue $attributeValue)
|
||||
{
|
||||
$this->attributeFamily = $attributeFamily;
|
||||
|
||||
$this->product = $product;
|
||||
|
||||
$this->attributeValue = $attributeValue;
|
||||
}
|
||||
|
||||
protected $rules;
|
||||
|
||||
/**
|
||||
* Determine if the product is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
$this->rules = [
|
||||
'sku' => ['required', 'unique:products,sku,' . $this->id, new \Webkul\Core\Contracts\Validations\Slug],
|
||||
'variants.*.name' => 'required',
|
||||
'variants.*.sku' => 'required',
|
||||
'variants.*.price' => 'required',
|
||||
'variants.*.weight' => 'required',
|
||||
];
|
||||
|
||||
$inputs = $this->all();
|
||||
|
||||
$product = $this->product->find($this->id);
|
||||
|
||||
$attributes = $product->attribute_family->custom_attributes;
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
if($attribute->code == 'sku')
|
||||
continue;
|
||||
|
||||
if($product->type == 'configurable' && in_array($attribute->code, ['price', 'cost', 'special_price', 'special_price_from', 'special_price_to', 'width', 'height', 'depth', 'weight']))
|
||||
continue;
|
||||
|
||||
$validations = [];
|
||||
if($attribute->is_required) {
|
||||
array_push($validations, 'required');
|
||||
} else {
|
||||
array_push($validations, 'nullable');
|
||||
}
|
||||
|
||||
if($attribute->type == 'text' && $attribute->validation) {
|
||||
array_push($validations, $attribute->validation);
|
||||
}
|
||||
|
||||
if($attribute->is_unique) {
|
||||
array_push($validations, function ($field, $value, $fail) use ($inputs, $attribute) {
|
||||
$column = ProductAttributeValue::$attributeTypeFields[$attribute->type];
|
||||
|
||||
if (!$this->attributeValue->isValueUnique($this->id, $attribute->id, $column, $inputs[$attribute->code])) {
|
||||
$fail('The :attribute has already been taken.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$this->rules[$attribute->code] = $validations;
|
||||
}
|
||||
|
||||
return $this->rules;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,27 +7,15 @@ use Webkul\Attribute\Models\AttributeFamily;
|
|||
use Webkul\Category\Models\Category;
|
||||
use Webkul\Attribute\Models\Attribute;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
use Webkul\Product\Models\ProductInventory;
|
||||
use Webkul\Product\Models\ProductImage;
|
||||
use Webkul\Inventory\Models\InventorySource;
|
||||
|
||||
class Product extends Model
|
||||
{
|
||||
protected $fillable = ['type', 'attribute_family_id', 'sku', 'parent_id'];
|
||||
|
||||
protected $with = ['attribute_values', 'varients'];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $attributeTypeFields = [
|
||||
'text' => 'text_value',
|
||||
'textarea' => 'text_value',
|
||||
'price' => 'float_value',
|
||||
'boolean' => 'boolean_value',
|
||||
'select' => 'integer_value',
|
||||
'multiselect' => 'text_value',
|
||||
'datetime' => 'datetime_time',
|
||||
'date' => 'date_value',
|
||||
];
|
||||
protected $with = ['attribute_family', 'attribute_values', 'variants', 'inventories'];
|
||||
|
||||
/**
|
||||
* Get the product attribute family that owns the product.
|
||||
|
|
@ -46,13 +34,21 @@ class Product extends Model
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the product varients that owns the product.
|
||||
* Get the product variants that owns the product.
|
||||
*/
|
||||
public function varients()
|
||||
public function variants()
|
||||
{
|
||||
return $this->hasMany(self::class, 'parent_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product that owns the product.
|
||||
*/
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo(self::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* The categories that belong to the product.
|
||||
*/
|
||||
|
|
@ -66,7 +62,15 @@ class Product extends Model
|
|||
*/
|
||||
public function inventories()
|
||||
{
|
||||
return $this->belongsToMany(InventorySource::class, 'product_inventories');
|
||||
return $this->hasMany(ProductInventory::class, 'product_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* The inventory sources that belong to the product.
|
||||
*/
|
||||
public function inventory_sources()
|
||||
{
|
||||
return $this->belongsToMany(InventorySource::class, 'product_inventories')->withPivot('id', 'qty');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -77,6 +81,14 @@ class Product extends Model
|
|||
return $this->belongsToMany(Attribute::class, 'product_super_attributes');
|
||||
}
|
||||
|
||||
/**
|
||||
* The images that belong to the product.
|
||||
*/
|
||||
public function images()
|
||||
{
|
||||
return $this->hasMany(ProductImage::class, 'product_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* The related products that belong to the product.
|
||||
*/
|
||||
|
|
@ -100,6 +112,64 @@ class Product extends Model
|
|||
{
|
||||
return $this->belongsToMany(self::class, 'product_cross_sells');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isCustomAttribute($attribute)
|
||||
{
|
||||
return $this->attribute_family->custom_attributes->pluck('code')->contains($attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an attribute from the model.
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function getAttribute($key)
|
||||
{
|
||||
if (!method_exists(self::class, $key) && !isset($this->attributes[$key])) {
|
||||
if ($this->isCustomAttribute($key)) {
|
||||
$attributeModel = $this->attribute_family->custom_attributes()->where('attributes.code', $key)->first();
|
||||
|
||||
if($attributeModel) {
|
||||
if($attributeModel->value_per_channel) {
|
||||
$channel = request()->get('channel') ?: channel()->getChannel();
|
||||
if($attributeModel->value_per_locale) {
|
||||
$locale = request()->get('locale') ?: app()->getLocale();
|
||||
$attributeValue = $this->attribute_values()->where('channel', $channel)->where('locale', $locale)->where('attribute_id', $attributeModel->id)->first();
|
||||
} else {
|
||||
$attributeValue = $this->attribute_values()->where('channel', $channel)->where('attribute_id', $attributeModel->id)->first();
|
||||
}
|
||||
} else {
|
||||
if($attributeModel->value_per_locale) {
|
||||
$locale = request()->get('locale') ?: app()->getLocale();
|
||||
$attributeValue = $this->attribute_values()->where('locale', $locale)->where('attribute_id', $attributeModel->id)->first();
|
||||
} else {
|
||||
$attributeValue = $this->attribute_values()->where('attribute_id', $attributeModel->id)->first();
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->hasGetMutator($key)) {
|
||||
$this->attributes[$key] = $attributeValue[ProductAttributeValue::$attributeTypeFields[$attributeModel->type]];
|
||||
|
||||
return $this->getAttributeValue($key);
|
||||
}
|
||||
|
||||
return $attributeValue[ProductAttributeValue::$attributeTypeFields[$attributeModel->type]];
|
||||
}
|
||||
|
||||
return $this->getAttributeValue($key);
|
||||
}
|
||||
|
||||
return $this->getAttributeValue($key);
|
||||
}
|
||||
|
||||
return parent::getAttribute($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
|
|
@ -110,15 +180,29 @@ class Product extends Model
|
|||
|
||||
$hiddenAttributes = $this->getHidden();
|
||||
|
||||
foreach ($this->attribute_values as $attributeValue) {
|
||||
|
||||
$attribute = $attributeValue->attribute;
|
||||
|
||||
foreach ($this->attribute_family->custom_attributes as $attribute) {
|
||||
if (in_array($attribute->code, $hiddenAttributes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($value = $attributeValue[$this->attributeTypeFields[$attribute->type]]) {
|
||||
if($attribute->value_per_channel) {
|
||||
$channel = request()->get('channel') ?: channel()->getChannel();
|
||||
if($attribute->value_per_locale) {
|
||||
$locale = request()->get('locale') ?: app()->getLocale();
|
||||
$attributeValue = $this->attribute_values()->where('channel', $channel)->where('locale', $locale)->where('attribute_id', $attribute->id)->first();
|
||||
} else {
|
||||
$attributeValue = $this->attribute_values()->where('channel', $channel)->where('attribute_id', $attribute->id)->first();
|
||||
}
|
||||
} else {
|
||||
if($attribute->value_per_locale) {
|
||||
$locale = request()->get('locale') ?: app()->getLocale();
|
||||
$attributeValue = $this->attribute_values()->where('locale', $locale)->where('attribute_id', $attribute->id)->first();
|
||||
} else {
|
||||
$attributeValue = $this->attribute_values()->where('attribute_id', $attribute->id)->first();
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($value = $attributeValue[ProductAttributeValue::$attributeTypeFields[$attribute->type]])) {
|
||||
$attributes[$attribute->code] = $value;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,11 +13,26 @@ class ProductAttributeValue extends Model
|
|||
|
||||
protected $with = ['attribute'];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public static $attributeTypeFields = [
|
||||
'text' => 'text_value',
|
||||
'textarea' => 'text_value',
|
||||
'price' => 'float_value',
|
||||
'boolean' => 'boolean_value',
|
||||
'select' => 'integer_value',
|
||||
'multiselect' => 'text_value',
|
||||
'datetime' => 'datetime_time',
|
||||
'date' => 'date_value',
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'product_id',
|
||||
'attribute_id',
|
||||
'channel_id',
|
||||
'locale',
|
||||
'channel',
|
||||
'text_value',
|
||||
'boolean_value',
|
||||
'integer_value',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Product\Models\Product;
|
||||
|
||||
class ProductImage extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = [];
|
||||
|
||||
/**
|
||||
* Get the product that owns the image.
|
||||
*/
|
||||
public function product()
|
||||
{
|
||||
return $this->belongsTo(Product::class);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ProductInventory extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $fillable = ['qty', 'product_id', 'inventory_source_id'];
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ namespace Webkul\Product\Repositories;
|
|||
use Illuminate\Container\Container as App;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
|
||||
/**
|
||||
* Product Attribute Value Reposotory
|
||||
|
|
@ -21,20 +22,6 @@ class ProductAttributeValueRepository extends Repository
|
|||
*/
|
||||
protected $attribute;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $attributeTypeFields = [
|
||||
'text' => 'text_value',
|
||||
'textarea' => 'text_value',
|
||||
'price' => 'float_value',
|
||||
'boolean' => 'boolean_value',
|
||||
'select' => 'integer_value',
|
||||
'multiselect' => 'text_value',
|
||||
'datetime' => 'datetime_time',
|
||||
'date' => 'date_value',
|
||||
];
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
|
|
@ -64,10 +51,31 @@ class ProductAttributeValueRepository extends Repository
|
|||
*/
|
||||
public function create(array $data)
|
||||
{
|
||||
$attribute = $this->attribute->find($data['attribute_id']);
|
||||
if(isset($data['attribute_id'])) {
|
||||
$attribute = $this->attribute->find($data['attribute_id']);
|
||||
} else {
|
||||
$attribute = $this->attribute->findBy('code', $data['attribute_code']);
|
||||
}
|
||||
|
||||
$data[$this->attributeTypeFields[$attribute->type]] = $data['value'];
|
||||
if(!$attribute)
|
||||
return;
|
||||
|
||||
$data[ProductAttributeValue::$attributeTypeFields[$attribute->type]] = $data['value'];
|
||||
|
||||
return $this->model->create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
* @param int $attributeId
|
||||
* @param int $productId
|
||||
* @param string $value
|
||||
* @return boolean
|
||||
*/
|
||||
public function isValueUnique($productId, $attributeId, $column, $value)
|
||||
{
|
||||
$result = $this->resetScope()->model->where($column, $value)->where('attribute_id', '!=', $attributeId)->where('product_id', '!=', $productId)->get();
|
||||
|
||||
return $result->count() ? false : true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace Webkul\Product\Repositories;
|
||||
|
||||
use Illuminate\Container\Container as App;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
/**
|
||||
* Product Inventory Reposotory
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
*/
|
||||
class ProductInventoryRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function model()
|
||||
{
|
||||
return 'Webkul\Product\Models\ProductInventory';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $inventories
|
||||
* @param mixed $product
|
||||
* @return mixed
|
||||
*/
|
||||
public function saveInventories(array $data, $product)
|
||||
{
|
||||
$inventorySourceIds = $product->inventory_sources->pluck('id');
|
||||
|
||||
if(isset($data['inventories'])) {
|
||||
foreach($data['inventories'] as $inventorySourceId => $qty) {
|
||||
if(is_null($qty))
|
||||
continue;
|
||||
|
||||
$productInventory = $this->findWhere([
|
||||
'product_id' => $product->id,
|
||||
'inventory_source_id' => $inventorySourceId,
|
||||
])->first();
|
||||
|
||||
if($productInventory) {
|
||||
if(is_numeric($index = $inventorySourceIds->search($inventorySourceId))) {
|
||||
$inventorySourceIds->forget($index);
|
||||
}
|
||||
|
||||
$this->update(['qty' => $qty], $productInventory->id);
|
||||
} else {
|
||||
$this->create([
|
||||
'qty' => $qty,
|
||||
'product_id' => $product->id,
|
||||
'inventory_source_id' => $inventorySourceId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($inventorySourceIds->count()) {
|
||||
$product->inventory_sources()->detach($inventorySourceIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,10 +5,13 @@ namespace Webkul\Product\Repositories;
|
|||
use Illuminate\Container\Container as App;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Attribute\Repositories\AttributeOptionRepository;
|
||||
use Webkul\Product\Repositories\ProductAttributeValueRepository;
|
||||
use Webkul\Product\Repositories\ProductInventoryRepository;
|
||||
use Webkul\Product\Models\ProductAttributeValue;
|
||||
|
||||
/**
|
||||
* Product Reposotory
|
||||
* Product Repository
|
||||
*
|
||||
* @author Jitendra Singh <jitendra@webkul.com>
|
||||
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
|
||||
|
|
@ -22,6 +25,13 @@ class ProductRepository extends Repository
|
|||
*/
|
||||
protected $attribute;
|
||||
|
||||
/**
|
||||
* AttributeOptionRepository object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attributeOption;
|
||||
|
||||
/**
|
||||
* ProductAttributeValueRepository object
|
||||
*
|
||||
|
|
@ -29,22 +39,37 @@ class ProductRepository extends Repository
|
|||
*/
|
||||
protected $attributeValue;
|
||||
|
||||
/**
|
||||
* ProductInventoryRepository object
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $productInventory;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @param Webkul\Attribute\Repositories\AttributeRepository $attribute
|
||||
* @param Webkul\Attribute\Repositories\ProductAttributeValueRepository $attributeValue
|
||||
* @param Webkul\Attribute\Repositories\AttributeRepository $attribute
|
||||
* @param Webkul\Attribute\Repositories\AttributeOptionRepository $attributeOption
|
||||
* @param Webkul\Product\Repositories\ProductAttributeValueRepository $attributeValue
|
||||
* @param Webkul\Product\Repositories\ProductInventoryRepository $productInventory
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
AttributeRepository $attribute,
|
||||
AttributeOptionRepository $attributeOption,
|
||||
ProductAttributeValueRepository $attributeValue,
|
||||
ProductInventoryRepository $productInventory,
|
||||
App $app)
|
||||
{
|
||||
$this->attribute = $attribute;
|
||||
|
||||
$this->attributeOption = $attributeOption;
|
||||
|
||||
$this->attributeValue = $attributeValue;
|
||||
|
||||
$this->productInventory = $productInventory;
|
||||
|
||||
parent::__construct($app);
|
||||
}
|
||||
|
||||
|
|
@ -66,6 +91,13 @@ class ProductRepository extends Repository
|
|||
{
|
||||
$product = $this->model->create($data);
|
||||
|
||||
$nameAttribute = $this->attribute->findBy('code', 'status');
|
||||
$this->attributeValue->create([
|
||||
'product_id' => $product->id,
|
||||
'attribute_id' => $nameAttribute->id,
|
||||
'value' => 1
|
||||
]);
|
||||
|
||||
if(isset($data['super_attributes'])) {
|
||||
|
||||
$super_attributes = [];
|
||||
|
|
@ -79,7 +111,7 @@ class ProductRepository extends Repository
|
|||
}
|
||||
|
||||
foreach (array_permutation($super_attributes) as $permutation) {
|
||||
$this->createVarient($product, $permutation);
|
||||
$this->createVariant($product, $permutation);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -88,25 +120,228 @@ class ProductRepository extends Repository
|
|||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param $id
|
||||
* @param string $attribute
|
||||
* @return mixed
|
||||
*/
|
||||
public function createVarient($product, $permutation)
|
||||
public function update(array $data, $id, $attribute = "id")
|
||||
{
|
||||
$varient = $this->model->create([
|
||||
$product = $this->findOrFail($id);
|
||||
|
||||
if($product->parent_id && $this->checkVariantOptionAvailabiliy($data, $product)) {
|
||||
$data['parent_id'] = null;
|
||||
}
|
||||
|
||||
$product->update($data);
|
||||
|
||||
if(isset($data['categories']))
|
||||
$product->categories()->sync($data['categories']);
|
||||
|
||||
$attributes = $product->attribute_family->custom_attributes;
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
if(!isset($data[$attribute->code]) || !$data[$attribute->code])
|
||||
continue;
|
||||
|
||||
$attributeValue = $this->attributeValue->findWhere([
|
||||
'product_id' => $product->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'channel' => $attribute->value_per_channel ? $data['channel'] : null,
|
||||
'locale' => $attribute->value_per_locale ? $data['locale'] : null
|
||||
])->first();
|
||||
|
||||
if(!$attributeValue) {
|
||||
$this->attributeValue->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->attributeValue->update([
|
||||
ProductAttributeValue::$attributeTypeFields[$attribute->type] => $data[$attribute->code]
|
||||
], $attributeValue->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 {
|
||||
$variantData['channel'] = $data['channel'];
|
||||
$variantData['locale'] = $data['locale'];
|
||||
$this->updateVariant($variantData, $variantId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->productInventory->saveInventories($data, $product);
|
||||
|
||||
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->model->create([
|
||||
'parent_id' => $product->id,
|
||||
'type' => 'simple',
|
||||
'attribute_family_id' => $product->attribute_family_id,
|
||||
'sku' => $product->sku . '-varient-' . implode('-', $permutation),
|
||||
'sku' => $data['sku'],
|
||||
]);
|
||||
|
||||
foreach (['sku', 'name', 'price', 'weight', 'status'] as $attributeCode) {
|
||||
$attribute = $this->attribute->findBy('code', $attributeCode);
|
||||
|
||||
if($attribute->value_per_channel) {
|
||||
if($attribute->value_per_locale) {
|
||||
foreach(channel()->getAllChannels() as $channel) {
|
||||
foreach(core()->getAllLocales() as $locale) {
|
||||
$this->attributeValue->create([
|
||||
'product_id' => $variant->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'channel' => $channel->code,
|
||||
'locale' => $locale->code,
|
||||
'value' => $data[$attributeCode]
|
||||
]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach(channel()->getAllChannels() as $channel) {
|
||||
$this->attributeValue->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->attributeValue->create([
|
||||
'product_id' => $variant->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'locale' => $locale->code,
|
||||
'value' => $data[$attributeCode]
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
$this->attributeValue->create([
|
||||
'product_id' => $variant->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'value' => $data[$attributeCode]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach($permutation as $attributeId => $optionId) {
|
||||
$this->attributeValue->create([
|
||||
'product_id' => $varient->id,
|
||||
'product_id' => $variant->id,
|
||||
'attribute_id' => $attributeId,
|
||||
'value' => $optionId
|
||||
]);
|
||||
}
|
||||
|
||||
return $varient;
|
||||
$this->productInventory->saveInventories($data, $variant);
|
||||
|
||||
return $variant;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param $id
|
||||
* @return mixed
|
||||
*/
|
||||
public function updateVariant(array $data, $id)
|
||||
{
|
||||
$variant = $this->findOrFail($id);
|
||||
|
||||
$variant->update(['sku' => $data['sku']]);
|
||||
|
||||
foreach (['sku', 'name', 'price', 'weight', 'status'] as $attributeCode) {
|
||||
$attribute = $this->attribute->findBy('code', $attributeCode);
|
||||
|
||||
$attributeValue = $this->attributeValue->findWhere([
|
||||
'product_id' => $id,
|
||||
'attribute_id' => $attribute->id,
|
||||
'channel' => $attribute->value_per_channel ? $data['channel'] : null,
|
||||
'locale' => $attribute->value_per_locale ? $data['locale'] : null
|
||||
])->first();
|
||||
|
||||
if(!$attributeValue) {
|
||||
$this->attributeValue->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->attributeValue->update([
|
||||
ProductAttributeValue::$attributeTypeFields[$attribute->type] => $data[$attribute->code]
|
||||
], $attributeValue->id);
|
||||
}
|
||||
}
|
||||
|
||||
$this->productInventory->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($data[$attributeCode] == $variant->{$attributeCode})
|
||||
$matchCount++;
|
||||
}
|
||||
|
||||
if($matchCount == $superAttributeCodes->count()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,3 +6,7 @@ Vue.component("tree-item", require("./components/tree-view/tree-item"));
|
|||
Vue.component("tree-checkbox", require("./components/tree-view/tree-checkbox"));
|
||||
Vue.component("tree-radio", require("./components/tree-view/tree-radio"));
|
||||
Vue.component("modal", require("./components/modal"));
|
||||
Vue.component("image-wrapper", require("./components/image/image-wrapper"));
|
||||
Vue.component("image-item", require("./components/image/image-item"));
|
||||
Vue.directive("slugify", require("./directives/slugify"));
|
||||
Vue.directive("code", require("./directives/code"));
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
active: Boolean
|
||||
},
|
||||
|
||||
inject: ['$validator'],
|
||||
|
||||
data: function() {
|
||||
return {
|
||||
isActive: false
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
<template>
|
||||
<div>
|
||||
<input type="file" :name="finalInputName" ref="imageInput"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
inputName: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'attachments'
|
||||
},
|
||||
|
||||
multiple: {
|
||||
type: [Boolean, String],
|
||||
required: false,
|
||||
default: true
|
||||
},
|
||||
|
||||
image: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
if(!this.image.id) {
|
||||
var element = this.$refs.imageInput;
|
||||
element.dispatchEvent(new Event("click"));
|
||||
element.click();
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
finalInputName () {
|
||||
if(this.multiple)
|
||||
return this.inputName + '[]';
|
||||
|
||||
return this.inputName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="image-wrapper">
|
||||
<image-item v-for='(image, index) in images' :key='image.uid' :image="image" :input-name="inputName" :multiple="multiple" @onRemoveImage="removImage($event)"></image-item>
|
||||
</div>
|
||||
|
||||
<label class="btn btn-lg btn-primary" style="display: inline-block" @click="createFileType">{{ buttonLabel }}</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
buttonLabel: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'Add Image'
|
||||
},
|
||||
|
||||
inputName: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'attachments'
|
||||
},
|
||||
|
||||
multiple: {
|
||||
type: [Boolean, String],
|
||||
required: false,
|
||||
default: true
|
||||
},
|
||||
|
||||
images: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => ([])
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
createFileType () {
|
||||
this.images.push({});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<span class="checkbox">
|
||||
<input type="checkbox" :id="id" :name="[nameField, '[]']" :value="modelValue" @change="inputChanged()" :checked="isActive">
|
||||
<input type="checkbox" :id="id" :name="[nameField + '[]']" :value="modelValue" @change="inputChanged()" :checked="isActive">
|
||||
<label class="checkbox-view" :for="id"></label>
|
||||
<span class="" :for="id">{{ label }}</span>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -30,6 +30,12 @@
|
|||
default: null
|
||||
},
|
||||
|
||||
behavior: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'reactive'
|
||||
},
|
||||
|
||||
savedValues: {
|
||||
type: Array,
|
||||
required: false,
|
||||
|
|
@ -104,45 +110,58 @@
|
|||
|
||||
generateRoot () {
|
||||
if(this.inputType == 'checkbox') {
|
||||
return this.$createElement('tree-checkbox', {
|
||||
props: {
|
||||
id: this.items[this.idField],
|
||||
label: this.caption,
|
||||
nameField: this.nameField,
|
||||
modelValue: this.items[this.valueField],
|
||||
inputValue: this.hasChildren ? this.isSomeChildrenSelected : this.value,
|
||||
value: this.hasChildren ? this.isAllChildrenSelected : this.items
|
||||
},
|
||||
on: {
|
||||
change: selection => {
|
||||
if(this.hasChildren) {
|
||||
if(this.isAllChildrenSelected) {
|
||||
this.allChildren.forEach(leaf => {
|
||||
let index = this.value.indexOf(leaf)
|
||||
this.value.splice(index, 1)
|
||||
})
|
||||
} else {
|
||||
this.allChildren.forEach(leaf => {
|
||||
let exists = false;
|
||||
this.value.forEach(item => {
|
||||
if(item['key'] == leaf['key']) {
|
||||
exists = true;
|
||||
if(this.behavior == 'reactive') {
|
||||
return this.$createElement('tree-checkbox', {
|
||||
props: {
|
||||
id: this.items[this.idField],
|
||||
label: this.caption,
|
||||
nameField: this.nameField,
|
||||
modelValue: this.items[this.valueField],
|
||||
inputValue: this.hasChildren ? this.isSomeChildrenSelected : this.value,
|
||||
value: this.hasChildren ? this.isAllChildrenSelected : this.items
|
||||
},
|
||||
on: {
|
||||
change: selection => {
|
||||
if(this.hasChildren) {
|
||||
if(this.isAllChildrenSelected) {
|
||||
this.allChildren.forEach(leaf => {
|
||||
let index = this.value.indexOf(leaf)
|
||||
this.value.splice(index, 1)
|
||||
})
|
||||
} else {
|
||||
this.allChildren.forEach(leaf => {
|
||||
let exists = false;
|
||||
this.value.forEach(item => {
|
||||
if(item['key'] == leaf['key']) {
|
||||
exists = true;
|
||||
}
|
||||
})
|
||||
|
||||
if(!exists) {
|
||||
this.value.push(leaf);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if(!exists) {
|
||||
this.value.push(leaf);
|
||||
}
|
||||
})
|
||||
this.$emit('input', this.value)
|
||||
} else {
|
||||
this.$emit('input', selection);
|
||||
}
|
||||
|
||||
this.$emit('input', this.value)
|
||||
} else {
|
||||
this.$emit('input', selection);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
return this.$createElement('tree-checkbox', {
|
||||
props: {
|
||||
id: this.items[this.idField],
|
||||
label: this.caption,
|
||||
nameField: this.nameField,
|
||||
modelValue: this.items[this.valueField],
|
||||
inputValue: this.value,
|
||||
value: this.items
|
||||
}
|
||||
})
|
||||
}
|
||||
} else if(this.inputType == 'radio') {
|
||||
return this.$createElement('tree-radio', {
|
||||
props: {
|
||||
|
|
@ -172,7 +191,8 @@
|
|||
captionField: this.captionField,
|
||||
childrenField: this.childrenField,
|
||||
valueField: this.valueField,
|
||||
idField: this.idField
|
||||
idField: this.idField,
|
||||
behavior: this.behavior
|
||||
}
|
||||
})
|
||||
},
|
||||
|
|
|
|||
|
|
@ -48,6 +48,12 @@
|
|||
default: () => ([])
|
||||
},
|
||||
|
||||
behavior: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: 'reactive'
|
||||
},
|
||||
|
||||
value: {
|
||||
type: [Array, String, Object],
|
||||
required: false,
|
||||
|
|
@ -96,7 +102,8 @@
|
|||
captionField: this.captionField,
|
||||
childrenField: this.childrenField,
|
||||
valueField: this.valueField,
|
||||
idField: this.idField
|
||||
idField: this.idField,
|
||||
behavior: this.behavior
|
||||
},
|
||||
on: {
|
||||
input: selection => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
<script>
|
||||
export default {
|
||||
bind(el, binding, vnode) {
|
||||
let handler = function(e) {
|
||||
setTimeout(function(){
|
||||
e.target.value = e.target.value.toString().toLowerCase()
|
||||
.replace(/[^\w ]+/g,'')
|
||||
.trim()
|
||||
.replace(/ +/g,'-');
|
||||
}, 100);
|
||||
}
|
||||
|
||||
el.addEventListener('input', handler);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<script>
|
||||
export default {
|
||||
bind(el, binding, vnode) {
|
||||
let handler = function(e) {
|
||||
setTimeout(function(){
|
||||
e.target.value = e.target.value.toString().toLowerCase()
|
||||
.replace(/[^\w- ]+/g,'')
|
||||
.trim()
|
||||
.replace(/ +/g,'-');
|
||||
}, 100);
|
||||
}
|
||||
|
||||
el.addEventListener('input', handler);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
$font-color: #3a3a3a;
|
||||
$brand-color: #0041FF;
|
||||
$danger-color: #FC6868;
|
||||
$success-color: #4CAF50;
|
||||
|
|
|
|||
|
|
@ -32,13 +32,13 @@ ul {
|
|||
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
color: #3a3a3a;
|
||||
color: $font-color;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 18px;
|
||||
color: #3a3a3a;
|
||||
color: $font-color;
|
||||
}
|
||||
|
||||
.hide {
|
||||
|
|
@ -168,6 +168,7 @@ h2 {
|
|||
padding: 0px;
|
||||
|
||||
li {
|
||||
padding: 5px 0px;
|
||||
// &:hover {
|
||||
// color: $brand-color;
|
||||
// }
|
||||
|
|
@ -186,6 +187,14 @@ h2 {
|
|||
.checkbox {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.control-group label {
|
||||
color: $font-color;
|
||||
font-size: 15px;
|
||||
font-weight: 500;
|
||||
text-transform: capitalize;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -209,13 +218,13 @@ h2 {
|
|||
font-weight: 700;
|
||||
padding: 12px 10px;
|
||||
background: #f8f9fa;
|
||||
color: #3a3a3a;
|
||||
color: $font-color;
|
||||
}
|
||||
|
||||
tbody td {
|
||||
padding: 12px 10px;
|
||||
border-bottom: solid 1px #d3d3d3;
|
||||
color: #3a3a3a;
|
||||
color: $font-color;
|
||||
vertical-align: top;
|
||||
|
||||
&.actions {
|
||||
|
|
@ -227,6 +236,10 @@ h2 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
tbody tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.control-group {
|
||||
|
|
@ -247,7 +260,6 @@ h2 {
|
|||
border: 2px solid $control-border-color;
|
||||
@include border-radius(3px);
|
||||
font-size: 14px;
|
||||
color: #8e8e8e;
|
||||
padding: 8px 35px 8px 10px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
|
@ -376,7 +388,14 @@ h2 {
|
|||
|
||||
label {
|
||||
display: block;
|
||||
color: #3a3a3a;
|
||||
color: $font-color;
|
||||
|
||||
&.required::after {
|
||||
content: "*";
|
||||
color: $danger-color;
|
||||
font-weight: 700;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
textarea.control {
|
||||
|
|
@ -511,7 +530,7 @@ h2 {
|
|||
.accordian {
|
||||
.accordian-header {
|
||||
font-size: 18px;
|
||||
color: #3a3a3a;
|
||||
color: $font-color;
|
||||
border-bottom: solid 1px $border-color;
|
||||
padding: 20px 15px;
|
||||
cursor: pointer;
|
||||
|
|
@ -913,7 +932,7 @@ h2 {
|
|||
h3 {
|
||||
display: inline-block;
|
||||
font-size: 20px;
|
||||
color: #3a3a3a;
|
||||
color: $font-color;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -175,13 +175,13 @@
|
|||
background-image: url("../images/Icon-Configure-Active.svg");
|
||||
}
|
||||
|
||||
.arrow-down-icon {
|
||||
> .arrow-down-icon {
|
||||
background-image: url("../images/Arrow-Down.svg");
|
||||
width: 14px;
|
||||
height: 8px;
|
||||
}
|
||||
|
||||
.expand-icon {
|
||||
> .expand-icon {
|
||||
background-image: url("../images/Expand-Light-On.svg");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,10 +49,6 @@ class UserServiceProvider extends ServiceProvider
|
|||
public function register()
|
||||
{
|
||||
$this->registerBouncer();
|
||||
|
||||
Event::listen('admin.acl.build', function ($acl) {
|
||||
$acl->add('settings.users.roles1', 'Roles1', 'admin.roles.index1', 3);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue