reslove conflicts

This commit is contained in:
Deepak Singh Gusain 2022-02-04 09:50:55 +05:30
commit fe6fa7bc7a
87 changed files with 3404 additions and 2025 deletions

View File

@ -1,6 +1,9 @@
<?php
return [
/**
* General.
*/
[
'key' => 'general',
'name' => 'admin::app.admin.system.general',
@ -27,7 +30,7 @@ return [
'value' => 'kgs',
],
],
'channel_based' => true
'channel_based' => true,
],
],
], [
@ -70,7 +73,7 @@ return [
'type' => 'textarea',
'channel_based' => true,
'locale_based' => false,
]
],
],
], [
'key' => 'general.design',
@ -95,7 +98,12 @@ return [
'validation' => 'mimes:bmp,jpeg,jpg,png,webp',
],
],
], [
],
/**
* Catalog.
*/
[
'key' => 'catalog',
'name' => 'admin::app.admin.system.catalog',
'sort' => 2,
@ -120,16 +128,16 @@ return [
'sort' => 2,
'fields' => [
[
'name' => 'no_of_new_product_homepage',
'title' => 'admin::app.admin.system.allow-no-of-new-product-homepage',
'type' => 'number',
'validation' => 'min:0',
'name' => 'no_of_new_product_homepage',
'title' => 'admin::app.admin.system.allow-no-of-new-product-homepage',
'type' => 'number',
'validation' => 'min:0',
],
[
'name' => 'no_of_featured_product_homepage',
'title' => 'admin::app.admin.system.allow-no-of-featured-product-homepage',
'type' => 'number',
'validation' => 'min:0',
'name' => 'no_of_featured_product_homepage',
'title' => 'admin::app.admin.system.allow-no-of-featured-product-homepage',
'type' => 'number',
'validation' => 'min:0',
],
[
'name' => 'out_of_stock_items',
@ -192,7 +200,7 @@ return [
'name' => 'buy_now_button_display',
'title' => 'admin::app.admin.system.buy-now-button-display',
'type' => 'boolean',
]
],
],
], [
'key' => 'catalog.products.cache-small-image',
@ -208,7 +216,7 @@ return [
'name' => 'height',
'title' => 'admin::app.admin.system.height',
'type' => 'text',
]
],
],
], [
'key' => 'catalog.products.cache-medium-image',
@ -224,7 +232,7 @@ return [
'name' => 'height',
'title' => 'admin::app.admin.system.height',
'type' => 'text',
]
],
],
], [
'key' => 'catalog.products.cache-large-image',
@ -240,7 +248,7 @@ return [
'name' => 'height',
'title' => 'admin::app.admin.system.height',
'type' => 'text',
]
],
],
], [
'key' => 'catalog.products.review',
@ -266,7 +274,7 @@ return [
'name' => 'file_attribute_upload_size',
'title' => 'admin::app.admin.system.file-upload-size',
'type' => 'text',
]
],
],
], [
'key' => 'catalog.inventory',
@ -340,16 +348,65 @@ return [
'name' => 'show_search_input_field',
'title' => 'admin::app.admin.system.show-search-input-field',
'type' => 'boolean',
]
]
], [
],
],
],
/**
* Customer.
*/
[
'key' => 'customer',
'name' => 'admin::app.admin.system.customer',
'sort' => 4,
'sort' => 3,
], [
'key' => 'customer.address',
'name' => 'admin::app.admin.system.address',
'sort' => 1,
], [
'key' => 'customer.address.requirements',
'name' => 'admin::app.admin.system.requirements',
'sort' => 1,
'fields' => [
[
'name' => 'country',
'title' => 'admin::app.admin.system.country',
'type' => 'boolean',
'channel_based' => true,
'default' => '1',
],
[
'name' => 'state',
'title' => 'admin::app.admin.system.state',
'type' => 'boolean',
'channel_based' => true,
'default' => '1',
],
[
'name' => 'postcode',
'title' => 'admin::app.admin.system.zip',
'type' => 'boolean',
'channel_based' => true,
'default' => '1',
],
],
], [
'key' => 'customer.address.information',
'name' => 'Information',
'sort' => 2,
'fields' => [
[
'name' => 'street_lines',
'title' => 'admin::app.admin.system.street-lines',
'type' => 'text',
'validation' => 'between:1,4',
'channel_based' => true,
],
],
], [
'key' => 'customer.settings',
'name' => 'admin::app.admin.system.settings',
'sort' => 1,
'sort' => 3,
], [
'key' => 'customer.settings.wishlist',
'name' => 'admin::app.admin.system.wishlist',
@ -361,23 +418,10 @@ return [
'type' => 'boolean',
],
],
], [
'key' => 'customer.settings.address',
'name' => 'admin::app.admin.system.address',
'sort' => 2,
'fields' => [
[
'name' => 'street_lines',
'title' => 'admin::app.admin.system.street-lines',
'type' => 'text',
'validation' => 'between:1,4',
'channel_based' => true,
],
],
], [
'key' => 'customer.settings.newsletter',
'name' => 'admin::app.admin.system.newsletter',
'sort' => 3,
'sort' => 2,
'fields' => [
[
'name' => 'subscription',
@ -388,7 +432,7 @@ return [
], [
'key' => 'customer.settings.email',
'name' => 'admin::app.admin.system.email',
'sort' => 4,
'sort' => 3,
'fields' => [
[
'name' => 'verification',
@ -396,10 +440,15 @@ return [
'type' => 'boolean',
],
],
], [
],
/**
* Emails.
*/
[
'key' => 'emails',
'name' => 'admin::app.admin.emails.email',
'sort' => 5,
'sort' => 4,
], [
'key' => 'emails.configure',
'name' => 'admin::app.admin.system.email-settings',
@ -417,7 +466,7 @@ return [
'validation' => 'required|max:50',
'channel_based' => true,
'default_value' => config('mail.from.name'),
], [
], [
'name' => 'shop_email_from',
'title' => 'admin::app.admin.system.shop-email-from',
'type' => 'text',
@ -425,7 +474,7 @@ return [
'validation' => 'required|email',
'channel_based' => true,
'default_value' => config('mail.from.address'),
], [
], [
'name' => 'admin_name',
'title' => 'admin::app.admin.system.admin-name',
'type' => 'text',
@ -433,7 +482,7 @@ return [
'validation' => 'required|max:50',
'channel_based' => true,
'default_value' => config('mail.admin.name'),
], [
], [
'name' => 'admin_email',
'title' => 'admin::app.admin.system.admin-email',
'type' => 'text',

View File

@ -37,8 +37,18 @@ class CustomerDataGrid extends DataGrid
{
$queryBuilder = DB::table('customers')
->leftJoin('customer_groups', 'customers.customer_group_id', '=', 'customer_groups.id')
->addSelect('customers.id as customer_id', 'customers.email', 'customer_groups.name as group', 'customers.phone', 'customers.gender', 'status')
->addSelect(DB::raw('CONCAT(' . DB::getTablePrefix() . 'customers.first_name, " ", ' . DB::getTablePrefix() . 'customers.last_name) as full_name'));
->addSelect(
'customers.id as customer_id',
'customers.email',
'customers.phone',
'customers.gender',
'customers.status',
'customers.is_suspended',
'customer_groups.name as group',
)
->addSelect(
DB::raw('CONCAT(' . DB::getTablePrefix() . 'customers.first_name, " ", ' . DB::getTablePrefix() . 'customers.last_name) as full_name')
);
$this->addFilter('customer_id', 'customers.id');
$this->addFilter('full_name', DB::raw('CONCAT(' . DB::getTablePrefix() . 'customers.first_name, " ", ' . DB::getTablePrefix() . 'customers.last_name)'));
@ -101,7 +111,7 @@ class CustomerDataGrid extends DataGrid
'sortable' => true,
'filterable' => false,
'closure' => function ($row) {
if (!$row->phone) {
if (! $row->phone) {
return '-';
} else {
return $row->phone;
@ -117,7 +127,7 @@ class CustomerDataGrid extends DataGrid
'sortable' => true,
'filterable' => false,
'closure' => function ($row) {
if (!$row->gender) {
if (! $row->gender) {
return '-';
} else {
return $row->gender;
@ -133,11 +143,19 @@ class CustomerDataGrid extends DataGrid
'sortable' => true,
'filterable' => true,
'closure' => function ($row) {
$html = '';
if ($row->status == 1) {
return '<span class="badge badge-md badge-success">' . trans('admin::app.customers.customers.active') . '</span>';
$html .= '<span class="badge badge-md badge-success">' . trans('admin::app.customers.customers.active') . '</span>';
} else {
return '<span class="badge badge-md badge-danger">' . trans('admin::app.customers.customers.inactive') . '</span>';
$html .= '<span class="badge badge-md badge-danger">' . trans('admin::app.customers.customers.inactive') . '</span>';
}
if ($row->is_suspended == 1) {
$html .= '<span class="badge badge-md badge-danger">' . trans('admin::app.customers.customers.suspended') . '</span>';
}
return $html;
},
]);
}

View File

@ -175,6 +175,8 @@ class CustomerController extends Controller
$data['status'] = ! isset($data['status']) ? 0 : 1;
$data['is_suspended'] = ! isset($data['is_suspended']) ? 0 : 1;
$this->customerRepository->update($data, $id);
session()->flash('success', trans('admin::app.response.update-success', ['name' => 'Customer']));

View File

@ -1027,6 +1027,9 @@ return [
'status' => 'الحالة',
'active' => 'نشيط',
'inactive' => 'غير نشط',
'is-suspended' => 'Is Suspended',
'suspend' => 'Suspend',
'suspended' => 'Suspended',
],
'reviews' => [
@ -1422,10 +1425,12 @@ return [
'flate-rate-shipping' => 'تعريفة موحدة للشحن بغض النظر عن الكمية',
'shipping' => 'الشحن',
'origin' => 'الأصل',
'requirements' => 'Requirements',
'country' => 'بلد',
'state' => 'حالة',
'zip' => 'الرمز البريدي',
'city' => 'مدينة',
'information' => 'Information',
'street-address' => 'عنوان الشارع',
'title' => 'عنوان',
'description' => 'وصف',

View File

@ -1027,6 +1027,9 @@ return [
'status' => 'Status',
'active' => 'Aktiv',
'inactive' => 'Inaktiv',
'is-suspended' => 'Is Suspended',
'suspend' => 'Suspend',
'suspended' => 'Suspended',
],
'reviews' =>
[
@ -1430,10 +1433,12 @@ return [
'flate-rate-shipping' => 'Pauschale Versandkosten',
'shipping' => 'Versand',
'origin' => 'Herkunft',
'requirements' => 'Requirements',
'country' => 'Land',
'state' => 'Bundesland',
'zip' => 'Postleitzahl',
'city' => 'Stadt',
'information' => 'Information',
'street-address' => 'Anschrift',
'title' => 'Titel',
'description' => 'Beschreibung',

View File

@ -1045,6 +1045,9 @@ return [
'status' => 'Status',
'active' => 'Active',
'inactive' => 'Inactive',
'is-suspended' => 'Is Suspended',
'suspend' => 'Suspend',
'suspended' => 'Suspended',
],
'reviews' => [
@ -1421,7 +1424,8 @@ return [
],
],
'system' => [
'system' => [
'catalog' => 'Catalog',
'homepage' => 'Homepage configuration',
'allow-out-of-stock-items' => 'Allow out of stock items',
@ -1449,10 +1453,12 @@ return [
'flate-rate-shipping' => 'Flat Rate Shipping',
'shipping' => 'Shipping',
'origin' => 'Origin',
'requirements' => 'Requirements',
'country' => 'Country',
'state' => 'State',
'zip' => 'Zip',
'city' => 'City',
'information' => 'Information',
'street-address' => 'Street Address',
'title' => 'Title',
'description' => 'Description',

View File

@ -1036,6 +1036,9 @@ return [
'status' => 'Estado',
'active' => 'Activo',
'inactive' => 'Inactivo',
'is-suspended' => 'Is Suspended',
'suspend' => 'Suspend',
'suspended' => 'Suspended',
],
'reviews' => [
@ -1434,10 +1437,12 @@ return [
'flate-rate-shipping' => 'Envío con tarifa plana',
'shipping' => 'Envío',
'origin' => 'Origen',
'requirements' => 'Requirements',
'country' => 'País',
'state' => 'Departamento',
'zip' => 'Código Postal',
'city' => 'Ciudad',
'information' => 'Information',
'street-address' => 'Dirección',
'title' => 'Título',
'description' => 'Descripción',

View File

@ -1022,6 +1022,9 @@ return [
'status' => 'وضعیت',
'active' => 'فعال',
'inactive' => 'غیرفعال',
'is-suspended' => 'Is Suspended',
'suspend' => 'Suspend',
'suspended' => 'Suspended',
],
'reviews' => [
@ -1419,10 +1422,12 @@ return [
'flate-rate-shipping' => 'نرخ ثابت حمل و نقل',
'shipping' => 'حمل و نقل دریایی',
'origin' => 'مبدا',
'requirements' => 'Requirements',
'country' => 'کشور',
'state' => 'استان',
'zip' => 'کد پستی',
'city' => 'شهر',
'information' => 'Information',
'street-address' => 'آدرس خیابان',
'title' => 'عنوان',
'description' => 'توضیحات',

View File

@ -1042,6 +1042,9 @@ return [
'status' => 'Statut',
'active' => 'actif',
'inactive' => 'Inactif',
'is-suspended' => 'Is Suspended',
'suspend' => 'Suspend',
'suspended' => 'Suspended',
],
'reviews' => [
@ -1446,10 +1449,12 @@ return [
'flate-rate-shipping' => 'Expédition forfaitaire',
'shipping' => 'Expédition',
'origin' => 'Origine',
'requirements' => 'Requirements',
'country' => 'Pays',
'state' => 'État',
'zip' => 'Zipper',
'city' => 'Ville',
'information' => 'Information',
'street-address' => 'Adresse de rue',
'title' => 'Titre',
'description' => 'La description',

View File

@ -1030,6 +1030,9 @@ return [
'active' => 'Attivo',
'inactive' => 'Non attivo',
'in-active' => 'Non attivo',
'is-suspended' => 'Is Suspended',
'suspend' => 'Suspend',
'suspended' => 'Suspended',
],
'reviews' => [
@ -1422,10 +1425,12 @@ return [
'flate-rate-shipping' => 'Spedizione Prezzo Fisso',
'shipping' => 'Spedizione',
'origin' => 'Origine',
'requirements' => 'Requirements',
'country' => 'Paese',
'state' => 'Provincia',
'zip' => 'CAP',
'city' => 'Città',
'information' => 'Information',
'street-address' => 'Indirizzo',
'title' => 'Titolo',
'description' => 'Descrizione',

View File

@ -1024,6 +1024,9 @@ return [
'status' => 'Status',
'active' => 'Actief',
'inactive' => 'Niet geactiveerd',
'is-suspended' => 'Is Suspended',
'suspend' => 'Suspend',
'suspended' => 'Suspended',
],
'reviews' => [
@ -1416,10 +1419,12 @@ return [
'flate-rate-shipping' => 'Forfaitaire verzendkosten',
'shipping' => 'Verzending',
'origin' => 'Herkomst',
'requirements' => 'Requirements',
'country' => 'Land',
'state' => 'Staat/Provincie',
'zip' => 'Zip',
'city' => 'Woonplaats',
'information' => 'Information',
'street-address' => 'Adres',
'title' => 'Titel',
'description' => 'Omschrijving',

View File

@ -1027,6 +1027,9 @@ return [
'status' => 'Status',
'active' => 'Aktywny',
'inactive' => 'Nieaktywny',
'is-suspended' => 'Is Suspended',
'suspend' => 'Suspend',
'suspended' => 'Suspended',
],
'reviews' => [
@ -1419,10 +1422,12 @@ return [
'flate-rate-shipping' => 'Stawka ryczałtowa',
'shipping' => 'Dostawa',
'origin' => 'Zamieszmanie',
'requirements' => 'Requirements',
'country' => 'Kraj',
'state' => 'Stan/województwo',
'zip' => 'Kod',
'city' => 'Miasto',
'information' => 'Information',
'street-address' => 'ulica',
'title' => 'Tytuł',
'description' => 'Opis',

View File

@ -1026,6 +1026,9 @@ return [
'status' => 'Status',
'active' => 'Ativo (a)',
'inactive' => 'Inativo (a)',
'is-suspended' => 'Is Suspended',
'suspend' => 'Suspend',
'suspended' => 'Suspended',
],
'reviews' => [
@ -1418,10 +1421,12 @@ return [
'flate-rate-shipping' => 'Envio de taxa fixa',
'shipping' => 'Remessa',
'origin' => 'Origem',
'requirements' => 'Requirements',
'country' => 'País',
'state' => 'Estado',
'zip' => 'CEP',
'city' => 'Cidade',
'information' => 'Information',
'street-address' => 'Endereço',
'title' => 'Titulo',
'description' => 'Descrição',

View File

@ -1015,6 +1015,9 @@ return [
'status' => 'Durum',
'active' => 'Aktif',
'inactive' => 'Pasif',
'is-suspended' => 'Is Suspended',
'suspend' => 'Suspend',
'suspended' => 'Suspended',
],
'reviews' => [
@ -1406,10 +1409,12 @@ return [
'flate-rate-shipping' => 'Sabit Fiyat Teslimat',
'shipping' => 'Teslimat',
'origin' => 'Menşei',
'requirements' => 'Requirements',
'country' => 'Ülke',
'state' => 'Şehir',
'zip' => 'Posta Kodu',
'city' => 'İlçe',
'information' => 'Information',
'street-address' => 'Sokak Adresi',
'title' => 'Başlık',
'description' => 'Açıklama',

View File

@ -4,21 +4,14 @@
<div slot="body">
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.images.controls.before', ['product' => $product]) !!}
<div class="control-group {!! $errors->has('images.*') ? 'has-error' : '' !!}">
<div class="control-group {{ $errors->has('images.files.*') ? 'has-error' : '' }}">
<label>{{ __('admin::app.catalog.categories.image') }}</label>
<product-image></product-image>
<span class="control-error" v-if="{!! $errors->has('images.*') !!}">
@php $count = 1; @endphp
@foreach ($errors->get('images.*') as $key => $message)
@php
echo str_replace($key, 'Image'.$count, $message[0]);
$count++;
@endphp
@endforeach
<span
class="control-error"
v-text="'{{ $errors->first('images.files.*') }}'">
</span>
<span class="control-info mt-10">{{ __('admin::app.catalog.products.image-size') }}</span>
@ -34,13 +27,15 @@
<script type="text/x-template" id="product-image-template">
<div>
<div class="image-wrapper">
<product-image-item
v-for='(image, index) in items'
:key='image.id'
:image="image"
@onRemoveImage="removeImage($event)"
@onImageSelected="imageSelected($event)"
></product-image-item>
<draggable v-model="items" group="people" @end="onDragEnd">
<product-image-item
v-for='(image, index) in items'
:key='image.id'
:image="image"
@onRemoveImage="removeImage($event)"
@onImageSelected="imageSelected($event)">
</product-image-item>
</draggable>
</div>
<label class="btn btn-lg btn-primary" style="display: inline-block; width: auto" @click="createFileType">
@ -51,11 +46,29 @@
<script type="text/x-template" id="product-image-item-template">
<label class="image-item" v-bind:class="{ 'has-image': imageData.length > 0 }">
<input type="hidden" :name="'images[' + image.id + ']'" v-if="! new_image"/>
<input
type="hidden"
:name="'images[files][' + image.id + ']'"
v-if="! new_image"/>
<input type="file" v-validate="'mimes:image/*'" accept="image/*" :name="'images[]'" ref="imageInput" :id="_uid" @change="addImageView($event)" multiple="multiple"/>
<input
type="hidden"
:name="'images[positions][' + image.id + ']'"/>
<img class="preview" :src="imageData" v-if="imageData.length > 0">
<input
:id="_uid"
ref="imageInput"
type="file"
name="images[files][]"
accept="image/*"
multiple="multiple"
v-validate="'mimes:image/*'"
@change="addImageView($event)"/>
<img
class="preview"
:src="imageData"
v-if="imageData.length > 0">
<label class="remove-image" @click="removeImage()">
{{ __('admin::app.catalog.products.remove-image-btn-title') }}
@ -73,7 +86,7 @@
imageCount: 0,
items: []
items: [],
}
},
@ -102,7 +115,7 @@
this.items.push({'id': 'image_' + this.imageCount});
},
removeImage (image) {
removeImage: function(image) {
let index = this.items.indexOf(image)
Vue.delete(this.items, index);
@ -118,7 +131,15 @@
self.items.push({'id': 'image_' + self.imageCount, file: image});
}
});
}
},
onDragEnd: function() {
this.items = this.items.map((item, index) => {
item.position = index;
return item;
});
},
}
});
@ -192,4 +213,4 @@
}
});
</script>
@endpush
@endpush

View File

@ -32,7 +32,6 @@
<accordian :title="'{{ __('admin::app.catalog.products.variations') }}'" :active="true">
<div slot="body">
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.variations.controls.before', ['product' => $product]) !!}
<button type="button" class="btn btn-md btn-primary" @click="showModal('addVariant')">
@ -42,7 +41,6 @@
<variant-list></variant-list>
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.variations.controls.after', ['product' => $product]) !!}
</div>
</accordian>
@ -58,17 +56,21 @@
@push('scripts')
<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')">
<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', errors.has('add-variant-form.' + attribute.code) ? 'has-error' : '']">
<label
class="required"
:for="attribute.code"
v-text="attribute.admin_name">
</label>
<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]"
@ -77,21 +79,25 @@
:name="attribute.code"
:data-vv-as="'&quot;' + attribute.admin_name + '&quot;'"
>
<option v-for='(option, index) in attribute.options' :value="option.id">
@{{ option.admin_name }}
<option
v-for='(option, index) in attribute.options'
:value="option.id"
v-text="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>
<span
class="control-error"
v-text="errors.first('add-variant-form.' + attribute.code)"
v-if="errors.has('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>
@ -106,8 +112,11 @@
<th>{{ __('admin::app.catalog.products.images') }}</th>
@foreach ($product->super_attributes as $attribute)
<th class="{{ $attribute->code }}"
style="width: 150px">{{ $attribute->admin_name }}</th>
<th
class="{{ $attribute->code }}"
style="width: 150px">
{{ $attribute->admin_name }}
</th>
@endforeach
<th class="qty">{{ __('admin::app.catalog.products.qty') }}</th>
@ -119,7 +128,10 @@
</thead>
<tbody>
<variant-item v-for='(variant, index) in variants' :key="index" :index="index"
<variant-item
v-for='(variant, index) in variants'
:key="index"
:index="index"
:variant="variant" @onRemoveVariant="removeVariant($event)">
</variant-item>
</tbody>
@ -132,9 +144,13 @@
<td>
<div class="control-group">
<span class="radio">
<input type="radio" id="default_variant_id"
name="default_variant_id" :value="variant.id"
v-on:change="checkDefaultVariant(variant.id)" :checked="variant.id == default_variant_id">
<input
id="default_variant_id"
type="radio"
name="default_variant_id"
:value="variant.id"
v-on:change="checkDefaultVariant(variant.id)"
:checked="variant.id == default_variant_id">
<label class="radio-view" :for="[variantInputName + '[default_variant_id]']"></label>
</span>
</div>
@ -142,33 +158,65 @@
<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"
<input
class="control"
type="text"
:name="[variantInputName + '[sku]']"
v-model="variant.sku"
v-validate="'required'"
data-vv-as="&quot;{{ __('admin::app.catalog.products.sku') }}&quot;"
v-slugify/>
<span class="control-error" v-if="errors.has(variantInputName + '[sku]')">@{{ errors.first(variantInputName + '[sku]') }}</span>
<span
class="control-error"
v-text="errors.first(variantInputName + '[sku]')"
v-if="errors.has(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"
<div
:class="['control-group', errors.has(variantInputName + '[name]') ? 'has-error' : '']">
<input
class="control"
type="text"
:name="[variantInputName + '[name]']"
v-model="variant.name"
v-validate="'required'"
data-vv-as="&quot;{{ __('admin::app.catalog.products.name') }}&quot;"/>
<span class="control-error" v-if="errors.has(variantInputName + '[name]')">@{{ errors.first(variantInputName + '[name]') }}</span>
<span
class="control-error"
v-text="errors.first(variantInputName + '[name]')"
v-if="errors.has(variantInputName + '[name]')">
</span>
</div>
</td>
<td>
<div class="control-group" :class="[errors.has(variantInputName + '[images][' + index + ']') ? 'has-error' : '']">
<div :class="['control-group', errors.has(variantInputName + '[images][files][' + index + ']') ? 'has-error' : '']">
<div v-for='(image, index) in items' class="image-wrapper variant-image">
<label class="image-item" v-bind:class="{ 'has-image': imageData[index] }">
<input type="hidden" :name="[variantInputName + '[images][' + image.id + ']']" v-if="! new_image[index]"/>
<input
type="hidden"
:name="[variantInputName + '[images][files][' + image.id + ']']"
v-if="! new_image[index]"/>
<input type="file" v-validate="'mimes:image/*'" :name="[variantInputName + '[images][' + index + ']']" accept="image/*" :ref="'imageInput' + index" multiple="multiple" @change="addImageView($event, index)" :id="image.id"/>
<input
:ref="'imageInput' + index"
:id="image.id"
type="file"
:name="[variantInputName + '[images][files][' + index + ']']"
accept="image/*"
multiple="multiple"
v-validate="'mimes:image/*'"
@change="addImageView($event, index)"/>
<img class="preview" :src="imageData[index]" v-if="imageData[index]">
<img
class="preview"
:src="imageData[index]"
v-if="imageData[index]">
</label>
<span class="icon trash-icon" @click="removeImage(image)"></span>
@ -182,9 +230,15 @@
<td v-for='(attribute, index) in superAttributes'>
<div class="control-group">
<input type="hidden" :name="[variantInputName + '[' + attribute.code + ']']"
<input
type="hidden"
:name="[variantInputName + '[' + attribute.code + ']']"
:value="variant[attribute.code]"/>
<input type="text" class="control" :value="optionName(variant[attribute.code])"
<input
type="text"
class="control"
:value="optionName(variant[attribute.code])"
readonly/>
</div>
</td>
@ -192,6 +246,7 @@
<td>
<button style="width: 100%;" type="button" class="dropdown-btn dropdown-toggle">
@{{ totalQty }}
<i class="icon arrow-down-icon"></i>
</button>
@ -201,14 +256,21 @@
<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'"
<label v-text="inventorySource.name"></label>
<input
type="text"
:name="[variantInputName + '[inventories][' + inventorySource.id + ']']"
v-model="inventories[inventorySource.id]" class="control"
v-on:keyup="updateTotalQty()"
:data-vv-as="'&quot;' + inventorySource.name + '&quot;'"/>
<span class="control-error"
v-if="errors.has(variantInputName + '[inventories][' + inventorySource.id + ']')">@{{ errors.first(variantInputName + '[inventories][' + inventorySource.id + ']') }}</span>
v-validate="'numeric|min:0'"
:data-vv-as="'&quot;' + inventorySource.name + '&quot;'"
v-on:keyup="updateTotalQty()"/>
<span
class="control-error"
v-text="errors.first(variantInputName + '[inventories][' + inventorySource.id + ']')"
v-if="errors.has(variantInputName + '[inventories][' + inventorySource.id + ']')">
</span>
</div>
</li>
</ul>
@ -217,42 +279,70 @@
</td>
<td>
<div class="control-group"
:class="[errors.has(variantInputName + '[price]') ? 'has-error' : '']">
<input type="number" v-validate="'required'" v-model="variant.price"
:name="[variantInputName + '[price]']" class="control"
<div :class="['control-group', errors.has(variantInputName + '[price]') ? 'has-error' : '']">
<input
class="control"
type="number"
:name="[variantInputName + '[price]']"
v-model="variant.price"
v-validate="'required'"
data-vv-as="&quot;{{ __('admin::app.catalog.products.price') }}&quot;"
step="any"/>
<span class="control-error" v-if="errors.has(variantInputName + '[price]')">@{{ errors.first(variantInputName + '[price]') }}</span>
<span
class="control-error"
v-text="errors.first(variantInputName + '[price]')"
v-if="errors.has(variantInputName + '[price]')">
</span>
</div>
</td>
<td>
<div class="control-group"
:class="[errors.has(variantInputName + '[weight]') ? 'has-error' : '']">
<input type="number" v-validate="'required'" v-model="variant.weight"
<div :class="['control-group', errors.has(variantInputName + '[weight]') ? 'has-error' : '']">
<input
type="number"
:name="[variantInputName + '[weight]']" class="control"
v-model="variant.weight"
v-validate="'required'"
data-vv-as="&quot;{{ __('admin::app.catalog.products.weight') }}&quot;"
step="any"/>
<span class="control-error" v-if="errors.has(variantInputName + '[weight]')">@{{ errors.first(variantInputName + '[weight]') }}</span>
<span
class="control-error"
v-text="errors.first(variantInputName + '[weight]')"
v-if="errors.has(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
class="control"
type="text"
v-model="variant.status"
:name="[variantInputName + '[status]']">
<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>
<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>

View File

@ -4,21 +4,14 @@
<div slot="body">
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.videos.controls.before', ['product' => $product]) !!}
<div class="control-group {!! $errors->has('videos.*') ? 'has-error' : '' !!}">
<div class="control-group {{ $errors->has('videos.files.*') ? 'has-error' : '' }}">
<label>{{ __('admin::app.catalog.products.video') }}</label>
<product-video></product-video>
<span class="control-error" v-if="{!! $errors->has('videos.*') !!}">
@php $count = 1; @endphp
@foreach ($errors->get('videos.*') as $key => $message)
@php
echo str_replace($key, 'Video'.$count, $message[0]);
$count++;
@endphp
@endforeach
<span
class="control-error"
v-text="'{{ $errors->first('videos.files.*') }}'">
</span>
</div>
@ -32,13 +25,15 @@
<script type="text/x-template" id="product-video-template">
<div>
<div class="image-wrapper">
<product-video-item
v-for='(video, index) in items'
:key='video.id'
:video="video"
@onRemoveVideo="removeVideo($event)"
@onVideoSelected="videoSelected($event)"
></product-video-item>
<draggable v-model="items" group="people" @end="onDragEnd">
<product-video-item
v-for='(video, index) in items'
:key='video.id'
:video="video"
@onRemoveVideo="removeVideo($event)"
@onVideoSelected="videoSelected($event)">
</product-video-item>
</draggable>
</div>
<label class="btn btn-lg btn-primary" style="display: inline-block; width: auto" @click="createFileType">
@ -49,12 +44,28 @@
<script type="text/x-template" id="product-video-item-template">
<label class="image-item" v-bind:class="{ 'has-image': videoData.length > 0 }">
<input type="hidden" :name="'videos[' + video.id + ']'" v-if="! new_video"/>
<input
type="hidden"
:name="'videos[files][' + video.id + ']'"
v-if="! new_video"/>
<input type="file" v-validate="'mimes:video/*'" accept="video/*" :name="'videos[]'" ref="videoInput" :id="_uid" @change="addVideoView($event)" multiple="multiple"/>
<input
type="hidden"
:name="'videos[positions][' + video.id + ']'"/>
<input
:id="_uid"
ref="videoInput"
type="file"
name="videos[files][]"
accept="video/*"
multiple="multiple"
v-validate="'mimes:video/*'"
@change="addVideoView($event)"/>
<video class="preview" v-if="videoData.length > 0" width="200" height="160" controls>
<source :src="videoData" type="video/mp4">
{{ __('admin::app.catalog.products.not-support-video') }}
</video>
@ -74,7 +85,7 @@
videoCount: 0,
items: []
items: [],
}
},
@ -88,7 +99,7 @@
let self = this;
this.videos.forEach(function(video) {
self.items.push(video)
self.items.push(video);
self.videoCount++;
});
@ -103,8 +114,8 @@
this.items.push({'id': 'video_' + this.videoCount});
},
removeVideo (video) {
let index = this.items.indexOf(video)
removeVideo: function(video) {
let index = this.items.indexOf(video);
Vue.delete(this.items, index);
},
@ -119,7 +130,15 @@
self.items.push({'id': 'video_' + self.videoCount, file: video});
}
});
}
},
onDragEnd: function() {
this.items = this.items.map((item, index) => {
item.position = index;
return item;
});
},
}
});
@ -130,7 +149,7 @@
video: {
type: Object,
required: false,
default: null
default: null,
},
},
@ -138,8 +157,8 @@
return {
videoData: '',
new_video: 0
}
new_video: 0,
};
},
mounted () {
@ -162,10 +181,10 @@
if (videoInput.files && videoInput.files[0]) {
if (videoInput.files[0].type.includes('video/')) {
this.readFile(videoInput.files[0])
this.readFile(videoInput.files[0]);
if (videoInput.files.length > 1) {
this.$emit('onVideoSelected', videoInput)
this.$emit('onVideoSelected', videoInput);
}
} else {
videoInput.value = "";
@ -188,9 +207,9 @@
},
removeVideo: function() {
this.$emit('onRemoveVideo', this.video)
}
this.$emit('onRemoveVideo', this.video);
},
}
});
</script>
@endpush
@endpush

View File

@ -105,6 +105,24 @@
{!! view_render_event('bagisto.admin.customer.edit.status.after', ['customer' => $customer]) !!}
<div class="control-group">
<label for="isSuspended" class="required">{{ __('admin::app.customers.customers.suspend') }}</label>
<label class="switch">
<input
id="isSuspended"
type="checkbox"
name="is_suspended"
value="{{ $customer->is_suspended }}" {{ $customer->is_suspended ? 'checked' : '' }}>
<span class="slider round"></span>
</label>
<span class="control-error" v-if="errors.has('is_suspended')">@{{ errors.first('is_suspended') }}</span>
</div>
{!! view_render_event('bagisto.admin.customer.edit.is_suspended.after', ['customer' => $customer]) !!}
<div class="control-group date" :class="[errors.has('date_of_birth') ? 'has-error' : '']">
<label for="dob">{{ __('admin::app.customers.customers.date_of_birth') }}</label>

View File

@ -3,6 +3,8 @@
namespace Webkul\Checkout\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Webkul\Core\Contracts\Validations\AlphaNumericSpace;
use Webkul\Core\Contracts\Validations\PhoneNumber;
class CustomerAddressForm extends FormRequest
{
@ -30,65 +32,69 @@ class CustomerAddressForm extends FormRequest
*/
public function rules(): array
{
$customerAddressIds = $this->getCustomerAddressIds();
if (isset($this->get('billing')['address_id'])) {
$billingAddressRules = [
'billing.address_id' => ['required'],
];
if (! empty($customerAddressIds)) {
$billingAddressRules['billing.address_id'][] = "in:{$customerAddressIds}";
}
$this->mergeWithRules($billingAddressRules);
$this->mergeExistingAddressRules('billing');
} else {
$this->mergeWithRules([
'billing.first_name' => ['required'],
'billing.last_name' => ['required'],
'billing.email' => ['required'],
'billing.address1' => ['required'],
'billing.city' => ['required'],
'billing.state' => ['required'],
'billing.postcode' => ['required'],
'billing.phone' => ['required'],
'billing.country' => ['required'],
]);
$this->mergeNewAddressRules('billing');
}
if (isset($this->get('billing')['use_for_shipping']) && ! $this->get('billing')['use_for_shipping']) {
if (isset($this->get('shipping')['address_id'])) {
$shippingAddressRules = [
'shipping.address_id' => ['required'],
];
if (! empty($customerAddressIds)) {
$shippingAddressRules['shipping.address_id'][] = "in:{$customerAddressIds}";
}
$this->mergeWithRules($shippingAddressRules);
$this->mergeExistingAddressRules('shipping');
} else {
$this->mergeWithRules([
'shipping.first_name' => ['required'],
'shipping.last_name' => ['required'],
'shipping.email' => ['required'],
'shipping.address1' => ['required'],
'shipping.city' => ['required'],
'shipping.state' => ['required'],
'shipping.postcode' => ['required'],
'shipping.phone' => ['required'],
'shipping.country' => ['required'],
]);
$this->mergeNewAddressRules('shipping');
}
}
return $this->rules;
}
/**
* Merge existing address rules.
*
* @param string $addressType
* @return void
*/
private function mergeExistingAddressRules(string $addressType)
{
$customerAddressIds = $this->getCustomerAddressIds();
$addressRules = [
"{$addressType}.address_id" => ['required'],
];
if (! empty($customerAddressIds)) {
$addressRules["{$addressType}.address_id"][] = "in:{$customerAddressIds}";
}
$this->mergeWithRules($addressRules);
}
/**
* Merge new address rules.
*
* @param string $addressType
* @return void
*/
private function mergeNewAddressRules(string $addressType)
{
$this->mergeWithRules([
"{$addressType}.first_name" => ['required', new AlphaNumericSpace],
"{$addressType}.last_name" => ['required', new AlphaNumericSpace],
"{$addressType}.email" => ['required'],
"{$addressType}.address1" => ['required'],
"{$addressType}.city" => ['required'],
"{$addressType}.country" => [new AlphaNumericSpace],
"{$addressType}.state" => [new AlphaNumericSpace],
"{$addressType}.postcode" => ['numeric'],
"{$addressType}.phone" => ['required', new PhoneNumber],
]);
}
/**
* Merge additional rules.
*
* @return string
* @return void
*/
private function mergeWithRules($additionalRules): void
{

View File

@ -860,13 +860,7 @@ class Core
}
if (! $coreConfigValue) {
$fields = explode('.', $field);
array_shift($fields);
$field = implode('.', $fields);
return Config::get($field);
return $this->getDefaultConfig($field);
}
return $coreConfigValue->value;
@ -951,6 +945,36 @@ class Core
}
}
/**
* Is country required.
*
* @return bool
*/
public function isCountryRequired()
{
return $this->getConfigData('customer.address.requirements.country') == 1;
}
/**
* Is state required.
*
* @return bool
*/
public function isStateRequired()
{
return $this->getConfigData('customer.address.requirements.state') == 1;
}
/**
* Is postcode required.
*
* @return bool
*/
public function isPostCodeRequired()
{
return $this->getConfigData('customer.address.requirements.postcode') == 1;
}
/**
* Returns time intervals.
*
@ -1292,4 +1316,23 @@ class Core
return $coreConfigValue;
}
/**
* Get default config.
*
* @param string $field
* @return mixed
*/
protected function getDefaultConfig($field)
{
$configFieldInfo = $this->getConfigField($field);
$fields = explode('.', $field);
array_shift($fields);
$field = implode('.', $fields);
return Config::get($field, $configFieldInfo['default'] ?? null);
}
}

View File

@ -5,11 +5,12 @@ namespace Webkul\Core\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Webkul\Customer\Models\Customer;
use Webkul\Core\Contracts\Address as AddressContract;
use Webkul\Customer\Models\Customer;
/**
* Class Address
* Address class.
*
* @package Webkul\Core\Models
*
* @property string $address_type
@ -34,18 +35,32 @@ use Webkul\Core\Contracts\Address as AddressContract;
* @property-read string $name
* @property-read Carbon $created_at
* @property-read Carbon $updated_at
*
*/
abstract class Address extends Model implements AddressContract
{
/**
* Table.
*
* @var string
*/
protected $table = 'addresses';
/**
* Guarded.
*
* @var array
*/
protected $guarded = [
'id',
'created_at',
'updated_at',
];
/**
* Fillable.
*
* @var array
*/
protected $fillable = [
'address_type',
'customer_id',
@ -68,6 +83,11 @@ abstract class Address extends Model implements AddressContract
'additional',
];
/**
* Castable.
*
* @var array
*/
protected $casts = [
'additional' => 'array',
'default_address' => 'boolean',
@ -75,6 +95,8 @@ abstract class Address extends Model implements AddressContract
/**
* Get all the attributes for the attribute groups.
*
* @return string
*/
public function getNameAttribute(): string
{
@ -83,6 +105,8 @@ abstract class Address extends Model implements AddressContract
/**
* Get the customer record associated with the address.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function customer(): BelongsTo
{

View File

@ -4,28 +4,28 @@ return [
[
'key' => 'customer.captcha',
'name' => 'customer::app.admin.system.captcha.title',
'sort' => 1,
'sort' => 2,
], [
'key' => 'customer.captcha.credentials',
'name' => 'customer::app.admin.system.captcha.credentials',
'sort' => 1,
'fields' => [
[
'name' => 'site_key',
'title' => 'customer::app.admin.system.captcha.site-key',
'type' => 'text',
'name' => 'site_key',
'title' => 'customer::app.admin.system.captcha.site-key',
'type' => 'text',
'channel_based' => true,
], [
'name' => 'secret_key',
'title' => 'customer::app.admin.system.captcha.secret-key',
'type' => 'text',
'name' => 'secret_key',
'title' => 'customer::app.admin.system.captcha.secret-key',
'type' => 'text',
'channel_based' => true,
], [
'name' => 'status',
'title' => 'customer::app.admin.system.captcha.status',
'type' => 'boolean',
'channel_based' => true,
]
],
],
],
];

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class UpdateCountryStateAndZipCodeInAddressesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('addresses', function (Blueprint $table) {
$table->string('country')->nullable()->change();
$table->string('state')->nullable()->change();
$table->string('postcode')->nullable()->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('addresses', function (Blueprint $table) {
$table->string('country')->nullable(false)->change();
$table->string('state')->nullable(false)->change();
$table->string('postcode')->nullable(false)->change();
});
}
}

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddIsSuspendedColumnToCustomersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('customers', function (Blueprint $table) {
$table->tinyInteger('is_suspended')->unsigned()->default(0)->after('is_verified');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('customers', function (Blueprint $table) {
$table->dropColumn('is_suspended');
});
}
}

View File

@ -33,10 +33,10 @@ class CustomerAddressRequest extends FormRequest
'last_name' => ['required', new AlphaNumericSpace],
'address1' => ['required', 'array'],
'address1.*' => ['required', new Address],
'country' => ['required', 'alpha'],
'state' => ['required', new AlphaNumericSpace],
'country' => [new AlphaNumericSpace],
'state' => [new AlphaNumericSpace],
'city' => ['required'],
'postcode' => ['required', 'numeric'],
'postcode' => ['numeric'],
'phone' => ['required', new PhoneNumber],
'vat_id' => [new VatIdRule()],
];

View File

@ -42,12 +42,13 @@ class Customer extends Authenticatable implements CustomerContract, JWTSubject
'phone',
'password',
'api_token',
'token',
'customer_group_id',
'subscribed_to_news_letter',
'is_verified',
'token',
'notes',
'status',
'is_verified',
'is_suspended',
'notes',
];
/**
@ -68,7 +69,7 @@ class Customer extends Authenticatable implements CustomerContract, JWTSubject
*/
protected static function newFactory()
{
return CustomerFactory::new();
return CustomerFactory::new ();
}
/**

View File

@ -1,14 +1,17 @@
<?php
/**
* For parent sales key, check the sales package config file,
* i.e. `packages/Webkul/Sales/src/Config/system.php`
*/
return [
/**
* Payment methods.
*/
[
'key' => 'sales',
'name' => 'admin::app.admin.system.sales',
'sort' => 1
], [
'key' => 'sales.paymentmethods',
'name' => 'admin::app.admin.system.payment-methods',
'sort' => 2,
'sort' => 3,
], [
'key' => 'sales.paymentmethods.cashondelivery',
'name' => 'admin::app.admin.system.cash-on-delivery',
@ -42,37 +45,37 @@ return [
'channel_based' => true,
'locale_based' => false,
], [
'name' => 'invoice_status',
'title' => 'admin::app.admin.system.set-invoice-status',
'name' => 'invoice_status',
'title' => 'admin::app.admin.system.set-invoice-status',
'validation' => 'required_if:generate_invoice,1',
'type' => 'select',
'options' => [
'type' => 'select',
'options' => [
[
'title' => 'admin::app.sales.invoices.status-pending',
'value' => 'pending'
'value' => 'pending',
], [
'title' => 'admin::app.sales.invoices.status-paid',
'value' => 'paid'
]
'value' => 'paid',
],
],
'info' => 'admin::app.admin.system.generate-invoice-applicable',
'channel_based' => true,
'locale_based' => false,
], [
'name' => 'order_status',
'title' => 'admin::app.admin.system.set-order-status',
'type' => 'select',
'options' => [
'name' => 'order_status',
'title' => 'admin::app.admin.system.set-order-status',
'type' => 'select',
'options' => [
[
'title' => 'admin::app.sales.orders.order-status-pending',
'value' => 'pending'
'value' => 'pending',
], [
'title' => 'admin::app.sales.orders.order-status-pending-payment',
'value' => 'pending_payment'
'value' => 'pending_payment',
], [
'title' => 'admin::app.sales.orders.order-status-processing',
'value' => 'processing'
]
'value' => 'processing',
],
],
'info' => 'admin::app.admin.system.generate-invoice-applicable',
'channel_based' => true,
@ -91,20 +94,20 @@ return [
'options' => [
[
'title' => '1',
'value' => 1
'value' => 1,
], [
'title' => '2',
'value' => 2
'value' => 2,
], [
'title' => '3',
'value' => 3
'value' => 3,
], [
'title' => '4',
'value' => 4,
]
],
],
]
]
],
],
], [
'key' => 'sales.paymentmethods.moneytransfer',
'name' => 'admin::app.admin.system.money-transfer',
@ -138,13 +141,13 @@ return [
'options' => [
[
'title' => 'admin::app.sales.invoices.status-pending',
'value' => 'pending'
'value' => 'pending',
], [
'title' => 'admin::app.sales.invoices.status-paid',
'value' => 'paid'
]
'value' => 'paid',
],
],
'info' => 'admin::app.admin.system.generate-invoice-applicable',
'info' => 'admin::app.admin.system.generate-invoice-applicable',
], [
'name' => 'order_status',
'title' => 'Order status after creating the invoice',
@ -152,16 +155,16 @@ return [
'options' => [
[
'title' => 'admin::app.sales.orders.order-status-pending',
'value' => 'pending'
'value' => 'pending',
], [
'title' => 'admin::app.sales.orders.order-status-pending-payment',
'value' => 'pending_payment'
'value' => 'pending_payment',
], [
'title' => 'admin::app.sales.orders.order-status-processing',
'value' => 'processing'
]
'value' => 'processing',
],
],
'info' => 'admin::app.admin.system.generate-invoice-applicable',
'info' => 'admin::app.admin.system.generate-invoice-applicable',
], [
'name' => 'mailing_address',
'title' => 'admin::app.admin.system.mailing-address',
@ -175,7 +178,7 @@ return [
'validation' => 'required',
'channel_based' => true,
'locale_based' => true,
],[
], [
'name' => 'sort',
'title' => 'admin::app.admin.system.sort_order',
'type' => 'select',
@ -192,9 +195,9 @@ return [
], [
'title' => '4',
'value' => 4,
]
],
],
]
]
]
];
],
],
],
];

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddPositionColumnToProductImagesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('product_images', function (Blueprint $table) {
$table->integer('position')->default(0)->unsigned();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('product_images', function (Blueprint $table) {
$table->dropColumn('position');
});
}
}

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddPositionColumnToProductVideosTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('product_videos', function (Blueprint $table) {
$table->integer('position')->default(0)->unsigned();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('product_videos', function (Blueprint $table) {
$table->dropColumn('position');
});
}
}

View File

@ -73,8 +73,10 @@ class ProductForm extends FormRequest
$this->rules = array_merge($product->getTypeInstance()->getTypeValidationRules(), [
'sku' => ['required', 'unique:products,sku,' . $this->id, new Slug],
'url_key' => ['required', new ProductCategoryUniqueSlug('product_flat', $this->id)],
'images.*' => ['nullable', 'mimes:bmp,jpeg,jpg,png,webp'],
'videos.*' => ['nullable', 'mimetypes:application/octet-stream,video/mp4,video/webm,video/quicktime', 'max:' . $maxVideoFileSize],
'images.files.*' => ['nullable', 'mimes:bmp,jpeg,jpg,png,webp'],
'images.positions.*' => ['nullable', 'integer'],
'videos.files.*' => ['nullable', 'mimetypes:application/octet-stream,video/mp4,video/webm,video/quicktime', 'max:' . $maxVideoFileSize],
'videos.positions.*' => ['nullable', 'integer'],
'special_price_from' => ['nullable', 'date'],
'special_price_to' => ['nullable', 'date', 'after_or_equal:special_price_from'],
'special_price' => ['nullable', new Decimal, 'lt:price'],
@ -141,6 +143,8 @@ class ProductForm extends FormRequest
public function attributes()
{
return [
'images.files.*' => 'image',
'videos.files.*' => 'video',
'variants.*.sku' => 'sku',
];
}

View File

@ -4,22 +4,22 @@ namespace Webkul\Product\Models;
use Exception;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Collection;
use Webkul\Attribute\Models\AttributeFamilyProxy;
use Webkul\Attribute\Models\AttributeProxy;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Webkul\Product\Database\Factories\ProductFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\BookingProduct\Models\BookingProductProxy;
use Webkul\Category\Models\CategoryProxy;
use Webkul\Inventory\Models\InventorySourceProxy;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Webkul\Product\Contracts\Product as ProductContract;
use Webkul\Product\Database\Eloquent\Builder;
use Webkul\Product\Database\Factories\ProductFactory;
use Webkul\Product\Type\AbstractType;
use Webkul\BookingProduct\Models\BookingProductProxy;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Product extends Model implements ProductContract
{
@ -49,19 +49,19 @@ class Product extends Model implements ProductContract
/**
* The type of product.
*
* @var $typeInstance
* @var \Webkul\Product\Type\AbstractType
*/
protected $typeInstance;
/**
* Loaded attribute values.
*
* @var $loadedAttributeValues
* @var array
*/
public static $loadedAttributeValues = [];
/**
* The "booted" method of the model.
* The `booted` method of the model.
*
* @return void
*/
@ -82,75 +82,137 @@ class Product extends Model implements ProductContract
});
}
/**
* Refresh the loaded attribute values.
*
* @return void
*/
public function refreshloadedAttributeValues(): void
{
self::$loadedAttributeValues = [];
}
/**
* Get the product attribute family that owns the product.
*/
public function attribute_family(): BelongsTo
{
return $this->belongsTo(AttributeFamilyProxy::modelClass());
}
/**
* Get the product attribute values that owns the product.
*/
public function attribute_values(): HasMany
{
return $this->hasMany(ProductAttributeValueProxy::modelClass());
}
/**
* Get the product flat entries that are associated with product.
* May be one for each locale and each channel.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function product_flats(): HasMany
{
return $this->hasMany(ProductFlatProxy::modelClass(), 'product_id');
}
/**
* Get the product variants that owns the product.
*/
public function variants(): HasMany
{
return $this->hasMany(static::class, 'parent_id');
}
/**
* Get the product reviews that owns the product.
*/
public function reviews(): HasMany
{
return $this->hasMany(ProductReviewProxy::modelClass());
}
/**
* Get the product that owns the product.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function parent(): BelongsTo
{
return $this->belongsTo(static::class, 'parent_id');
}
/**
* Get the product attribute family that owns the product.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function attribute_family(): BelongsTo
{
return $this->belongsTo(AttributeFamilyProxy::modelClass());
}
/**
* The super attributes that belong to the product.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function super_attributes(): BelongsToMany
{
return $this->belongsToMany(AttributeProxy::modelClass(), 'product_super_attributes');
}
/**
* Get the product attribute values that owns the product.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function attribute_values(): HasMany
{
return $this->hasMany(ProductAttributeValueProxy::modelClass());
}
/**
* Get the product customer group prices that owns the product.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function customer_group_prices(): HasMany
{
return $this->hasMany(ProductCustomerGroupPriceProxy::modelClass());
}
/**
* The categories that belong to the product.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function categories(): BelongsToMany
{
return $this->belongsToMany(CategoryProxy::modelClass(), 'product_categories');
}
/**
* The images that belong to the product.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function images(): HasMany
{
return $this->hasMany(ProductImageProxy::modelClass(), 'product_id')
->orderBy('position');
}
/**
* The videos that belong to the product.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function videos(): HasMany
{
return $this->hasMany(ProductVideoProxy::modelClass(), 'product_id')
->orderBy('position');
}
/**
* Get the product reviews that owns the product.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function reviews(): HasMany
{
return $this->hasMany(ProductReviewProxy::modelClass());
}
/**
* The inventory sources that belong to the product.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function inventory_sources(): BelongsToMany
{
return $this->belongsToMany(InventorySourceProxy::modelClass(), 'product_inventories')
->withPivot('id', 'qty');
}
/**
* Get inventory source quantity.
*
* @param $inventorySourceId
* @return bool
*/
public function inventory_source_qty($inventorySourceId)
{
return $this->inventories()
->where('inventory_source_id', $inventorySourceId)
->sum('qty');
}
/**
* The inventories that belong to the product.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function inventories(): HasMany
{
@ -159,6 +221,8 @@ class Product extends Model implements ProductContract
/**
* The ordered inventories that belong to the product.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function ordered_inventories(): HasMany
{
@ -166,78 +230,29 @@ class Product extends Model implements ProductContract
}
/**
* The inventory sources that belong to the product.
* Get the product variants that owns the product.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function inventory_sources(): BelongsToMany
public function variants(): HasMany
{
return $this->belongsToMany(InventorySourceProxy::modelClass(), 'product_inventories')
->withPivot('id', 'qty');
return $this->hasMany(static::class, 'parent_id');
}
/**
* The super attributes that belong to the product.
* Get the grouped products that owns the product.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function super_attributes(): BelongsToMany
public function grouped_products(): HasMany
{
return $this->belongsToMany(AttributeProxy::modelClass(), 'product_super_attributes');
}
/**
* The images that belong to the product.
*/
public function images(): HasMany
{
return $this->hasMany(ProductImageProxy::modelClass(), 'product_id');
}
/**
* The videos that belong to the product.
*/
public function videos(): HasMany
{
return $this->hasMany(ProductVideoProxy::modelClass(), 'product_id');
}
/**
* The images that belong to the product.
*/
public function getBaseImageUrlAttribute()
{
$image = $this->images()
->first();
return $image->url ?? null;
}
/**
* The related products that belong to the product.
*/
public function related_products(): BelongsToMany
{
return $this->belongsToMany(static::class, 'product_relations', 'parent_id', 'child_id')
->limit(4);
}
/**
* The up sells that belong to the product.
*/
public function up_sells(): BelongsToMany
{
return $this->belongsToMany(static::class, 'product_up_sells', 'parent_id', 'child_id')
->limit(4);
}
/**
* The cross sells that belong to the product.
*/
public function cross_sells(): BelongsToMany
{
return $this->belongsToMany(static::class, 'product_cross_sells', 'parent_id', 'child_id')
->limit(4);
return $this->hasMany(ProductGroupedProductProxy::modelClass());
}
/**
* The images that belong to the product.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function downloadable_samples(): HasMany
{
@ -246,22 +261,18 @@ class Product extends Model implements ProductContract
/**
* The images that belong to the product.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function downloadable_links(): HasMany
{
return $this->hasMany(ProductDownloadableLinkProxy::modelClass());
}
/**
* Get the grouped products that owns the product.
*/
public function grouped_products(): HasMany
{
return $this->hasMany(ProductGroupedProductProxy::modelClass());
}
/**
* Get the bundle options that owns the product.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function bundle_options(): HasMany
{
@ -269,31 +280,107 @@ class Product extends Model implements ProductContract
}
/**
* Get the product customer group prices that owns the product.
* Get the booking that owns the product.
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function customer_group_prices(): HasMany
public function booking_product()
{
return $this->hasMany(ProductCustomerGroupPriceProxy::modelClass());
return $this->hasOne(BookingProductProxy::modelClass());
}
/**
* Get inventory source quantity.
* The related products that belong to the product.
*
* @param $inventorySourceId
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function related_products(): BelongsToMany
{
return $this->belongsToMany(static::class, 'product_relations', 'parent_id', 'child_id')
->limit(4);
}
/**
* The up sells that belong to the product.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function up_sells(): BelongsToMany
{
return $this->belongsToMany(static::class, 'product_up_sells', 'parent_id', 'child_id')
->limit(4);
}
/**
* The cross sells that belong to the product.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function cross_sells(): BelongsToMany
{
return $this->belongsToMany(static::class, 'product_cross_sells', 'parent_id', 'child_id')
->limit(4);
}
/**
* Is saleable.
*
* @param string $key
* @return bool
*
* @throws \Exception
*/
public function isSaleable(): bool
{
return $this->getTypeInstance()
->isSaleable();
}
/**
* Is stockable.
*
* @return bool
*
* @throws \Exception
*/
public function inventory_source_qty($inventorySourceId)
public function isStockable(): bool
{
return $this->inventories()
->where('inventory_source_id', $inventorySourceId)
->sum('qty');
return $this->getTypeInstance()
->isStockable();
}
/**
* Total quantity.
*
* @return integer
*
* @throws \Exception
*/
public function totalQuantity(): int
{
return $this->getTypeInstance()
->totalQuantity();
}
/**
* Have sufficient quantity.
*
* @param int $qty
* @return bool
*
* @throws \Exception
*/
public function haveSufficientQuantity(int $qty): bool
{
return $this->getTypeInstance()
->haveSufficientQuantity($qty);
}
/**
* Get type instance.
*
* @return AbstractType
*
* @throws \Exception
*/
public function getTypeInstance(): AbstractType
@ -314,62 +401,42 @@ class Product extends Model implements ProductContract
}
/**
* Is saleable.
* Return the product id attribute.
*
* @param string $key
*
* @return bool
* @throws \Exception
* @return int
*/
public function isSaleable(): bool
public function getProductIdAttribute()
{
return $this->getTypeInstance()
->isSaleable();
return $this->id;
}
/**
* Total quantity.
* Return the product attribute.
*
* @return integer
* @throws \Exception
* @return self
*/
public function totalQuantity(): int
public function getProductAttribute()
{
return $this->getTypeInstance()
->totalQuantity();
return $this;
}
/**
* Have sufficient quantity.
* The images that belong to the product.
*
* @param int $qty
*
* @return bool
* @throws \Exception
* @return string
*/
public function haveSufficientQuantity(int $qty): bool
public function getBaseImageUrlAttribute()
{
return $this->getTypeInstance()
->haveSufficientQuantity($qty);
}
$image = $this->images()
->first();
/**
* Is stockable.
*
* @return bool
* @throws \Exception
*/
public function isStockable(): bool
{
return $this->getTypeInstance()
->isStockable();
return $image->url ?? null;
}
/**
* Get an attribute from the model.
*
* @param string $key
*
* @return mixed
*/
public function getAttribute($key)
@ -402,14 +469,14 @@ class Product extends Model implements ProductContract
*
* @param Group $group
* @param bool $skipSuperAttribute
*
* @return \Illuminate\Support\Collection
*
* @throws \Exception
*/
public function getEditableAttributes($group = null, $skipSuperAttribute = true): Collection
{
return $this->getTypeInstance()
->getEditableAttributes($group, $skipSuperAttribute);
->getEditableAttributes($group, $skipSuperAttribute);
}
/**
@ -434,26 +501,26 @@ class Product extends Model implements ProductContract
if ($attribute->value_per_channel) {
if ($attribute->value_per_locale) {
$attributeValue = $this->attribute_values()
->where('channel', $channel)
->where('locale', $locale)
->where('attribute_id', $attribute->id)
->first();
->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();
->where('channel', $channel)
->where('attribute_id', $attribute->id)
->first();
}
} else {
if ($attribute->value_per_locale) {
$attributeValue = $this->attribute_values()
->where('locale', $locale)
->where('attribute_id', $attribute->id)
->first();
->where('locale', $locale)
->where('attribute_id', $attribute->id)
->first();
} else {
$attributeValue = $this->attribute_values()
->where('attribute_id', $attribute->id)
->first();
->where('attribute_id', $attribute->id)
->first();
}
}
@ -486,34 +553,6 @@ class Product extends Model implements ProductContract
return $attributes;
}
/**
* Overrides the default Eloquent query builder.
*
* @param \Illuminate\Database\Query\Builder $query
*
* @return \Webkul\Product\Database\Eloquent\Builder
*/
public function newEloquentBuilder($query)
{
return new Builder($query);
}
/**
* Return the product id attribute.
*/
public function getProductIdAttribute()
{
return $this->id;
}
/**
* Return the product attribute.
*/
public function getProductAttribute()
{
return $this;
}
/**
* Check in loaded family attributes.
*
@ -533,20 +572,33 @@ class Product extends Model implements ProductContract
}
/**
* Create a new factory instance for the model.
* Overrides the default Eloquent query builder.
*
* @return Factory
* @param \Illuminate\Database\Query\Builder $query
* @return \Webkul\Product\Database\Eloquent\Builder
*/
protected static function newFactory(): Factory
public function newEloquentBuilder($query)
{
return ProductFactory::new();
return new Builder($query);
}
/**
* Get the booking that owns the product.
* Refresh the loaded attribute values.
*
* @return void
*/
public function booking_product()
public function refreshloadedAttributeValues(): void
{
return $this->hasOne(BookingProductProxy::modelClass());
self::$loadedAttributeValues = [];
}
/**
* Create a new factory instance for the model.
*
* @return \Illuminate\Database\Eloquent\Factories\Factory
*/
protected static function newFactory(): Factory
{
return ProductFactory::new ();
}
}

View File

@ -154,7 +154,8 @@ class ProductFlat extends Model implements ProductFlatContract
*/
public function images()
{
return $this->hasMany(ProductImageProxy::modelClass(), 'product_id', 'product_id');
return $this->hasMany(ProductImageProxy::modelClass(), 'product_id', 'product_id')
->orderBy('position');
}
/**
@ -164,7 +165,8 @@ class ProductFlat extends Model implements ProductFlatContract
*/
public function videos()
{
return $this->product->videos();
return $this->product->videos()
->orderBy('position');
}
/**
@ -222,7 +224,7 @@ class ProductFlat extends Model implements ProductFlatContract
/**
* Retrieve product attributes.
*
* @param Group $group
* @param Group $group
* @param bool $skipSuperAttribute
* @return Collection
*/
@ -255,7 +257,7 @@ class ProductFlat extends Model implements ProductFlatContract
/**
* Is product saleable.
*
* @param string $key
* @param string $key
* @return bool
*/
public function isSaleable()

View File

@ -8,15 +8,36 @@ use Webkul\Product\Contracts\ProductImage as ProductImageContract;
class ProductImage extends Model implements ProductImageContract
{
/**
* Timestamp.
*
* @var boolean
*/
public $timestamps = false;
/**
* Fillable.
*
* @var array
*/
protected $fillable = [
'type',
'path',
'product_id',
'position',
];
/**
* The accessors to append to the model's array form.
*
* @var array
*/
protected $appends = ['url'];
/**
* Get the product that owns the image.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function product()
{
@ -25,6 +46,8 @@ class ProductImage extends Model implements ProductImageContract
/**
* Get image url for the product image.
*
* @return string
*/
public function url()
{
@ -33,6 +56,8 @@ class ProductImage extends Model implements ProductImageContract
/**
* Get image url for the product image.
*
* @return string
*/
public function getUrlAttribute()
{
@ -40,24 +65,13 @@ class ProductImage extends Model implements ProductImageContract
}
/**
* @param string $key
* Is custom attribute.
*
* @param string $key
* @return bool
*/
public function isCustomAttribute($attribute)
{
return $this->attribute_family->custom_attributes->pluck('code')->contains($attribute);
}
/**
* @return array
*/
public function toArray()
{
$array = parent::toArray();
$array['url'] = $this->url;
return $array;
}
}
}

View File

@ -8,16 +8,36 @@ use Webkul\Product\Contracts\ProductVideo as ProductVideoContract;
class ProductVideo extends Model implements ProductVideoContract
{
/**
* Timestamps.
*
* @param bool
*/
public $timestamps = false;
/**
* Fillable.
*
* @param array
*/
protected $fillable = [
'type',
'path',
'product_id',
'type',
'position',
];
/**
* The accessors to append to the model's array form.
*
* @var array
*/
protected $appends = ['url'];
/**
* Get the product that owns the image.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function product()
{
@ -26,6 +46,8 @@ class ProductVideo extends Model implements ProductVideoContract
/**
* Get image url for the product image.
*
* @return string
*/
public function url()
{
@ -34,6 +56,8 @@ class ProductVideo extends Model implements ProductVideoContract
/**
* Get image url for the product image.
*
* @return string
*/
public function getUrlAttribute()
{
@ -41,24 +65,13 @@ class ProductVideo extends Model implements ProductVideoContract
}
/**
* @param string $key
* Is custom attribute.
*
* @param string $attribute
* @return bool
*/
public function isCustomAttribute($attribute)
{
return $this->attribute_family->custom_attributes->pluck('code')->contains($attribute);
}
/**
* @return array
*/
public function toArray()
{
$array = parent::toArray();
$array['url'] = $this->url;
return $array;
}
}
}

View File

@ -3,13 +3,13 @@
namespace Webkul\Product;
use Illuminate\Support\Facades\Storage;
use Webkul\Product\Repositories\ProductRepository;
use Webkul\Product\Helpers\AbstractProduct;
use Webkul\Product\Repositories\ProductRepository;
class ProductImage extends AbstractProduct
{
/**
* ProductRepository instance
* Product repository instance.
*
* @var \Webkul\Product\Repositories\ProductRepository
*/
@ -23,13 +23,12 @@ class ProductImage extends AbstractProduct
*/
public function __construct(
ProductRepository $productRepository
)
{
) {
$this->productRepository = $productRepository;
}
/**
* Retrieve collection of gallery images
* Retrieve collection of gallery images.
*
* @param \Webkul\Product\Contracts\Product|\Webkul\Product\Contracts\ProductFlat $product
* @return array
@ -87,7 +86,7 @@ class ProductImage extends AbstractProduct
* present or not. If not then it will load from the product.
*
* @param \Webkul\Product\Contracts\Product|\Webkul\Product\Contracts\ProductFlat $product
* @param array
* @param array
* @return array
*/
public function getProductBaseImage($product, array $galleryImages = null)
@ -126,7 +125,7 @@ class ProductImage extends AbstractProduct
return $this->getProductBaseImage($product);
}
/**
/**
* Load product's base image.
*
* @param \Webkul\Product\Contracts\Product|\Webkul\Product\Contracts\ProductFlat $product
@ -154,4 +153,4 @@ class ProductImage extends AbstractProduct
return $image;
}
}
}

View File

@ -2,13 +2,10 @@
namespace Webkul\Product\Repositories;
use Illuminate\Http\UploadedFile;
use Webkul\Core\Eloquent\Repository;
use Illuminate\Support\Facades\Storage;
use Illuminate\Container\Container as App;
use Webkul\Product\Repositories\ProductRepository;
class ProductImageRepository extends Repository
class ProductImageRepository extends ProductMediaRepository
{
/**
* Product repository object.
@ -40,17 +37,7 @@ class ProductImageRepository extends Repository
*/
public function model(): string
{
return 'Webkul\Product\Contracts\ProductImage';
}
/**
* Get product directory.
*
* @param Webkul\Product\Models\Product $variant
*/
public function getProductDirectory($product): string
{
return 'product/' . $product->id;
return \Webkul\Product\Contracts\ProductImage::class;
}
/**
@ -62,48 +49,13 @@ class ProductImageRepository extends Repository
*/
public function uploadImages($data, $product): void
{
$this->upload($product, $data['images'] ?? null);
$this->upload($data, $product, 'images');
if (isset($data['variants'])) {
$this->uploadVariantImages($data['variants']);
}
}
/**
* Upload.
*
* @param Webkul\Product\Models\Product $product
* @param array
* @return void
*/
public function upload($product, $images): void
{
$previousVariantImageIds = $product->images()->pluck('id');
if ($images) {
foreach ($images as $imageId => $image) {
if ($image instanceof UploadedFile) {
$this->create([
'path' => $image->store($this->getProductDirectory($product)),
'product_id' => $product->id,
]);
} else {
if (is_numeric($index = $previousVariantImageIds->search($imageId))) {
$previousVariantImageIds->forget($index);
}
}
}
}
foreach ($previousVariantImageIds as $imageId) {
if ($image = $this->find($imageId)) {
Storage::delete($image->path);
$this->delete($imageId);
}
}
}
/**
* Upload variant images.
*
@ -112,14 +64,14 @@ class ProductImageRepository extends Repository
*/
public function uploadVariantImages($variants): void
{
foreach ($variants as $variantsId => $variant) {
foreach ($variants as $variantsId => $variantData) {
$product = $this->productRepository->find($variantsId);
if (! $product) {
break;
}
$this->upload($product, $variant['images'] ?? null);
$this->upload($variantData, $product, 'images');
}
}
}
}

View File

@ -0,0 +1,113 @@
<?php
namespace Webkul\Product\Repositories;
use Exception;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Webkul\Core\Eloquent\Repository;
class ProductMediaRepository extends Repository
{
/**
* Specify model class name.
*
* @return string
*/
public function model()
{
/**
* This repository is extended to `ProductImageRepository` and `ProductVideoRepository`
* repository.
*
* And currently no model is assigned to this repo.
*/
}
/**
* Get product directory.
*
* @param \Webkul\Product\Contracts\Product $product
* @return string
*/
public function getProductDirectory($product): string
{
return 'product/' . $product->id;
}
/**
* Upload.
*
* @param array $data
* @param \Webkul\Product\Contracts\Product $product
* @param string $uploadFileType
* @return void
*/
public function upload($data, $product, string $uploadFileType): void
{
/**
* Previous model ids for filtering.
*/
$previousIds = $this->resolveFileTypeQueryBuilder($product, $uploadFileType)->pluck('id');
if (isset($data[$uploadFileType]['files']) && $data[$uploadFileType]['files']) {
foreach ($data[$uploadFileType]['files'] as $indexOrModelId => $file) {
if ($file instanceof UploadedFile) {
$this->create([
'type' => $uploadFileType,
'path' => $file->store($this->getProductDirectory($product)),
'product_id' => $product->id,
'position' => $indexOrModelId,
]);
} else {
/**
* Filter out existing models because new model positions are already setuped by index.
*/
if (isset($data[$uploadFileType]['positions']) && $data[$uploadFileType]['positions']) {
$positions = collect($data[$uploadFileType]['positions'])->keys()->filter(function ($position) {
return is_numeric($position);
});
$this->update([
'position' => $positions->search($indexOrModelId),
], $indexOrModelId);
}
if (is_numeric($index = $previousIds->search($indexOrModelId))) {
$previousIds->forget($index);
}
}
}
}
foreach ($previousIds as $indexOrModelId) {
if ($model = $this->find($indexOrModelId)) {
Storage::delete($model->path);
$this->delete($indexOrModelId);
}
}
}
/**
* Resolve file type query builder.
*
* @param \Webkul\Product\Contracts\Product $product
* @param string $uploadFileType
* @return mixed
*
* @throws \Exception
*/
private function resolveFileTypeQueryBuilder($product, string $uploadFileType)
{
if ($uploadFileType === 'images') {
return $product->images();
}
if ($uploadFileType === 'videos') {
return $product->videos();
}
throw new Exception('Unsupported file type.');
}
}

View File

@ -2,59 +2,27 @@
namespace Webkul\Product\Repositories;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Http\UploadedFile;
use Webkul\Core\Eloquent\Repository;
class ProductVideoRepository extends Repository
class ProductVideoRepository extends ProductMediaRepository
{
/**
* Specify Model class name
* Specify model class name.
*
* @return mixed
* @return string
*/
function model()
public function model()
{
return 'Webkul\Product\Contracts\ProductVideo';
return \Webkul\Product\Contracts\ProductVideo::class;
}
/**
* Upload videos.
*
* @param array $data
* @param \Webkul\Product\Contracts\Product $product
* @return void
*/
public function uploadVideos($data, $product)
{
$previousVideoIds = $product->videos()->pluck('id');
if (isset($data['videos'])) {
foreach ($data['videos'] as $videoId => $video) {
$file = 'videos.' . $videoId;
$dir = 'product/' . $product->id;
if ($video instanceof UploadedFile) {
if (request()->hasFile($file)) {
$this->create([
'path' => request()->file($file)->store($dir),
'product_id' => $product->id,
'type' => 'video'
]);
}
} else {
if (is_numeric($index = $previousVideoIds->search($videoId))) {
$previousVideoIds->forget($index);
}
}
}
}
foreach ($previousVideoIds as $videoId) {
if ($videoModel = $this->find($videoId)) {
Storage::delete($videoModel->path);
$this->delete($videoId);
}
}
$this->upload($data, $product, 'videos');
}
}
}

View File

@ -1053,7 +1053,7 @@ abstract class AbstractType
/**
* Get offers lines.
*
* @param array $customerGroupPrice
* @param object $customerGroupPrice
* @return array
*/
public function getOfferLines($customerGroupPrice)

View File

@ -17,63 +17,65 @@ use Webkul\Product\Repositories\ProductVideoRepository;
class Bundle extends AbstractType
{
/**
* ProductBundleOptionRepository instance
* Product bundle option repository instance.
*
* @var \Webkul\Product\Repositories\ProductBundleOptionRepository
*/
protected $productBundleOptionRepository;
/**
* ProductBundleOptionProductRepository instance
* Product bundle option product repository instance.
*
* @var \Webkul\Product\Repositories\ProductBundleOptionProductRepository
*/
protected $productBundleOptionProductRepository;
/**
* Bundle Option helper instance
* Bundle Option helper instance.
*
* @var \Webkul\Product\Helpers\BundleOption
*/
*/
protected $bundleOptionHelper;
/**
* Skip attribute for Bundle product type
* Skip attribute for Bundle product type.
*
* @var array
*/
protected $skipAttributes = ['price', 'cost', 'special_price', 'special_price_from', 'special_price_to', 'length', 'width', 'height', 'weight'];
/**
* These blade files will be included in product edit page
* These blade files will be included in product edit page.
*
* @var array
*/
protected $additionalViews = [
'admin::catalog.products.accordians.images',
'admin::catalog.products.accordians.videos',
'admin::catalog.products.accordians.categories',
'admin::catalog.products.accordians.bundle-items',
'admin::catalog.products.accordians.channels',
'admin::catalog.products.accordians.product-links',
'admin::catalog.products.accordians.videos',
];
/**
* Is a composite product type
* Is a composite product type.
*
* @var bool
*/
protected $isComposite = true;
/**
* Product children price can be calculated or not
* Product children price can be calculated or not.
*
* @var bool
*/
protected $isChildrenCalculated = true;
/**
* Product Options
* Product options.
*
* @var array
*/
protected $productOptions = [];
@ -101,8 +103,7 @@ class Bundle extends AbstractType
ProductBundleOptionProductRepository $productBundleOptionProductRepository,
BundleOption $bundleOptionHelper,
ProductVideoRepository $productVideoRepository
)
{
) {
parent::__construct(
$attributeRepository,
$productRepository,
@ -120,12 +121,14 @@ class Bundle extends AbstractType
}
/**
* Update.
*
* @param array $data
* @param int $id
* @param string $attribute
* @return \Webkul\Product\Contracts\Product
*/
public function update(array $data, $id, $attribute = "id")
public function update(array $data, $id, $attribute = 'id')
{
$product = parent::update($data, $id, $attribute);
$route = request()->route() ? request()->route()->getName() : '';
@ -138,7 +141,7 @@ class Bundle extends AbstractType
}
/**
* Returns children ids
* Returns children ids.
*
* @return array
*/
@ -148,7 +151,7 @@ class Bundle extends AbstractType
}
/**
* Check if catalog rule can be applied
* Check if catalog rule can be applied.
*
* @return bool
*/
@ -158,7 +161,7 @@ class Bundle extends AbstractType
}
/**
* Get product minimal price
* Get product minimal price.
*
* @param int $qty
* @return float
@ -193,7 +196,7 @@ class Bundle extends AbstractType
}
/**
* Get product regular minimal price
* Get product regular minimal price.
*
* @return float
*/
@ -227,7 +230,7 @@ class Bundle extends AbstractType
}
/**
* Get product regular minimal price
* Get product regular minimal price.
*
* @param \Webkul\Product\Contracts\ProductBundleOption $option
* @param bool $minPrice
@ -243,17 +246,17 @@ class Bundle extends AbstractType
}
$optionPrices[] = $bundleOptionProduct->qty
* ($minPrice
? $bundleOptionProduct->product->getTypeInstance()->getMinimalPrice()
: $bundleOptionProduct->product->price
);
* ($minPrice
? $bundleOptionProduct->product->getTypeInstance()->getMinimalPrice()
: $bundleOptionProduct->product->price
);
}
return $optionPrices;
}
/**
* Check if product has required options or not
* Check if product has required options or not.
*
* @return bool
*/
@ -269,7 +272,7 @@ class Bundle extends AbstractType
}
/**
* Get product maximam price
* Get product maximum price.
*
* @return float
*/
@ -306,7 +309,7 @@ class Bundle extends AbstractType
}
/**
* Get product regular maximam price
* Get product regular maximum price.
*
* @return float
*/
@ -343,7 +346,7 @@ class Bundle extends AbstractType
}
/**
* Get product minimal price
* Get product minimal price.
*
* @param int $qty
* @return float
@ -354,7 +357,7 @@ class Bundle extends AbstractType
}
/**
* Returns product prices
* Returns product prices.
*
* @return array
*/
@ -369,10 +372,10 @@ class Bundle extends AbstractType
'final_price' => [
'price' => core()->convertPrice($this->evaluatePrice($this->getMinimalPrice())),
'formated_price' => core()->currency($this->evaluatePrice($this->getMinimalPrice())),
]
],
],
'to' => [
'to' => [
'regular_price' => [
'price' => core()->convertPrice($this->evaluatePrice($this->getRegularMaximamPrice())),
'formated_price' => core()->currency($this->evaluatePrice($this->getRegularMaximamPrice())),
@ -380,13 +383,13 @@ class Bundle extends AbstractType
'final_price' => [
'price' => core()->convertPrice($this->evaluatePrice($this->getMaximamPrice())),
'formated_price' => core()->currency($this->evaluatePrice($this->getMaximamPrice())),
]
]
],
],
];
}
/**
* Get bundle product special price
* Get bundle product special price.
*
* @return boolean
*/
@ -405,7 +408,7 @@ class Bundle extends AbstractType
}
/**
* Get product minimal price
* Get product minimal price.
*
* @return string
*/
@ -415,19 +418,19 @@ class Bundle extends AbstractType
$priceHtml = '';
if ($this->checkBundleProductHaveSpecialPrice())
if ($this->checkBundleProductHaveSpecialPrice()) {
$priceHtml .= '<div class="sticker sale">' . trans('shop::app.products.sale') . '</div>';
}
$priceHtml .= '<div class="price-from">';
if ($prices['from']['regular_price']['price'] != $prices['from']['final_price']['price']) {
$priceHtml .= '<span class="bundle-regular-price">' . $prices['from']['regular_price']['formated_price'] . '</span>'
. '<span class="bundle-special-price">' . $prices['from']['final_price']['formated_price'] . '</span>';
. '<span class="bundle-special-price">' . $prices['from']['final_price']['formated_price'] . '</span>';
} else {
$priceHtml .= '<span>' . $prices['from']['regular_price']['formated_price'] . '</span>';
}
if ($prices['from']['regular_price']['price'] != $prices['to']['regular_price']['price']
|| $prices['from']['final_price']['price'] != $prices['to']['final_price']['price']
) {
@ -435,7 +438,7 @@ class Bundle extends AbstractType
if ($prices['to']['regular_price']['price'] != $prices['to']['final_price']['price']) {
$priceHtml .= '<span class="bundle-regular-price">' . $prices['to']['regular_price']['formated_price'] . '</span>'
. '<span class="bundle-special-price">' . $prices['to']['final_price']['formated_price'] . '</span>';
. '<span class="bundle-special-price">' . $prices['to']['final_price']['formated_price'] . '</span>';
} else {
$priceHtml .= '<span>' . $prices['to']['regular_price']['formated_price'] . '</span>';
}
@ -552,6 +555,7 @@ class Bundle extends AbstractType
}
/**
* Compare options.
*
* @param array $options1
* @param array $options2
@ -564,17 +568,20 @@ class Bundle extends AbstractType
}
if (isset($options1['bundle_options']) && isset($options2['bundle_options'])) {
return $options1['bundle_options'] == $options2['bundle_options']
&& $options1['bundle_option_qty'] == $this->getOptionQuantities($options2);
} elseif (! isset($options1['bundle_options'])) {
return $options1['bundle_options'] == $options2['bundle_options'] && $options1['bundle_option_qty'] == $this->getOptionQuantities($options2);
}
if (! isset($options1['bundle_options'])) {
return false;
} elseif (! isset($options2['bundle_options'])) {
}
if (! isset($options2['bundle_options'])) {
return false;
}
}
/**
* Remove invalid options from add to cart request
* Remove invalid options from add to cart request.
*
* @param array $data
* @return array
@ -585,7 +592,7 @@ class Bundle extends AbstractType
if (is_array($value)) {
$data[$key] = $this->validateBundleOptionForCart($value);
} elseif ($value && $value) {
$data[$key] = (int)$value;
$data[$key] = (int) $value;
} else {
unset($data[$key]);
}
@ -595,7 +602,7 @@ class Bundle extends AbstractType
}
/**
* Returns additional information for items
* Returns additional information for items.
*
* @param array $data
* @return array
@ -628,7 +635,7 @@ class Bundle extends AbstractType
$label = $qty . ' x ' . $optionProduct->product->name;
$price = $optionProduct->product->getTypeInstance()->getMinimalPrice();
if($price != 0){
if ($price != 0) {
$label .= ' ' . core()->currency($price);
}
@ -650,7 +657,7 @@ class Bundle extends AbstractType
}
/**
* Returns additional information for items
* Returns additional information for items.
*
* @param array $data
* @return array
@ -681,10 +688,9 @@ class Bundle extends AbstractType
}
/**
* Validate cart item product price and other things
*
* @param \Webkul\Checkout\Models\CartItem $item
* Validate cart item product price and other things.
*
* @param \Webkul\Checkout\Models\CartItem $item
* @return \Webkul\Product\Datatypes\CartItemValidationResult
*/
public function validateCartItem(CartItem $item): CartItemValidationResult
@ -732,17 +738,23 @@ class Bundle extends AbstractType
}
/**
* get product options
* Get product options.
*
* @param object $product
* @return mixed
*/
public function getProductOptions($product = "")
public function getProductOptions($product = '')
{
$bundleOption = app('Webkul\Product\Helpers\BundleOption');
$options = $bundleOption->getProductOptions($product);
return $options;
}
/**
* Have sufficient quantity.
*
* @param int $qty
* @return bool
*/

View File

@ -33,11 +33,11 @@ class Configurable extends AbstractType
*/
protected $additionalViews = [
'admin::catalog.products.accordians.images',
'admin::catalog.products.accordians.videos',
'admin::catalog.products.accordians.categories',
'admin::catalog.products.accordians.variations',
'admin::catalog.products.accordians.channels',
'admin::catalog.products.accordians.product-links',
'admin::catalog.products.accordians.videos',
];
/**
@ -347,7 +347,7 @@ class Configurable extends AbstractType
* Fill required fields.
*
* @param array $data
* @param int $id
* @param int $id
* @return \Webkul\Product\Contracts\Product
*/
public function fillRequiredFields(array $data): array
@ -365,7 +365,7 @@ class Configurable extends AbstractType
/**
* Check variant option availability.
*
* @param array $data
* @param array $data
* @param \Webkul\Product\Contracts\Product $product
* @return bool
*/
@ -653,9 +653,13 @@ class Configurable extends AbstractType
if (isset($options1['selected_configurable_option']) && isset($options2['selected_configurable_option'])) {
return $options1['selected_configurable_option'] === $options2['selected_configurable_option'];
} elseif (! isset($options1['selected_configurable_option'])) {
}
if (! isset($options1['selected_configurable_option'])) {
return false;
} elseif (! isset($options2['selected_configurable_option'])) {
}
if (! isset($options2['selected_configurable_option'])) {
return false;
}
}

View File

@ -16,56 +16,58 @@ use Webkul\Product\Repositories\ProductVideoRepository;
class Downloadable extends AbstractType
{
/**
* ProductDownloadableLinkRepository instance
* Product downloadable link repository instance.
*
* @var \Webkul\Product\Repositories\ProductDownloadableLinkRepository
*/
protected $productDownloadableLinkRepository;
/**
* ProductDownloadableSampleRepository instance
* Product downloadable sample repository instance.
*
* @var \Webkul\Product\Repositories\ProductDownloadableSampleRepository
*/
protected $productDownloadableSampleRepository;
/**
* Skip attribute for downloadable product type
* Skip attribute for downloadable product type.
*
* @var array
*/
protected $skipAttributes = ['length', 'width', 'height', 'weight', 'guest_checkout'];
/**
* These blade files will be included in product edit page
* These blade files will be included in product edit page.
*
* @var array
*/
protected $additionalViews = [
'admin::catalog.products.accordians.images',
'admin::catalog.products.accordians.videos',
'admin::catalog.products.accordians.categories',
'admin::catalog.products.accordians.downloadable',
'admin::catalog.products.accordians.channels',
'admin::catalog.products.accordians.product-links',
'admin::catalog.products.accordians.videos',
];
/**
* Is a stokable product type
* Is a stokable product type.
*
* @var bool
*/
protected $isStockable = false;
/**
* Show quantity box
* Show quantity box.
*
* @var bool
*/
protected $allowMultipleQty = false;
/**
* getProductOptions
* Get product options.
*
* @var array
*/
protected $getProductOptions = [];
@ -80,7 +82,6 @@ class Downloadable extends AbstractType
* @param \Webkul\Product\Repositories\ProductDownloadableLinkRepository $productDownloadableLinkRepository
* @param \Webkul\Product\Repositories\ProductDownloadableSampleRepository $productDownloadableSampleRepository
* @param \Webkul\Product\Repositories\ProductVideoRepository $productVideoRepository
*
* @return void
*/
public function __construct(
@ -92,8 +93,7 @@ class Downloadable extends AbstractType
ProductDownloadableLinkRepository $productDownloadableLinkRepository,
ProductDownloadableSampleRepository $productDownloadableSampleRepository,
ProductVideoRepository $productVideoRepository
)
{
) {
parent::__construct(
$attributeRepository,
$productRepository,
@ -109,13 +109,14 @@ class Downloadable extends AbstractType
}
/**
* @param array $data
* @param int $id
* @param string $attribute
* Update.
*
* @param array $data
* @param int $id
* @param string $attribute
* @return \Webkul\Product\Contracts\Product
*/
public function update(array $data, $id, $attribute = "id")
public function update(array $data, $id, $attribute = 'id')
{
$product = parent::update($data, $id, $attribute);
$route = request()->route() ? request()->route()->getName() : '';
@ -130,7 +131,7 @@ class Downloadable extends AbstractType
}
/**
* Return true if this product type is saleable
* Return true if this product type is saleable.
*
* @return bool
*/
@ -153,14 +154,13 @@ class Downloadable extends AbstractType
}
/**
* Returns validation rules
* Returns validation rules.
*
* @return array
*/
public function getTypeValidationRules()
{
return [
// 'downloadable_links.*.title' => 'required',
'downloadable_links.*.type' => 'required',
'downloadable_links.*.file' => 'required_if:type,==,file',
'downloadable_links.*.file_name' => 'required_if:type,==,file',
@ -173,8 +173,7 @@ class Downloadable extends AbstractType
/**
* Add product. Returns error message if can't prepare product.
*
* @param array $data
*
* @param array $data
* @return array
*/
public function prepareForCart($data)
@ -200,10 +199,10 @@ class Downloadable extends AbstractType
}
/**
* Compare options.
*
* @param array $options1
* @param array $options2
*
* @param array $options1
* @param array $options2
* @return bool
*/
public function compareOptions($options1, $options2)
@ -214,18 +213,21 @@ class Downloadable extends AbstractType
if (isset($options1['links']) && isset($options2['links'])) {
return $options1['links'] === $options2['links'];
} elseif (! isset($options1['links'])) {
}
if (! isset($options1['links'])) {
return false;
} elseif (! isset($options2['links'])) {
}
if (! isset($options2['links'])) {
return false;
}
}
/**
* Returns additional information for items
*
* @param array $data
* Returns additional information for items.
*
* @param array $data
* @return array
*/
public function getAdditionalOptions($data)
@ -250,8 +252,7 @@ class Downloadable extends AbstractType
/**
* Validate cart item product price
*
* @param \Webkul\Checkout\Models\CartItem $item
*
* @param \Webkul\Checkout\Models\CartItem $item
* @return \Webkul\Product\Datatypes\CartItemValidationResult
*/
public function validateCartItem(CartItem $item): CartItemValidationResult
@ -292,7 +293,7 @@ class Downloadable extends AbstractType
}
/**
* Get product maximam price
* Get product maximum price
*
* @return float
*/

View File

@ -34,11 +34,11 @@ class Grouped extends AbstractType
*/
protected $additionalViews = [
'admin::catalog.products.accordians.images',
'admin::catalog.products.accordians.videos',
'admin::catalog.products.accordians.categories',
'admin::catalog.products.accordians.grouped-products',
'admin::catalog.products.accordians.channels',
'admin::catalog.products.accordians.product-links',
'admin::catalog.products.accordians.videos',
];
/**

View File

@ -5,17 +5,17 @@ namespace Webkul\Product\Type;
class Simple extends AbstractType
{
/**
* These blade files will be included in product edit page
* These blade files will be included in product edit page.
*
* @var array
*/
protected $additionalViews = [
'admin::catalog.products.accordians.inventories',
'admin::catalog.products.accordians.images',
'admin::catalog.products.accordians.videos',
'admin::catalog.products.accordians.categories',
'admin::catalog.products.accordians.channels',
'admin::catalog.products.accordians.product-links',
'admin::catalog.products.accordians.videos',
];
/**
@ -52,6 +52,8 @@ class Simple extends AbstractType
}
/**
* Have sufficient quantity.
*
* @param int $qty
* @return bool
*/
@ -59,13 +61,13 @@ class Simple extends AbstractType
{
$backorders = core()->getConfigData('catalog.inventory.stock_options.backorders');
$backorders = ! is_null ($backorders) ? $backorders : false;
$backorders = ! is_null($backorders) ? $backorders : false;
return $qty <= $this->totalQuantity() ? true : $backorders;
}
/**
* Get product maximam price
* Get product maximum price.
*
* @return float
*/

View File

@ -5,42 +5,42 @@ namespace Webkul\Product\Type;
class Virtual extends AbstractType
{
/**
* Skip attribute for virtual product type
* Skip attribute for virtual product type.
*
* @var array
*/
protected $skipAttributes = ['length', 'width', 'height', 'weight'];
/**
* These blade files will be included in product edit page
* These blade files will be included in product edit page.
*
* @var array
*/
protected $additionalViews = [
'admin::catalog.products.accordians.inventories',
'admin::catalog.products.accordians.images',
'admin::catalog.products.accordians.videos',
'admin::catalog.products.accordians.categories',
'admin::catalog.products.accordians.channels',
'admin::catalog.products.accordians.product-links',
'admin::catalog.products.accordians.videos',
];
/**
* Is a stokable product type
* Is a stokable product type.
*
* @var bool
*/
protected $isStockable = false;
/**
* Show quantity box
* Show quantity box.
*
* @var bool
*/
protected $showQuantityBox = true;
/**
* Return true if this product type is saleable
* Return true if this product type is saleable.
*
* @return bool
*/
@ -63,8 +63,9 @@ class Virtual extends AbstractType
}
/**
* @param int $qty
* Have sufficient quantity.
*
* @param int $qty
* @return bool
*/
public function haveSufficientQuantity(int $qty): bool
@ -73,7 +74,7 @@ class Virtual extends AbstractType
}
/**
* Get product maximam price
* Get product maximum price.
*
* @return float
*/

View File

@ -2,12 +2,29 @@
return [
/**
* Order Settings
* Sales.
*
* Child keys are in different package.
*
* Sort `1` | Shipping | Shipping Package
* Sort `2` | Shipping Method | Shipping Package
* Sort `3` | Payment Method | Payment Package
* Sort `4` | Order Settings | Self
* Sort `5` | Invoice Settings | Self
*/
[
'key' => 'sales',
'name' => 'admin::app.admin.system.sales',
'sort' => 5,
],
/**
* Order settings.
*/
[
'key' => 'sales.orderSettings',
'name' => 'admin::app.admin.system.order-settings',
'sort' => 3,
'sort' => 4,
], [
'key' => 'sales.orderSettings.order_number',
'name' => 'admin::app.admin.system.orderNumber',
@ -45,7 +62,7 @@ return [
'channel_based' => true,
'locale_based' => true,
],
]
],
], [
'key' => 'sales.orderSettings.minimum-order',
'name' => 'admin::app.admin.system.minimum-order',
@ -59,16 +76,16 @@ return [
'channel_based' => true,
'locale_based' => true,
],
]
],
],
/**
* Invoice Settings
* Invoice settings.
*/
[
'key' => 'sales.invoice_setttings',
'name' => 'admin::app.admin.system.invoice-settings',
'sort' => 4,
'sort' => 5,
], [
'key' => 'sales.invoice_setttings.invoice_number',
'name' => 'admin::app.admin.system.invoice-number',
@ -106,7 +123,7 @@ return [
'channel_based' => true,
'locale_based' => true,
],
]
],
], [
'key' => 'sales.invoice_setttings.payment_terms',
'name' => 'admin::app.admin.system.payment-terms',
@ -119,7 +136,7 @@ return [
'validation' => 'numeric',
'channel_based' => true,
],
]
],
], [
'key' => 'sales.invoice_setttings.invoice_slip_design',
'name' => 'admin::app.admin.system.invoice-slip-design',
@ -132,7 +149,7 @@ return [
'validation' => 'mimes:bmp,jpeg,jpg,png,webp',
'channel_based' => true,
],
]
],
], [
'key' => 'sales.invoice_setttings.invoice_reminders',
'name' => 'admin::app.admin.system.invoice-reminders',
@ -146,10 +163,10 @@ return [
'channel_based' => true,
],
[
'name' => 'interval_between_reminders',
'title' => 'admin::app.admin.system.interval-between-reminders',
'type' => 'select',
'options' => [
'name' => 'interval_between_reminders',
'title' => 'admin::app.admin.system.interval-between-reminders',
'type' => 'select',
'options' => [
[
'title' => '1 day',
'value' => 'P1D',
@ -183,6 +200,6 @@ return [
],
],
],
]
],
],
];

View File

@ -1,109 +1,17 @@
<?php
/**
* For parent sales key, check the sales package config file,
* i.e. `packages/Webkul/Sales/src/Config/system.php`
*/
return [
/**
* Shipping.
*/
[
'key' => 'sales',
'name' => 'admin::app.admin.system.sales',
'sort' => 5,
], [
'key' => 'sales.carriers',
'name' => 'admin::app.admin.system.shipping-methods',
'sort' => 1,
], [
'key' => 'sales.carriers.free',
'name' => 'admin::app.admin.system.free-shipping',
'sort' => 1,
'fields' => [
[
'name' => 'title',
'title' => 'admin::app.admin.system.title',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
'channel_based' => false,
'locale_based' => true,
], [
'name' => 'description',
'title' => 'admin::app.admin.system.description',
'type' => 'textarea',
'channel_based' => false,
'locale_based' => true,
], [
'name' => 'active',
'title' => 'admin::app.admin.system.status',
'type' => 'boolean',
'validation' => 'required',
'channel_based' => false,
'locale_based' => true,
], [
'name' => 'is_calculate_tax',
'title' => 'admin::app.admin.system.calculate-tax',
'type' => 'boolean',
'validation' => 'required',
'channel_based' => false,
'locale_based' => false,
]
]
], [
'key' => 'sales.carriers.flatrate',
'name' => 'admin::app.admin.system.flate-rate-shipping',
'sort' => 2,
'fields' => [
[
'name' => 'title',
'title' => 'admin::app.admin.system.title',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
'channel_based' => true,
'locale_based' => true,
], [
'name' => 'description',
'title' => 'admin::app.admin.system.description',
'type' => 'textarea',
'channel_based' => true,
'locale_based' => false,
], [
'name' => 'default_rate',
'title' => 'admin::app.admin.system.rate',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
'channel_based' => true,
'locale_based' => false,
], [
'name' => 'type',
'title' => 'admin::app.admin.system.type',
'type' => 'select',
'options' => [
[
'title' => 'Per Unit',
'value' => 'per_unit',
], [
'title' => 'Per Order',
'value' => 'per_order',
]
],
], [
'name' => 'active',
'title' => 'admin::app.admin.system.status',
'type' => 'boolean',
'validation' => 'required',
'channel_based' => false,
'locale_based' => true,
], [
'name' => 'is_calculate_tax',
'title' => 'admin::app.admin.system.calculate-tax',
'type' => 'boolean',
'validation' => 'required',
'channel_based' => false,
'locale_based' => false,
]
]
], [
'key' => 'sales.shipping',
'name' => 'admin::app.admin.system.shipping',
'sort' => 0,
'sort' => 1,
], [
'key' => 'sales.shipping.origin',
'name' => 'admin::app.admin.system.origin',
@ -123,7 +31,7 @@ return [
'validation' => 'required',
'channel_based' => true,
'locale_based' => true,
], [
], [
'name' => 'city',
'title' => 'admin::app.admin.system.city',
'type' => 'text',
@ -164,7 +72,107 @@ return [
'title' => 'admin::app.admin.system.bank-details',
'type' => 'textarea',
'channel_based' => true,
]
]
]
],
],
],
/**
* Shipping method.
*/
[
'key' => 'sales.carriers',
'name' => 'admin::app.admin.system.shipping-methods',
'sort' => 2,
], [
'key' => 'sales.carriers.free',
'name' => 'admin::app.admin.system.free-shipping',
'sort' => 1,
'fields' => [
[
'name' => 'title',
'title' => 'admin::app.admin.system.title',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
'channel_based' => false,
'locale_based' => true,
], [
'name' => 'description',
'title' => 'admin::app.admin.system.description',
'type' => 'textarea',
'channel_based' => false,
'locale_based' => true,
], [
'name' => 'active',
'title' => 'admin::app.admin.system.status',
'type' => 'boolean',
'validation' => 'required',
'channel_based' => false,
'locale_based' => true,
], [
'name' => 'is_calculate_tax',
'title' => 'admin::app.admin.system.calculate-tax',
'type' => 'boolean',
'validation' => 'required',
'channel_based' => false,
'locale_based' => false,
],
],
], [
'key' => 'sales.carriers.flatrate',
'name' => 'admin::app.admin.system.flate-rate-shipping',
'sort' => 2,
'fields' => [
[
'name' => 'title',
'title' => 'admin::app.admin.system.title',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
'channel_based' => true,
'locale_based' => true,
], [
'name' => 'description',
'title' => 'admin::app.admin.system.description',
'type' => 'textarea',
'channel_based' => true,
'locale_based' => false,
], [
'name' => 'default_rate',
'title' => 'admin::app.admin.system.rate',
'type' => 'depends',
'depend' => 'active:1',
'validation' => 'required_if:active,1',
'channel_based' => true,
'locale_based' => false,
], [
'name' => 'type',
'title' => 'admin::app.admin.system.type',
'type' => 'select',
'options' => [
[
'title' => 'Per Unit',
'value' => 'per_unit',
], [
'title' => 'Per Order',
'value' => 'per_order',
],
],
], [
'name' => 'active',
'title' => 'admin::app.admin.system.status',
'type' => 'boolean',
'validation' => 'required',
'channel_based' => false,
'locale_based' => true,
], [
'name' => 'is_calculate_tax',
'title' => 'admin::app.admin.system.calculate-tax',
'type' => 'boolean',
'validation' => 'required',
'channel_based' => false,
'locale_based' => false,
],
],
],
];

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
{
"/js/shop.js": "/js/shop.js?id=081e6c585ea2bde54421",
"/css/shop.css": "/css/shop.css?id=ff2ffa89e3bbaf07953d"
"/css/shop.css": "/css/shop.css?id=b8a554b90754154b6a86"
}

View File

@ -3,25 +3,25 @@
namespace Webkul\Shop\Http\Controllers;
use Illuminate\Support\Facades\Event;
use Webkul\Shop\Http\Controllers\Controller;
use Webkul\Checkout\Facades\Cart;
use Webkul\Shipping\Facades\Shipping;
use Webkul\Payment\Facades\Payment;
use Webkul\Checkout\Http\Requests\CustomerAddressForm;
use Webkul\Sales\Repositories\OrderRepository;
use Webkul\Customer\Repositories\CustomerRepository;
use Webkul\Payment\Facades\Payment;
use Webkul\Sales\Repositories\OrderRepository;
use Webkul\Shipping\Facades\Shipping;
use Webkul\Shop\Http\Controllers\Controller;
class OnepageController extends Controller
{
/**
* OrderRepository object
* Order repository instance.
*
* @var \Webkul\Sales\Repositories\OrderRepository
*/
protected $orderRepository;
/**
* customerRepository instance object
/**
* Customer repository instance.
*
* @var \Webkul\Customer\Repositories\CustomerRepository
*/
@ -37,8 +37,7 @@ class OnepageController extends Controller
public function __construct(
OrderRepository $orderRepository,
CustomerRepository $customerRepository
)
{
) {
$this->orderRepository = $orderRepository;
$this->customerRepository = $customerRepository;
@ -50,27 +49,31 @@ class OnepageController extends Controller
* Display a listing of the resource.
*
* @return \Illuminate\View\View
*/
*/
public function index()
{
Event::dispatch('checkout.load.index');
if (! auth()->guard('customer')->check()
&& ! core()->getConfigData('catalog.products.guest-checkout.allow-guest-checkout')) {
if (! auth()->guard('customer')->check() && ! core()->getConfigData('catalog.products.guest-checkout.allow-guest-checkout')) {
return redirect()->route('customer.session.index');
}
if (auth()->guard('customer')->check() && auth()->guard('customer')->user()->is_suspended) {
session()->flash('warning', trans('shop::app.checkout.cart.suspended-account-message'));
return redirect()->route('shop.checkout.cart.index');
}
if (Cart::hasError()) {
return redirect()->route('shop.checkout.cart.index');
}
$cart = Cart::getCart();
if (! auth()->guard('customer')->check() && $cart->hasDownloadableItems()) {
return redirect()->route('customer.session.index');
}
if (! auth()->guard('customer')->check() && ! $cart->hasGuestCheckoutItems()) {
if (
(! auth()->guard('customer')->check() && $cart->hasDownloadableItems())
|| (! auth()->guard('customer')->check() && ! $cart->hasGuestCheckoutItems())
) {
return redirect()->route('customer.session.index');
}
@ -88,10 +91,10 @@ class OnepageController extends Controller
}
/**
* Return order short summary
* Return order short summary.
*
* @return \Illuminate\Http\Response
*/
*/
public function summary()
{
$cart = Cart::getCart();
@ -106,10 +109,10 @@ class OnepageController extends Controller
*
* @param \Webkul\Checkout\Http\Requests\CustomerAddressForm $request
* @return \Illuminate\Http\Response
*/
*/
public function saveAddress(CustomerAddressForm $request)
{
$data = request()->all();
$data = $request->all();
if (! auth()->guard('customer')->check() && ! Cart::getCart()->hasGuestCheckoutItems()) {
return response()->json(['redirect_url' => route('customer.session.index')], 403);
@ -120,33 +123,33 @@ class OnepageController extends Controller
if (Cart::hasError() || ! Cart::saveCustomerAddress($data)) {
return response()->json(['redirect_url' => route('shop.checkout.cart.index')], 403);
} else {
$cart = Cart::getCart();
Cart::collectTotals();
if ($cart->haveStockableItems()) {
if (! $rates = Shipping::collectRates()) {
return response()->json(['redirect_url' => route('shop.checkout.cart.index')], 403);
} else {
return response()->json($rates);
}
} else {
return response()->json(Payment::getSupportedPaymentMethods());
}
}
$cart = Cart::getCart();
Cart::collectTotals();
if ($cart->haveStockableItems()) {
if (! $rates = Shipping::collectRates()) {
return response()->json(['redirect_url' => route('shop.checkout.cart.index')], 403);
}
return response()->json($rates);
}
return response()->json(Payment::getSupportedPaymentMethods());
}
/**
* Saves shipping method.
*
* @return \Illuminate\Http\Response
*/
*/
public function saveShipping()
{
$shippingMethod = request()->get('shipping_method');
if (Cart::hasError() || !$shippingMethod || !Cart::saveShippingMethod($shippingMethod)) {
if (Cart::hasError() || ! $shippingMethod || ! Cart::saveShippingMethod($shippingMethod)) {
return response()->json(['redirect_url' => route('shop.checkout.cart.index')], 403);
}
@ -159,7 +162,7 @@ class OnepageController extends Controller
* Saves payment method.
*
* @return \Illuminate\Http\Response
*/
*/
public function savePayment()
{
$payment = request()->get('payment');
@ -182,7 +185,7 @@ class OnepageController extends Controller
* Saves order.
*
* @return \Illuminate\Http\Response
*/
*/
public function saveOrder()
{
if (Cart::hasError()) {
@ -216,10 +219,10 @@ class OnepageController extends Controller
}
/**
* Order success page
* Order success page.
*
* @return \Illuminate\Http\Response
*/
*/
public function success()
{
if (! $order = session('order')) {
@ -230,7 +233,7 @@ class OnepageController extends Controller
}
/**
* Validate order before creation
* Validate order before creation.
*
* @return void|\Exception
*/
@ -240,54 +243,58 @@ class OnepageController extends Controller
$minimumOrderAmount = core()->getConfigData('sales.orderSettings.minimum-order.minimum_order_amount') ?? 0;
if (auth()->guard('customer')->check() && auth()->guard('customer')->user()->is_suspended) {
throw new \Exception(trans('shop::app.checkout.cart.suspended-account-message'));
}
if (! $cart->checkMinimumOrder()) {
throw new \Exception(trans('shop::app.checkout.cart.minimum-order-message', ['amount' => core()->currency($minimumOrderAmount)]));
}
if ($cart->haveStockableItems() && ! $cart->shipping_address) {
throw new \Exception(trans('Please check shipping address.'));
throw new \Exception(trans('shop::app.checkout.cart.check-shipping-address'));
}
if (! $cart->billing_address) {
throw new \Exception(trans('Please check billing address.'));
throw new \Exception(trans('shop::app.checkout.cart.check-billing-address'));
}
if ($cart->haveStockableItems() && ! $cart->selected_shipping_rate) {
throw new \Exception(trans('Please specify shipping method.'));
throw new \Exception(trans('shop::app.checkout.cart.specify-shipping-method'));
}
if (! $cart->payment) {
throw new \Exception(trans('Please specify payment method.'));
throw new \Exception(trans('shop::app.checkout.cart.specify-payment-method'));
}
}
/**
* Check Customer is exist or not
* Check customer is exist or not.
*
* @return \Illuminate\Http\Response
*/
public function checkExistCustomer()
{
$customer = $this->customerRepository->findOneWhere([
$customer = $this->customerRepository->findOneWhere([
'email' => request()->email,
]);
]);
if (! is_null($customer)) {
return 'true';
}
if (! is_null($customer)) {
return 'true';
}
return 'false';
return 'false';
}
/**
* Login for checkout
* Login for checkout.
*
* @return \Illuminate\Http\Response
*/
public function loginForCheckout()
{
$this->validate(request(), [
'email' => 'required|email'
'email' => 'required|email',
]);
if (! auth()->guard('customer')->attempt(request(['email', 'password']))) {
@ -300,7 +307,7 @@ class OnepageController extends Controller
}
/**
* To apply couponable rule requested
* To apply couponable rule requested.
*
* @return \Illuminate\Http\Response
*/
@ -322,19 +329,17 @@ class OnepageController extends Controller
'message' => trans('shop::app.checkout.total.coupon-applied'),
'result' => $result,
], 200);
} else {
return response()->json([
'success' => false,
'message' => trans('shop::app.checkout.total.cannot-apply-coupon'),
'result' => null,
], 422);
}
return $result;
return response()->json([
'success' => false,
'message' => trans('shop::app.checkout.total.cannot-apply-coupon'),
'result' => null,
], 422);
}
/**
* Initiates the removal of couponable cart rule
* Initiates the removal of couponable cart rule.
*
* @return array
*/
@ -352,13 +357,13 @@ class OnepageController extends Controller
'grand_total' => core()->currency(Cart::getCart()->grand_total),
],
], 200);
} else {
return response()->json([
'success' => false,
'message' => trans('admin::app.promotion.status.coupon-remove-failed'),
'data' => null,
], 422);
}
return response()->json([
'success' => false,
'message' => trans('admin::app.promotion.status.coupon-remove-failed'),
'data' => null,
], 422);
}
/**
@ -373,8 +378,8 @@ class OnepageController extends Controller
$status = Cart::checkMinimumOrder();
return response()->json([
'status' => ! $status ? false : true,
'status' => ! $status ? false : true,
'message' => ! $status ? trans('shop::app.checkout.cart.minimum-order-message', ['amount' => core()->currency($minimumOrderAmount)]) : 'Success',
]);
}
}
}

View File

@ -3796,7 +3796,8 @@ ol.breadcrumb {
.account-head {
display: flex;
justify-content: space-between;
justify-content: inherit;
column-gap: 10px;
border-bottom: 1px solid $border-color;
border-top: 1px solid $border-color;
height: 50px;

View File

@ -514,7 +514,7 @@ return [
'error' => 'لا يستطيع تحديث عنصر s في الوقت الحالي رجاء حاول ثانية لاحقا',
],
'item' => [
'item' => [
'error_remove' => 'لا عناصر لإزالتها من العربة',
'success' => 'تم بنجاح إضافة العنصر إلى العربة',
'success-remove' => 'تم إزالة العنصر بنجاح من العربة',
@ -522,15 +522,20 @@ return [
'inactive' => 'An item is inactive and was removed from cart',
'inactive-add' => 'Inactive item cannot be added to cart',
],
'quantity-error' => 'الكمية المطلوبة غير متوفرة',
'cart-subtotal' => 'المجموع الفرعي للمشتريات',
'cart-remove-action' => 'هل تريد حقا أن تسمح هذا ؟',
'partial-cart-update' => 'تم تحديث بعض المنتجات.',
'link-missing' => '',
'event' => [
'quantity-error' => 'الكمية المطلوبة غير متوفرة',
'cart-subtotal' => 'المجموع الفرعي للمشتريات',
'cart-remove-action' => 'هل تريد حقا أن تسمح هذا ؟',
'partial-cart-update' => 'تم تحديث بعض المنتجات.',
'link-missing' => '',
'event' => [
'expired' => 'This event has been expired.',
],
'minimum-order-message' => 'الحد الأدنى لمبلغ الطلب هو :amount',
'minimum-order-message' => 'الحد الأدنى لمبلغ الطلب هو :amount',
'suspended-account-message' => 'Your account has been suspended.',
'check-shipping-address' => 'Please check shipping address.',
'check-billing-address' => 'Please check billing address.',
'specify-shipping-method' => 'Please specify shipping method.',
'specify-payment-method' => 'Please specify payment method.',
],
'onepage' => [

View File

@ -511,7 +511,7 @@ return [
'error' => 'Die Elemente können derzeit nicht aktualisiert werden. Bitte versuchen Sie es später erneut.',
],
'item' => [
'item' => [
'error_remove' => 'Keine Artikel aus dem Warenkorb zu entfernen',
'success' => 'Artikel wurde erfolgreich zum Warenkorb hinzugefügt',
'success-remove' => 'Artikel wurde erfolgreich aus dem Warenkorb entfernt',
@ -519,12 +519,17 @@ return [
'inactive' => 'Ein Artikel ist inaktiv und wurde aus dem Warenkorb entfernt.',
'inactive-add' => 'Ein inaktiver Artikel kann nicht zum Warenkorb hinzugefügt werde.',
],
'quantity-error' => 'Die angeforderte Menge ist nicht verfügbar',
'cart-subtotal' => 'Warenkorb Zwischensumme',
'cart-remove-action' => 'Wollen Sie dies wirklich tun?',
'partial-cart-update' => 'Nur einige der Produkte wurden aktualisiert',
'link-missing' => '',
'minimum-order-message' => 'Mindestbestellmenge ist :amount',
'quantity-error' => 'Die angeforderte Menge ist nicht verfügbar',
'cart-subtotal' => 'Warenkorb Zwischensumme',
'cart-remove-action' => 'Wollen Sie dies wirklich tun?',
'partial-cart-update' => 'Nur einige der Produkte wurden aktualisiert',
'link-missing' => '',
'minimum-order-message' => 'Mindestbestellmenge ist :amount',
'suspended-account-message' => 'Your account has been suspended.',
'check-shipping-address' => 'Please check shipping address.',
'check-billing-address' => 'Please check billing address.',
'specify-shipping-method' => 'Please specify shipping method.',
'specify-payment-method' => 'Please specify payment method.',
],
'onepage' => [

View File

@ -479,45 +479,40 @@ return [
'tax-inclusive' => 'Inclusive of all taxes',
],
// 'reviews' => [
// 'empty' => 'You Have Not Reviewed Any Of Product Yet'
// ]
'buynow' => [
'no-options' => 'Please select options before buying this product.',
],
'checkout' => [
'cart' => [
'integrity' => [
'integrity' => [
'missing_fields' => 'Some required fields missing for this product.',
'missing_options' => 'Options are missing for this product.',
'missing_links' => 'Downloadable links are missing for this product.',
'qty_missing' => 'Atleast one product should have more than 1 quantity.',
'qty_impossible' => 'Cannot add more than one of these products to cart.',
],
'create-error' => 'Encountered some issue while making cart instance.',
'title' => 'Shopping Cart',
'empty' => 'Your shopping cart is empty',
'update-cart' => 'Update Cart',
'continue-shopping' => 'Continue Shopping',
'continue-registration' => 'Continue Registration',
'proceed-to-checkout' => 'Proceed To Checkout',
'remove' => 'Remove',
'remove-link' => 'Remove',
'move-to-wishlist' => 'Move to Wishlist',
'move-to-wishlist-success' => 'Item moved to wishlist successfully.',
'move-to-wishlist-error' => 'Cannot move item to wishlist, please try again later.',
'add-config-warning' => 'Please select option before adding to cart.',
'quantity' => [
'create-error' => 'Encountered some issue while making cart instance.',
'title' => 'Shopping Cart',
'empty' => 'Your shopping cart is empty',
'update-cart' => 'Update Cart',
'continue-shopping' => 'Continue Shopping',
'continue-registration' => 'Continue Registration',
'proceed-to-checkout' => 'Proceed To Checkout',
'remove' => 'Remove',
'remove-link' => 'Remove',
'move-to-wishlist' => 'Move to Wishlist',
'move-to-wishlist-success' => 'Item moved to wishlist successfully.',
'move-to-wishlist-error' => 'Cannot move item to wishlist, please try again later.',
'add-config-warning' => 'Please select option before adding to cart.',
'quantity' => [
'quantity' => 'Quantity',
'success' => 'Cart Item(s) successfully updated.',
'illegal' => 'Quantity cannot be lesser than one.',
'inventory_warning' => 'The requested quantity is not available, please try again later.',
'error' => 'Cannot update the item(s) at the moment, please try again later.',
],
'item' => [
'item' => [
'error_remove' => 'No items to remove from the cart.',
'success' => 'Item is successfully added to cart.',
'success-remove' => 'Item is successfully removed from the cart.',
@ -525,15 +520,20 @@ return [
'inactive' => 'An item is inactive and was removed from cart.',
'inactive-add' => 'Inactive item cannot be added to cart.',
],
'quantity-error' => 'Requested quantity is not available.',
'cart-subtotal' => 'Cart Subtotal',
'cart-remove-action' => 'Do you really want to do this ?',
'partial-cart-update' => 'Only some of the product(s) were updated',
'link-missing' => '',
'event' => [
'quantity-error' => 'Requested quantity is not available.',
'cart-subtotal' => 'Cart Subtotal',
'cart-remove-action' => 'Do you really want to do this ?',
'partial-cart-update' => 'Only some of the product(s) were updated',
'link-missing' => '',
'event' => [
'expired' => 'This event has been expired.',
],
'minimum-order-message' => 'Minimum order amount is :amount',
'minimum-order-message' => 'Minimum order amount is :amount',
'suspended-account-message' => 'Your account has been suspended.',
'check-shipping-address' => 'Please check shipping address.',
'check-billing-address' => 'Please check billing address.',
'specify-shipping-method' => 'Please specify shipping method.',
'specify-payment-method' => 'Please specify payment method.',
],
'onepage' => [

View File

@ -487,34 +487,34 @@ return [
'checkout' => [
'cart' => [
'integrity' => [
'integrity' => [
'missing_fields' => 'Faltan algunos campos requeridos',
'missing_options' => 'Faltan opciones configurables del producto',
'missing_links' => 'Faltan enlaces descargables para este producto.',
'qty_missing' => 'Al menos un producto debe tener más de 1 cantidad.',
'qty_impossible' => 'No se pueden agregar más de uno de estos productos al carrito.',
],
'create-error' => 'Se encontraron problemas con el carrito de compra',
'title' => 'Carrito de la compra',
'empty' => 'Tu carrito está vacía',
'update-cart' => 'Actualizar carrito',
'continue-shopping' => 'Seguir comprando',
'continue-registration' => 'Daŭrigu Registradon',
'proceed-to-checkout' => 'Continuar con el pago',
'remove' => 'Eliminar',
'remove-link' => 'Eliminar',
'move-to-wishlist' => 'Mover a la lista de deseos',
'move-to-wishlist-success' => 'Artículo movido a la lista de deseos',
'move-to-wishlist-error' => 'El artículo no se puede añadir a la lista de deseos, por favor inténtalo más tarde',
'add-config-warning' => 'Por favor selecciona las opciones antes de añadir al carrito',
'quantity' => [
'create-error' => 'Se encontraron problemas con el carrito de compra',
'title' => 'Carrito de la compra',
'empty' => 'Tu carrito está vacía',
'update-cart' => 'Actualizar carrito',
'continue-shopping' => 'Seguir comprando',
'continue-registration' => 'Daŭrigu Registradon',
'proceed-to-checkout' => 'Continuar con el pago',
'remove' => 'Eliminar',
'remove-link' => 'Eliminar',
'move-to-wishlist' => 'Mover a la lista de deseos',
'move-to-wishlist-success' => 'Artículo movido a la lista de deseos',
'move-to-wishlist-error' => 'El artículo no se puede añadir a la lista de deseos, por favor inténtalo más tarde',
'add-config-warning' => 'Por favor selecciona las opciones antes de añadir al carrito',
'quantity' => [
'quantity' => 'Cantidad',
'success' => 'Carrito actualizada exitosamente',
'illegal' => 'La cantidad no puede ser menor que uno',
'inventory_warning' => 'La cantidad solicitada no está disponible, inténtelo más tarde',
'error' => 'No se pueden actualizar los artículos, inténtelo más tarde',
],
'item' => [
'item' => [
'error_remove' => 'No hay artículos que eliminar en el carrito',
'success' => 'El artículo se añadió al carrito',
'success-remove' => 'El artículo se eliminó del carrito',
@ -522,14 +522,19 @@ return [
'inactive' => 'Un artículo está inactivo y se eliminó del carrito.',
'inactive-add' => 'El artículo inactivo no se puede agregar al carrito',
],
'quantity-error' => 'La cantidad solicitada no está disponible',
'cart-subtotal' => 'Total parcial',
'cart-remove-action' => '¿Realmente quieres hacer esto?',
'partial-cart-update' => 'Solo algunos de los productos se han actualizado',
'event' => [
'quantity-error' => 'La cantidad solicitada no está disponible',
'cart-subtotal' => 'Total parcial',
'cart-remove-action' => '¿Realmente quieres hacer esto?',
'partial-cart-update' => 'Solo algunos de los productos se han actualizado',
'event' => [
'expired' => 'This event has been expired.',
],
'minimum-order-message' => 'La cantidad mínima de pedido es :amount',
'minimum-order-message' => 'La cantidad mínima de pedido es :amount',
'suspended-account-message' => 'Your account has been suspended.',
'check-shipping-address' => 'Please check shipping address.',
'check-billing-address' => 'Please check billing address.',
'specify-shipping-method' => 'Please specify shipping method.',
'specify-payment-method' => 'Please specify payment method.',
],
'onepage' => [

View File

@ -520,14 +520,19 @@ return [
'inactive-add' => 'Inactive item cannot be added to cart',
],
'quantity-error' => 'مقدار درخواستی در دسترس نیست',
'cart-subtotal' => 'سبد فرعی',
'cart-remove-action' => 'آیا واقعاً می خواهید این کار را انجام دهید؟',
'partial-cart-update' => 'فقط برخی از محصولات (های) به روز شده اند',
'event' => [
'quantity-error' => 'مقدار درخواستی در دسترس نیست',
'cart-subtotal' => 'سبد فرعی',
'cart-remove-action' => 'آیا واقعاً می خواهید این کار را انجام دهید؟',
'partial-cart-update' => 'فقط برخی از محصولات (های) به روز شده اند',
'event' => [
'expired' => 'This event has been expired.',
],
'minimum-order-message' => 'حداقل مقدار سفارش است :amount',
'minimum-order-message' => 'حداقل مقدار سفارش است :amount',
'suspended-account-message' => 'Your account has been suspended.',
'check-shipping-address' => 'Please check shipping address.',
'check-billing-address' => 'Please check billing address.',
'specify-shipping-method' => 'Please specify shipping method.',
'specify-payment-method' => 'Please specify payment method.',
],
'onepage' => [

View File

@ -530,7 +530,12 @@ return [
'expired' => 'Cet événement a expiré.',
],
'minimum-order-message' => 'Le montant minimum de commande est de :amount',
'minimum-order-message' => 'Le montant minimum de commande est de :amount',
'suspended-account-message' => 'Your account has been suspended.',
'check-shipping-address' => 'Please check shipping address.',
'check-billing-address' => 'Please check billing address.',
'specify-shipping-method' => 'Please specify shipping method.',
'specify-payment-method' => 'Please specify payment method.',
],
'onepage' => [

View File

@ -512,7 +512,7 @@ return [
'error' => 'Non è posibile aggiornare gli articoli al momento, prova ancora.',
],
'item' => [
'item' => [
'error_remove' => 'Nessun prodotto da rimuovere nel carrello.',
'success' => 'Prodotto aggiunto al carrello.',
'success-remove' => 'Prodotto rimosso dal carrello.',
@ -520,15 +520,20 @@ return [
'inactive' => 'An item is inactive and was removed from cart.',
'inactive-add' => 'Inactive item cannot be added to cart.',
],
'quantity-error' => 'La quantità richiesta non è disponibile.',
'cart-subtotal' => 'Subtotale Carrello',
'cart-remove-action' => 'Vuoi veramente farlo ?',
'partial-cart-update' => 'Solo alcuni dei prodotti sono stati aggiornati',
'link-missing' => '',
'event' => [
'quantity-error' => 'La quantità richiesta non è disponibile.',
'cart-subtotal' => 'Subtotale Carrello',
'cart-remove-action' => 'Vuoi veramente farlo ?',
'partial-cart-update' => 'Solo alcuni dei prodotti sono stati aggiornati',
'link-missing' => '',
'event' => [
'expired' => 'Questo evento è terminato.',
],
'minimum-order-message' => 'L\'importo minimo dell\'ordine è :amount',
'minimum-order-message' => 'L\'importo minimo dell\'ordine è :amount',
'suspended-account-message' => 'Your account has been suspended.',
'check-shipping-address' => 'Please check shipping address.',
'check-billing-address' => 'Please check billing address.',
'specify-shipping-method' => 'Please specify shipping method.',
'specify-payment-method' => 'Please specify payment method.',
],
'onepage' => [

View File

@ -449,34 +449,34 @@ return [
'checkout' => [
'cart' => [
'integrity' => [
'integrity' => [
'missing_fields' => '赤くなった項目を入力してください',
'missing_options' => 'Options are missing for this product.',
'missing_links' => 'Downloadable links are missing for this product.',
'qty_missing' => 'Atleast one product should have more than 1 quantity.',
'qty_impossible' => 'Cannot add more than one of these products to cart.',
],
'create-error' => 'カートで問題が発生しました',
'title' => 'カート',
'empty' => 'カートが空です。',
'update-cart' => 'カートを更新する',
'continue-shopping' => '買い物を続ける',
'continue-registration' => '登録を続ける',
'proceed-to-checkout' => '購入手続きに進む',
'remove' => '削除',
'remove-link' => '削除',
'move-to-wishlist' => 'お気に入りに移動する',
'move-to-wishlist-success' => 'アイテムがお気に入りに追加されました。',
'move-to-wishlist-error' => 'アイテムをお気に入りに追加することができませんでした。しばらくしてから再度お試し下さい。',
'add-config-warning' => 'カートに追加する前にオプションを選択してください',
'quantity' => [
'create-error' => 'カートで問題が発生しました',
'title' => 'カート',
'empty' => 'カートが空です。',
'update-cart' => 'カートを更新する',
'continue-shopping' => '買い物を続ける',
'continue-registration' => '登録を続ける',
'proceed-to-checkout' => '購入手続きに進む',
'remove' => '削除',
'remove-link' => '削除',
'move-to-wishlist' => 'お気に入りに移動する',
'move-to-wishlist-success' => 'アイテムがお気に入りに追加されました。',
'move-to-wishlist-error' => 'アイテムをお気に入りに追加することができませんでした。しばらくしてから再度お試し下さい。',
'add-config-warning' => 'カートに追加する前にオプションを選択してください',
'quantity' => [
'quantity' => '数量',
'success' => 'カートが更新されました。',
'illegal' => '数量を1以下にすることは出来ません。',
'inventory_warning' => 'ご希望の数量の在庫が現在ございません。しばらくしてから再度お試し下さい。現在在庫がございません。',
'error' => 'アイテムの更新が出来ませんでした。しばらくしてから再度お試し下さい。',
],
'item' => [
'item' => [
'error_remove' => 'カートに削除するアイテムがございません。',
'success' => 'アイテムがカートに追加されました。',
'success-remove' => 'アイテムがカートから削除されました。',
@ -484,12 +484,17 @@ return [
'inactive' => 'An item is inactive and was removed from cart',
'inactive-add' => 'Inactive item cannot be added to cart',
],
'quantity-error' => 'ご希望の数量の在庫が現在ございません。',
'cart-subtotal' => '小計',
'cart-remove-action' => '手続きを進めますか。',
'partial-cart-update' => 'Only some of the product(s) were updated',
'link-missing' => '',
'minimum-order-message' => '最小注文額は :amount',
'quantity-error' => 'ご希望の数量の在庫が現在ございません。',
'cart-subtotal' => '小計',
'cart-remove-action' => '手続きを進めますか。',
'partial-cart-update' => 'Only some of the product(s) were updated',
'link-missing' => '',
'minimum-order-message' => '最小注文額は :amount',
'suspended-account-message' => 'Your account has been suspended.',
'check-shipping-address' => 'Please check shipping address.',
'check-billing-address' => 'Please check billing address.',
'specify-shipping-method' => 'Please specify shipping method.',
'specify-payment-method' => 'Please specify payment method.',
],
'onepage' => [

View File

@ -519,7 +519,7 @@ return [
'error' => 'Kan de item (s) momenteel niet updaten. Probeer het later opnieuw.',
],
'item' => [
'item' => [
'error_remove' => 'Geen items om uit de winkelwagen te verwijderen.',
'success' => 'Artikel is succesvol toegevoegd aan winkelwagen.',
'success-remove' => 'Item is met succes uit de winkelwagen verwijderd.',
@ -527,15 +527,20 @@ return [
'inactive' => 'An item is inactive and was removed from cart.',
'inactive-add' => 'Inactive item cannot be added to cart.',
],
'quantity-error' => 'Gevraagde hoeveelheid is niet beschikbaar.',
'cart-subtotal' => 'Subtotaal',
'cart-remove-action' => 'Wil je dit echt doen?',
'partial-cart-update' => 'Slechts enkele van de producten zijn bijgewerkt',
'link-missing' => '',
'event' => [
'quantity-error' => 'Gevraagde hoeveelheid is niet beschikbaar.',
'cart-subtotal' => 'Subtotaal',
'cart-remove-action' => 'Wil je dit echt doen?',
'partial-cart-update' => 'Slechts enkele van de producten zijn bijgewerkt',
'link-missing' => '',
'event' => [
'expired' => 'This event has been expired.',
],
'minimum-order-message' => 'Minimum orderbedrag is :amount',
'minimum-order-message' => 'Minimum orderbedrag is :amount',
'suspended-account-message' => 'Your account has been suspended.',
'check-shipping-address' => 'Please check shipping address.',
'check-billing-address' => 'Please check billing address.',
'specify-shipping-method' => 'Please specify shipping method.',
'specify-payment-method' => 'Please specify payment method.',
],
'onepage' => [

View File

@ -512,7 +512,7 @@ return [
'error' => 'W tej chwili nie można zaktualizować produktów. Spróbuj ponownie później.',
],
'item' => [
'item' => [
'error_remove' => 'Brak produktów do usunięcia z koszyka.',
'success' => 'Produkt został pomyślnie dodany do koszyka.',
'success-remove' => 'Produkt został pomyślnie usunięty z koszyka.',
@ -520,14 +520,19 @@ return [
'inactive' => 'An item is inactive and was removed from cart.',
'inactive-add' => 'Inactive item cannot be added to cart.',
],
'quantity-error' => 'Żądana ilość nie jest dostępna.',
'cart-subtotal' => 'Suma częściowa koszyka',
'cart-remove-action' => 'Czy na pewno chcesz to zrobić ?',
'partial-cart-update' => 'Tylko niektóre produkty zostały zaktualizowane',
'event' => [
'quantity-error' => 'Żądana ilość nie jest dostępna.',
'cart-subtotal' => 'Suma częściowa koszyka',
'cart-remove-action' => 'Czy na pewno chcesz to zrobić ?',
'partial-cart-update' => 'Tylko niektóre produkty zostały zaktualizowane',
'event' => [
'expired' => 'To wydarzenie wygasło.',
],
'minimum-order-message' => 'Minimalna kwota zamówienia to :amount',
'minimum-order-message' => 'Minimalna kwota zamówienia to :amount',
'suspended-account-message' => 'Your account has been suspended.',
'check-shipping-address' => 'Please check shipping address.',
'check-billing-address' => 'Please check billing address.',
'specify-shipping-method' => 'Please specify shipping method.',
'specify-payment-method' => 'Please specify payment method.',
],
'onepage' => [

View File

@ -503,7 +503,7 @@ return [
'error' => 'Não é possível atualizar o item(s) no momento, por favor, tente novamente mais tarde',
],
'item' => [
'item' => [
'error_remove' => 'Nenhum item para remover do carrinho',
'success' => 'Item foi adicionado com sucesso ao carrinho',
'success-remove' => 'Item foi removido com sucesso do carrinho',
@ -511,15 +511,20 @@ return [
'inactive' => 'An item is inactive and was removed from cart',
'inactive-add' => 'Inactive item cannot be added to cart',
],
'quantity-error' => 'Quantidade solicitada não está disponível',
'cart-subtotal' => 'Subtotal do carrinho',
'cart-remove-action' => 'Você realmente quer fazer isso ?',
'partial-cart-update' => 'Only some of the product(s) were updated',
'link-missing' => '',
'event' => [
'quantity-error' => 'Quantidade solicitada não está disponível',
'cart-subtotal' => 'Subtotal do carrinho',
'cart-remove-action' => 'Você realmente quer fazer isso ?',
'partial-cart-update' => 'Only some of the product(s) were updated',
'link-missing' => '',
'event' => [
'expired' => 'This event has been expired.',
],
'minimum-order-message' => 'O valor mínimo do pedido é :amount',
'minimum-order-message' => 'O valor mínimo do pedido é :amount',
'suspended-account-message' => 'Your account has been suspended.',
'check-shipping-address' => 'Please check shipping address.',
'check-billing-address' => 'Please check billing address.',
'specify-shipping-method' => 'Please specify shipping method.',
'specify-payment-method' => 'Please specify payment method.',
],
'onepage' => [

View File

@ -512,7 +512,7 @@ return [
'error' => 'Ürün güncellemesi yapılamıyor, lütfen tekrar deneyin.',
],
'item' => [
'item' => [
'error_remove' => 'Sepetten kaldırılacak ürün bulunamadı.',
'success' => 'Ürün başarıyla sepete eklendi.',
'success-remove' => 'Ürün sepetten başarıyla kaldırıldı.',
@ -520,15 +520,20 @@ return [
'inactive' => 'An item is inactive and was removed from cart.',
'inactive-add' => 'Inactive item cannot be added to cart.',
],
'quantity-error' => 'Girilen miktar mevcut değil.',
'cart-subtotal' => 'Sepet Ara Toplam',
'cart-remove-action' => 'Sepeti boşaltmak istediğinizden emin misiniz?',
'partial-cart-update' => 'Sadece bazı ürünler güncellendi.',
'link-missing' => '',
'event' => [
'quantity-error' => 'Girilen miktar mevcut değil.',
'cart-subtotal' => 'Sepet Ara Toplam',
'cart-remove-action' => 'Sepeti boşaltmak istediğinizden emin misiniz?',
'partial-cart-update' => 'Sadece bazı ürünler güncellendi.',
'link-missing' => '',
'event' => [
'expired' => 'Bu eylemin geçerliliği sona erdi.',
],
'minimum-order-message' => 'Minimum order amount is :amount',
'minimum-order-message' => 'Minimum order amount is :amount',
'suspended-account-message' => 'Your account has been suspended.',
'check-shipping-address' => 'Please check shipping address.',
'check-billing-address' => 'Please check billing address.',
'specify-shipping-method' => 'Please specify shipping method.',
'specify-payment-method' => 'Please specify payment method.',
],
'onepage' => [

View File

@ -17,6 +17,7 @@
<ul class="checkout-steps">
<li class="active" :class="[completed_step >= 0 ? 'active' : '', completed_step > 0 ? 'completed' : '']" @click="navigateToStep(1)">
<div class="decorator address-info"></div>
<span>{{ __('shop::app.checkout.onepage.information') }}</span>
</li>
@ -25,6 +26,7 @@
@if ($cart->haveStockableItems())
<li :class="[current_step == 2 || completed_step > 1 ? 'active' : '', completed_step > 1 ? 'completed' : '']" @click="navigateToStep(2)">
<div class="decorator shipping"></div>
<span>{{ __('shop::app.checkout.onepage.shipping') }}</span>
</li>
@ -33,6 +35,7 @@
<li :class="[current_step == 3 || completed_step > 2 ? 'active' : '', completed_step > 2 ? 'completed' : '']" @click="navigateToStep(3)">
<div class="decorator payment"></div>
<span>{{ __('shop::app.checkout.onepage.payment') }}</span>
</li>
@ -61,7 +64,6 @@
<button type="button" class="btn btn-lg btn-primary" @click="validateForm('shipping-form')" :disabled="disable_button" id="checkout-shipping-continue-button">
{{ __('shop::app.checkout.onepage.continue') }}
</button>
</div>
</div>
@ -104,13 +106,13 @@
</script>
<script>
var shippingHtml = '';
var paymentHtml = '';
var reviewHtml = '';
var summaryHtml = '';
var customerAddress = '';
var shippingMethods = '';
var paymentMethods = '';
let shippingHtml = '';
let paymentHtml = '';
let reviewHtml = '';
let summaryHtml = '';
let customerAddress = '';
let shippingMethods = '';
let paymentMethods = '';
@auth('customer')
@if(auth('customer')->user()->addresses)
@ -190,16 +192,6 @@
this.new_billing_address = true;
} else {
this.allAddress = customerAddress;
for (var country in this.country) {
for (var code in this.allAddress) {
if (this.allAddress[code].country) {
if (this.allAddress[code].country == this.country[country].code) {
this.allAddress[code]['country'] = this.country[country].name;
}
}
}
}
}
}
},
@ -220,16 +212,16 @@
},
validateForm: async function(scope) {
var this_this = this;
let self = this;
await this.$validator.validateAll(scope).then(function (result) {
if (result) {
if (scope == 'address-form') {
this_this.saveAddress();
self.saveAddress();
} else if (scope == 'shipping-form') {
this_this.saveShipping();
self.saveShipping();
} else if (scope == 'payment-form') {
this_this.savePayment();
self.savePayment();
}
}
});
@ -238,16 +230,16 @@
isCustomerExist: function() {
this.$validator.attach({ name: "email", rules: "required|email" });
var this_this = this;
let self = this;
this.$validator.validate('email', this.address.billing.email)
.then(function(isValid) {
if (! isValid)
return;
this_this.$http.post("{{ route('customer.checkout.exist') }}", {email: this_this.address.billing.email})
self.$http.post("{{ route('customer.checkout.exist') }}", {email: self.address.billing.email})
.then(function(response) {
this_this.is_customer_exist = response.data ? 1 : 0;
self.is_customer_exist = response.data ? 1 : 0;
})
.catch(function (error) {})
@ -255,11 +247,11 @@
},
loginCustomer: function() {
var this_this = this;
let self = this;
this_this.$http.post("{{ route('customer.checkout.login') }}", {
email: this_this.address.billing.email,
password: this_this.address.billing.password
self.$http.post("{{ route('customer.checkout.login') }}", {
email: self.address.billing.email,
password: self.address.billing.password
})
.then(function(response) {
if (response.data.success) {
@ -267,27 +259,26 @@
} else {
window.flashMessages = [{'type': 'alert-error', 'message': response.data.error }];
this_this.$root.addFlashMessages()
self.$root.addFlashMessages()
}
})
.catch(function (error) {})
},
getOrderSummary () {
var this_this = this;
let self = this;
this.$http.get("{{ route('shop.checkout.summary') }}")
.then(function(response) {
summaryHtml = Vue.compile(response.data.html)
this_this.summeryComponentKey++;
//this_this.reviewComponentKey++;
self.summeryComponentKey++;
})
.catch(function (error) {})
},
saveAddress: async function() {
var this_this = this;
let self = this;
this.disable_button = true;
@ -305,76 +296,76 @@
this.$http.post("{{ route('shop.checkout.save-address') }}", this.address)
.then(function(response) {
this_this.disable_button = false;
self.disable_button = false;
if (this_this.step_numbers[response.data.jump_to_section] == 2)
if (self.step_numbers[response.data.jump_to_section] == 2)
shippingHtml = Vue.compile(response.data.html)
else
paymentHtml = Vue.compile(response.data.html)
this_this.completed_step = this_this.step_numbers[response.data.jump_to_section] - 1;
this_this.current_step = this_this.step_numbers[response.data.jump_to_section];
self.completed_step = self.step_numbers[response.data.jump_to_section] - 1;
self.current_step = self.step_numbers[response.data.jump_to_section];
shippingMethods = response.data.shippingMethods;
paymentMethods = response.data.paymentMethods;
this_this.getOrderSummary();
self.getOrderSummary();
})
.catch(function (error) {
this_this.disable_button = false;
self.disable_button = false;
this_this.handleErrorResponse(error.response, 'address-form')
self.handleErrorResponse(error.response, 'address-form')
})
},
saveShipping: async function() {
var this_this = this;
let self = this;
this.disable_button = true;
this.$http.post("{{ route('shop.checkout.save-shipping') }}", {'shipping_method': this.selected_shipping_method})
.then(function(response) {
this_this.disable_button = false;
self.disable_button = false;
paymentHtml = Vue.compile(response.data.html)
this_this.completed_step = this_this.step_numbers[response.data.jump_to_section] - 1;
this_this.current_step = this_this.step_numbers[response.data.jump_to_section];
self.completed_step = self.step_numbers[response.data.jump_to_section] - 1;
self.current_step = self.step_numbers[response.data.jump_to_section];
paymentMethods = response.data.paymentMethods;
this_this.getOrderSummary();
self.getOrderSummary();
})
.catch(function (error) {
this_this.disable_button = false;
self.disable_button = false;
this_this.handleErrorResponse(error.response, 'shipping-form')
self.handleErrorResponse(error.response, 'shipping-form')
})
},
savePayment: async function() {
var this_this = this;
let self = this;
this.disable_button = true;
this.$http.post("{{ route('shop.checkout.save-payment') }}", {'payment': this.selected_payment_method})
.then(function(response) {
this_this.disable_button = false;
self.disable_button = false;
reviewHtml = Vue.compile(response.data.html)
this_this.completed_step = this_this.step_numbers[response.data.jump_to_section] - 1;
this_this.current_step = this_this.step_numbers[response.data.jump_to_section];
self.completed_step = self.step_numbers[response.data.jump_to_section] - 1;
self.current_step = self.step_numbers[response.data.jump_to_section];
this_this.getOrderSummary();
self.getOrderSummary();
})
.catch(function (error) {
this_this.disable_button = false;
self.disable_button = false;
this_this.handleErrorResponse(error.response, 'payment-form')
self.handleErrorResponse(error.response, 'payment-form')
});
},
placeOrder: async function() {
var this_this = this;
let self = this;
this.disable_button = true;
@ -389,11 +380,11 @@
}
})
.catch(function (error) {
this_this.disable_button = true;
self.disable_button = true;
window.flashMessages = [{'type': 'alert-error', 'message': "{{ __('shop::app.common.error') }}" }];
this_this.$root.addFlashMessages()
self.$root.addFlashMessages()
})
},
@ -434,9 +425,9 @@
this.new_shipping_address = false;
},
}
})
});
var shippingTemplateRenderFns = [];
let shippingTemplateRenderFns = [];
Vue.component('shipping-section', {
inject: ['$validator'],
@ -465,7 +456,7 @@
}
this.templateRender = shippingHtml.render;
for (var i in shippingHtml.staticRenderFns) {
for (let i in shippingHtml.staticRenderFns) {
shippingTemplateRenderFns.push(shippingHtml.staticRenderFns[i]);
}
@ -487,9 +478,9 @@
eventBus.$emit('after-shipping-method-selected', this.selected_shipping_method);
}
}
})
});
var paymentTemplateRenderFns = [];
let paymentTemplateRenderFns = [];
Vue.component('payment-section', {
inject: ['$validator'],
@ -518,7 +509,7 @@
}
this.templateRender = paymentHtml.render;
for (var i in paymentHtml.staticRenderFns) {
for (let i in paymentHtml.staticRenderFns) {
paymentTemplateRenderFns.push(paymentHtml.staticRenderFns[i]);
}
@ -542,9 +533,9 @@
eventBus.$emit('after-payment-method-selected', this.payment);
}
}
})
});
var reviewTemplateRenderFns = [];
let reviewTemplateRenderFns = [];
Vue.component('review-section', {
data: function() {
@ -568,8 +559,7 @@
mounted: function() {
this.templateRender = reviewHtml.render;
for (var i in reviewHtml.staticRenderFns) {
// reviewTemplateRenderFns.push(reviewHtml.staticRenderFns[i]);
for (let i in reviewHtml.staticRenderFns) {
reviewTemplateRenderFns[i] = reviewHtml.staticRenderFns[i];
}
@ -577,8 +567,7 @@
}
});
var summaryTemplateRenderFns = [];
let summaryTemplateRenderFns = [];
Vue.component('summary-section', {
inject: ['$validator'],
@ -594,8 +583,7 @@
mounted: function() {
this.templateRender = summaryHtml.render;
for (var i in summaryHtml.staticRenderFns) {
// summaryTemplateRenderFns.push(summaryHtml.staticRenderFns[i]);
for (let i in summaryHtml.staticRenderFns) {
summaryTemplateRenderFns[i] = summaryHtml.staticRenderFns[i];
}
@ -609,7 +597,6 @@
'')
]);
}
})
});
</script>
@endpush

View File

@ -6,7 +6,7 @@
</div>
<div class="control-group" id="login-and-forgot-btn">
<div class="forgot-password-link" style="float: right;margin-right: 503px; margin-top: 11px;">
<div class="forgot-password-link" style="float: right; margin-right: 503px; margin-top: 11px;">
<a href="{{ route('customer.forgot-password.create') }}">{{ __('shop::app.customer.login-form.forgot_pass') }}</a>
<div class="mt-10">

View File

@ -1,56 +1,59 @@
<form data-vv-scope="address-form">
<div class="form-container" v-if="!this.new_billing_address">
<div class="form-container" v-if="! this.new_billing_address">
<div class="form-header mb-30">
<span class="checkout-step-heading">{{ __('shop::app.checkout.onepage.billing-address') }}</span>
<a class="btn btn-lg btn-primary" @click = newBillingAddress()>
<a class="btn btn-lg btn-primary" @click="newBillingAddress()">
{{ __('shop::app.checkout.onepage.new-address') }}
</a>
</div>
<div class="address-holder">
<div class="address-card" v-for='(addresses, index) in this.allAddress'>
<div class="checkout-address-content" style="display: flex; flex-direction: row; justify-content: space-between; width: 100%;">
<label class="radio-container" style="float: right; width: 10%;">
<input type="radio" v-validate="'required'" id="billing[address_id]" name="billing[address_id]" :value="addresses.id" v-model="address.billing.address_id" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.billing-address') }}&quot;">
<span class="checkmark"></span>
</label>
<ul class="address-card-list" style="float: right; width: 85%;">
<li class="mb-5" v-if="addresses.company_name != ''">
@{{ addresses.company_name }}
</li>
<li class="mb-10">
<b>@{{ allAddress.first_name }} @{{ allAddress.last_name }},</b>
<b v-text="`${allAddress.first_name} ${allAddress.last_name}`"></b>
</li>
<li class="mb-5">
@{{ addresses.address1 }},
<li
class="mb-5"
v-text="addresses.company_name"
v-if="addresses.company_name != ''">
</li>
<li class="mb-5">
@{{ addresses.city }},
</li>
<li class="mb-5" v-text="addresses.address1"></li>
<li class="mb-5">
@{{ addresses.state }},
</li>
<li class="mb-5" v-text="addresses.city"></li>
<li class="mb-5" v-text="addresses.state"></li>
<li class="mb-15">
@{{ addresses.country }} @{{ addresses.postcode }}
<span v-text="addresses.country" v-if="addresses.country"></span>
<span v-text="addresses.postcode" v-if="addresses.postcode"></span>
</li>
<li>
<b>{{ __('shop::app.customer.account.address.index.contact') }}</b> : @{{ addresses.phone }}
<b>{{ __('shop::app.customer.account.address.index.contact') }}</b> :
<span v-text="addresses.phone"></span>
</li>
</ul>
</div>
</div>
<div id="message"></div>
<div class="control-group" :class="[errors.has('address-form.billing[address_id]') ? 'has-error' : '']">
<span class="control-error" v-if="errors.has('address-form.billing[address_id]')">
@{{ errors.first('address-form.billing[address_id]') }}
<span
class="control-error"
v-text="errors.first('address-form.billing[address_id]')"
v-if="errors.has('address-form.billing[address_id]')">
</span>
</div>
</div>
@ -60,6 +63,7 @@
<span class="checkbox">
<input type="checkbox" id="billing[use_for_shipping]" name="billing[use_for_shipping]" v-model="address.billing.use_for_shipping"/>
<label class="checkbox-view" for="billing[use_for_shipping]"></label>
{{ __('shop::app.checkout.onepage.use_for_shipping') }}
</span>
</div>
@ -67,13 +71,12 @@
</div>
<div class="form-container" v-if="this.new_billing_address">
<div class="form-header">
<h1>{{ __('shop::app.checkout.onepage.billing-address') }}</h1>
@auth('customer')
@if(count(auth('customer')->user()->addresses))
<a class="btn btn-lg btn-primary" @click = backToSavedBillingAddress()>
<a class="btn btn-lg btn-primary" @click="backToSavedBillingAddress()">
{{ __('shop::app.checkout.onepage.back') }}
</a>
@endif
@ -85,14 +88,23 @@
{{ __('shop::app.checkout.onepage.email') }}
</label>
<input type="text" v-validate="'required|email'" class="control" id="billing[email]" name="billing[email]" v-model="address.billing.email" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.email') }}&quot;" @blur="isCustomerExist"/>
<input
class="control"
id="billing[email]"
type="text"
name="billing[email]"
v-model="address.billing.email"
v-validate="'required|email'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.email') }}&quot;"
@blur="isCustomerExist"/>
<span class="control-error" v-if="errors.has('address-form.billing[email]')">
@{{ errors.first('address-form.billing[email]') }}
<span
class="control-error"
v-text="errors.first('address-form.billing[email]')"
v-if="errors.has('address-form.billing[email]')">
</span>
</div>
{{-- for customer login checkout --}}
@if (! auth()->guard('customer')->check())
@include('shop::checkout.onepage.customer-checkout')
@endif
@ -102,10 +114,18 @@
{{ __('shop::app.checkout.onepage.company-name') }}
</label>
<input type="text" class="control" id="billing[company_name]" name="billing[company_name]" v-model="address.billing.company_name" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.company-name') }}&quot;"/>
<input
class="control"
id="billing[company_name]"
type="text"
name="billing[company_name]"
v-model="address.billing.company_name"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.company-name') }}&quot;"/>
<span class="control-error" v-if="errors.has('address-form.billing[company_name]')">
@{{ errors.first('address-form.billing[company_name]') }}
<span
class="control-error"
v-text="errors.first('address-form.billing[company_name]')"
v-if="errors.has('address-form.billing[company_name]')">
</span>
</div>
@ -114,10 +134,19 @@
{{ __('shop::app.checkout.onepage.first-name') }}
</label>
<input type="text" v-validate="'required'" class="control" id="billing[first_name]" name="billing[first_name]" v-model="address.billing.first_name" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.first-name') }}&quot;"/>
<input
class="control"
id="billing[first_name]"
type="text"
name="billing[first_name]"
v-model="address.billing.first_name"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.first-name') }}&quot;"/>
<span class="control-error" v-if="errors.has('address-form.billing[first_name]')">
@{{ errors.first('address-form.billing[first_name]') }}
<span
class="control-error"
v-text="errors.first('address-form.billing[first_name]')"
v-if="errors.has('address-form.billing[first_name]')">
</span>
</div>
@ -126,10 +155,19 @@
{{ __('shop::app.checkout.onepage.last-name') }}
</label>
<input type="text" v-validate="'required'" class="control" id="billing[last_name]" name="billing[last_name]" v-model="address.billing.last_name" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.last-name') }}&quot;"/>
<input
class="control"
id="billing[last_name]"
type="text"
name="billing[last_name]"
v-model="address.billing.last_name"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.last-name') }}&quot;"/>
<span class="control-error" v-if="errors.has('address-form.billing[last_name]')">
@{{ errors.first('address-form.billing[last_name]') }}
<span
class="control-error"
v-text="errors.first('address-form.billing[last_name]')"
v-if="errors.has('address-form.billing[last_name]')">
</span>
</div>
@ -138,17 +176,31 @@
{{ __('shop::app.checkout.onepage.address1') }}
</label>
<input type="text" v-validate="'required'" class="control" id="billing_address_0" name="billing[address1][]" v-model="address.billing.address1[0]" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.address1') }}&quot;"/>
<input
class="control"
id="billing_address_0"
type="text"
name="billing[address1][]"
v-model="address.billing.address1[0]"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.address1') }}&quot;"/>
<span class="control-error" v-if="errors.has('address-form.billing[address1][]')">
@{{ errors.first('address-form.billing[address1][]') }}
<span
class="control-error"
v-text="errors.first('address-form.billing[address1][]')"
v-if="errors.has('address-form.billing[address1][]')">
</span>
</div>
@if (core()->getConfigData('customer.settings.address.street_lines') && core()->getConfigData('customer.settings.address.street_lines') > 1)
<div class="control-group" style="margin-top: -25px;">
@for ($i = 1; $i < core()->getConfigData('customer.settings.address.street_lines'); $i++)
<input type="text" class="control" name="billing[address1][{{ $i }}]" id="billing_address_{{ $i }}" v-model="address.billing.address1[{{$i}}]">
<input
class="control"
id="billing_address_{{ $i }}"
type="text"
name="billing[address1][{{ $i }}]"
v-model="address.billing.address1[{{$i}}]">
@endfor
</div>
@endif
@ -158,64 +210,102 @@
{{ __('shop::app.checkout.onepage.city') }}
</label>
<input type="text" v-validate="'required'" class="control" id="billing[city]" name="billing[city]" v-model="address.billing.city" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.city') }}&quot;"/>
<input
class="control"
id="billing[city]"
type="text"
name="billing[city]"
v-model="address.billing.city"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.city') }}&quot;"/>
<span class="control-error" v-if="errors.has('address-form.billing[city]')">
@{{ errors.first('address-form.billing[city]') }}
<span
class="control-error"
v-text="errors.first('address-form.billing[city]')"
v-if="errors.has('address-form.billing[city]')">
</span>
</div>
<div class="control-group" :class="[errors.has('address-form.billing[country]') ? 'has-error' : '']">
<label for="billing[country]" class="required">
<label for="billing[country]" class="{{ core()->isCountryRequired() ? 'required' : '' }}">
{{ __('shop::app.checkout.onepage.country') }}
</label>
<select type="text" v-validate="'required'" class="control" id="billing[country]" name="billing[country]" v-model="address.billing.country" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.country') }}&quot;">
<select
class="control"
id="billing[country]"
type="text"
name="billing[country]"
v-validate="'{{ core()->isCountryRequired() ? 'required' : '' }}'"
v-model="address.billing.country"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.country') }}&quot;">
<option value=""></option>
@foreach (core()->countries() as $country)
<option value="{{ $country->code }}">{{ $country->name }}</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('address-form.billing[country]')">
@{{ errors.first('address-form.billing[country]') }}
<span
class="control-error"
v-text="errors.first('address-form.billing[country]')"
v-if="errors.has('address-form.billing[country]')">
</span>
</div>
<div class="control-group" :class="[errors.has('address-form.billing[state]') ? 'has-error' : '']">
<label for="billing[state]" class="required">
<label for="billing[state]" class="{{ core()->isStateRequired() ? 'required' : '' }}">
{{ __('shop::app.checkout.onepage.state') }}
</label>
<input type="text" v-validate="'required'" class="control" id="billing[state]" name="billing[state]" v-model="address.billing.state" v-if="!haveStates('billing')" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.state') }}&quot;"/>
<select v-validate="'required'" class="control" id="billing[state]" name="billing[state]" v-model="address.billing.state" v-if="haveStates('billing')" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.state') }}&quot;">
<input
class="control"
id="billing[state]"
name="billing[state]"
type="text"
v-model="address.billing.state"
v-validate="'{{ core()->isStateRequired() ? 'required' : '' }}'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.state') }}&quot;"
v-if="! haveStates('billing')"/>
<select
class="control"
id="billing[state]"
name="billing[state]"
v-model="address.billing.state"
v-validate=""
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.state') }}&quot;"
v-if="haveStates('billing')">
<option value="">{{ __('shop::app.checkout.onepage.select-state') }}</option>
<option v-for='(state, index) in countryStates[address.billing.country]' :value="state.code">
@{{ state.default_name }}
</option>
<option v-for='(state, index) in countryStates[address.billing.country]' :value="state.code" v-text="state.default_name"></option>
</select>
<span class="control-error" v-if="errors.has('address-form.billing[state]')">
@{{ errors.first('address-form.billing[state]') }}
<span
class="control-error"
v-text="errors.first('address-form.billing[state]')"
v-if="errors.has('address-form.billing[state]')">
</span>
</div>
<div class="control-group" :class="[errors.has('address-form.billing[postcode]') ? 'has-error' : '']">
<label for="billing[postcode]" class="required">
<label for="billing[postcode]" class="{{ core()->isPostCodeRequired() ? 'required' : '' }}">
{{ __('shop::app.checkout.onepage.postcode') }}
</label>
<input type="text" v-validate="'required'" class="control" id="billing[postcode]" name="billing[postcode]" v-model="address.billing.postcode" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.postcode') }}&quot;"/>
<input
class="control"
id="billing[postcode]"
type="text"
name="billing[postcode]"
v-model="address.billing.postcode"
v-validate="'{{ core()->isPostCodeRequired() ? 'required' : '' }}'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.postcode') }}&quot;"/>
<span class="control-error" v-if="errors.has('address-form.billing[postcode]')">
@{{ errors.first('address-form.billing[postcode]') }}
<span
class="control-error"
v-text="errors.first('address-form.billing[postcode]')"
v-if="errors.has('address-form.billing[postcode]')">
</span>
</div>
@ -224,18 +314,32 @@
{{ __('shop::app.checkout.onepage.phone') }}
</label>
<input type="text" v-validate="'required|numeric'" class="control" id="billing[phone]" name="billing[phone]" v-model="address.billing.phone" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.phone') }}&quot;"/>
<input
class="control"
id="billing[phone]"
type="text"
name="billing[phone]"
v-validate="'required|numeric'"
v-model="address.billing.phone"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.phone') }}&quot;"/>
<span class="control-error" v-if="errors.has('address-form.billing[phone]')">
@{{ errors.first('address-form.billing[phone]') }}
</span>
<span
class="control-error"
v-text="errors.first('address-form.billing[phone]')"
v-if="errors.has('address-form.billing[phone]')"></span>
</div>
@if ($cart->haveStockableItems())
<div class="control-group">
<span class="checkbox">
<input type="checkbox" id="billing[use_for_shipping]" name="billing[use_for_shipping]" v-model="address.billing.use_for_shipping"/>
<input
id="billing[use_for_shipping]"
type="checkbox"
name="billing[use_for_shipping]"
v-model="address.billing.use_for_shipping"/>
<label class="checkbox-view" for="billing[use_for_shipping]"></label>
{{ __('shop::app.checkout.onepage.use_for_shipping') }}
</span>
</div>
@ -244,21 +348,26 @@
@auth('customer')
<div class="control-group">
<span class="checkbox">
<input type="checkbox" id="billing[save_as_address]" name="billing[save_as_address]" v-model="address.billing.save_as_address"/>
<input
id="billing[save_as_address]"
type="checkbox"
name="billing[save_as_address]"
v-model="address.billing.save_as_address"/>
<label class="checkbox-view" for="billing[save_as_address]"></label>
{{ __('shop::app.checkout.onepage.save_as_address') }}
</span>
</div>
@endauth
</div>
@if ($cart->haveStockableItems())
<div class="form-container" v-if="!address.billing.use_for_shipping && !this.new_shipping_address">
<div class="form-container" v-if="! address.billing.use_for_shipping && ! this.new_shipping_address">
<div class="form-header mb-30">
<span class="checkout-step-heading">{{ __('shop::app.checkout.onepage.shipping-address') }}</span>
<a class="btn btn-lg btn-primary" @click=newShippingAddress()>
<a class="btn btn-lg btn-primary" @click="newShippingAddress()">
{{ __('shop::app.checkout.onepage.new-address') }}
</a>
</div>
@ -267,59 +376,65 @@
<div class="address-card" v-for='(addresses, index) in this.allAddress'>
<div class="checkout-address-content" style="display: flex; flex-direction: row; justify-content: space-between; width: 100%;">
<label class="radio-container" style="float: right; width: 10%;">
<input v-validate="'required'" type="radio" id="shipping[address_id]" name="shipping[address_id]" v-model="address.shipping.address_id" :value="addresses.id"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.shipping-address') }}&quot;">
<input
id="shipping[address_id]"
type="radio"
name="shipping[address_id]"
:value="addresses.id"
v-model="address.shipping.address_id"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.shipping-address') }}&quot;">
<span class="checkmark"></span>
</label>
<ul class="address-card-list" style="float: right; width: 85%;">
<li class="mb-5" v-if="addresses.company_name != ''">
@{{ addresses.company_name }}
</li>
<li class="mb-10">
<b>@{{ addresses.first_name }} @{{ addresses.last_name }},</b>
<b v-text="`${addresses.first_name} ${addresses.last_name}`"></b>
</li>
<li class="mb-5">
@{{ addresses.address1 }},
<li
class="mb-5"
v-text="addresses.company_name"
v-if="addresses.company_name != ''">
</li>
<li class="mb-5">
@{{ addresses.city }},
</li>
<li class="mb-5" v-text="addresses.address1"></li>
<li class="mb-5">
@{{ addresses.state }},
</li>
<li class="mb-5" v-text="addresses.city"></li>
<li class="mb-5" v-text="addresses.state"></li>
<li class="mb-15">
@{{ addresses.country }} @{{ addresses.postcode }}
<span v-text="addresses.country" v-if="addresses.country"></span>
<span v-text="addresses.postcode" v-if="addresses.postcode"></span>
</li>
<li>
<b>{{ __('shop::app.customer.account.address.index.contact') }}</b> : @{{ addresses.phone }}
<b>{{ __('shop::app.customer.account.address.index.contact') }}</b> :
<span v-text="addresses.phone"></span>
</li>
</ul>
</div>
</div>
<div class="control-group" :class="[errors.has('address-form.shipping[address_id]') ? 'has-error' : '']">
<span class="control-error" v-if="errors.has('address-form.shipping[address_id]')">
@{{ errors.first('address-form.shipping[address_id]') }}
<span
class="control-error"
v-text="errors.first('address-form.shipping[address_id]')"
v-if="errors.has('address-form.shipping[address_id]')">
</span>
</div>
</div>
</div>
<div class="form-container" v-if="!address.billing.use_for_shipping && this.new_shipping_address">
<div class="form-container" v-if="! address.billing.use_for_shipping && this.new_shipping_address">
<div class="form-header">
<h1>{{ __('shop::app.checkout.onepage.shipping-address') }}</h1>
@auth('customer')
@if(count(auth('customer')->user()->addresses))
<a class="btn btn-lg btn-primary" @click = backToSavedShippingAddress()>
<a class="btn btn-lg btn-primary" @click="backToSavedShippingAddress()">
{{ __('shop::app.checkout.onepage.back') }}
</a>
@endif
@ -331,10 +446,19 @@
{{ __('shop::app.checkout.onepage.first-name') }}
</label>
<input type="text" v-validate="'required'" class="control" id="shipping[first_name]" name="shipping[first_name]" v-model="address.shipping.first_name" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.first-name') }}&quot;"/>
<input
class="control"
id="shipping[first_name]"
type="text"
name="shipping[first_name]"
v-model="address.shipping.first_name"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.first-name') }}&quot;"/>
<span class="control-error" v-if="errors.has('address-form.shipping[first_name]')">
@{{ errors.first('address-form.shipping[first_name]') }}
<span
class="control-error"
v-text="errors.first('address-form.shipping[first_name]')"
v-if="errors.has('address-form.shipping[first_name]')">
</span>
</div>
@ -343,10 +467,19 @@
{{ __('shop::app.checkout.onepage.last-name') }}
</label>
<input type="text" v-validate="'required'" class="control" id="shipping[last_name]" name="shipping[last_name]" v-model="address.shipping.last_name" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.last-name') }}&quot;"/>
<input
class="control"
id="shipping[last_name]"
type="text"
name="shipping[last_name]"
v-model="address.shipping.last_name"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.last-name') }}&quot;"/>
<span class="control-error" v-if="errors.has('address-form.shipping[last_name]')">
@{{ errors.first('address-form.shipping[last_name]') }}
<span
class="control-error"
v-text="errors.first('address-form.shipping[last_name]')"
v-if="errors.has('address-form.shipping[last_name]')">
</span>
</div>
@ -355,10 +488,19 @@
{{ __('shop::app.checkout.onepage.email') }}
</label>
<input type="text" v-validate="'required|email'" class="control" id="shipping[email]" name="shipping[email]" v-model="address.shipping.email" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.email') }}&quot;"/>
<input
class="control"
id="shipping[email]"
type="text"
name="shipping[email]"
v-validate="'required|email'"
v-model="address.shipping.email"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.email') }}&quot;"/>
<span class="control-error" v-if="errors.has('address-form.shipping[email]')">
@{{ errors.first('address-form.shipping[email]') }}
<span
class="control-error"
v-text="errors.first('address-form.shipping[email]')"
v-if="errors.has('address-form.shipping[email]')">
</span>
</div>
@ -367,17 +509,31 @@
{{ __('shop::app.checkout.onepage.address1') }}
</label>
<input type="text" v-validate="'required'" class="control" id="shipping_address_0" name="shipping[address1][]" v-model="address.shipping.address1[0]" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.address1') }}&quot;"/>
<input
class="control"
id="shipping_address_0"
type="text"
name="shipping[address1][]"
v-model="address.shipping.address1[0]"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.address1') }}&quot;"/>
<span class="control-error" v-if="errors.has('address-form.shipping[address1][]')">
@{{ errors.first('address-form.shipping[address1][]') }}
<span
class="control-error"
v-text="errors.first('address-form.shipping[address1][]')"
v-if="errors.has('address-form.shipping[address1][]')">
</span>
</div>
@if (core()->getConfigData('customer.settings.address.street_lines') && core()->getConfigData('customer.settings.address.street_lines') > 1)
<div class="control-group" style="margin-top: -25px;">
@for ($i = 1; $i < core()->getConfigData('customer.settings.address.street_lines'); $i++)
<input type="text" class="control" name="shipping[address1][{{ $i }}]" id="shipping_address_{{ $i }}" v-model="address.shipping.address1[{{$i}}]">
<input
class="control"
id="shipping_address_{{ $i }}"
type="text"
name="shipping[address1][{{ $i }}]"
v-model="address.shipping.address1[{{$i}}]">
@endfor
</div>
@endif
@ -387,19 +543,35 @@
{{ __('shop::app.checkout.onepage.city') }}
</label>
<input type="text" v-validate="'required'" class="control" id="shipping[city]" name="shipping[city]" v-model="address.shipping.city" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.city') }}&quot;"/>
<input
class="control"
id="shipping[city]"
type="text"
name="shipping[city]"
v-model="address.shipping.city"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.city') }}&quot;"/>
<span class="control-error" v-if="errors.has('address-form.shipping[city]')">
@{{ errors.first('address-form.shipping[city]') }}
<span
class="control-error"
v-text="errors.first('address-form.shipping[city]')"
v-if="errors.has('address-form.shipping[city]')">
</span>
</div>
<div class="control-group" :class="[errors.has('address-form.shipping[country]') ? 'has-error' : '']">
<label for="shipping[country]" class="required">
<label for="shipping[country]" class="{{ core()->isCountryRequired() ? 'required' : '' }}">
{{ __('shop::app.checkout.onepage.country') }}
</label>
<select type="text" v-validate="'required'" class="control" id="shipping[country]" name="shipping[country]" v-model="address.shipping.country" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.country') }}&quot;">
<select
class="control"
id="shipping[country]"
type="text"
name="shipping[country]"
v-model="address.shipping.country"
v-validate="'{{ core()->isCountryRequired() ? 'required' : '' }}'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.country') }}&quot;">
<option value=""></option>
@foreach (core()->countries() as $country)
@ -407,43 +579,67 @@
@endforeach
</select>
<span class="control-error" v-if="errors.has('address-form.shipping[country]')">
@{{ errors.first('address-form.shipping[country]') }}
<span
class="control-error"
v-text="errors.first('address-form.shipping[country]')"
v-if="errors.has('address-form.shipping[country]')">
</span>
</div>
<div class="control-group" :class="[errors.has('address-form.shipping[state]') ? 'has-error' : '']">
<label for="shipping[state]" class="required">
<label for="shipping[state]" class="{{ core()->isStateRequired() ? 'required' : '' }}">
{{ __('shop::app.checkout.onepage.state') }}
</label>
<input
class="control"
id="shipping[state]"
type="text"
name="shipping[state]"
v-model="address.shipping.state"
v-validate="'{{ core()->isStateRequired() ? 'required' : '' }}'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.state') }}&quot;"
v-if="! haveStates('shipping')"/>
<input type="text" v-validate="'required'" class="control" id="shipping[state]" name="shipping[state]" v-model="address.shipping.state" v-if="!haveStates('shipping')" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.state') }}&quot;"/>
<select v-validate="'required'" class="control" id="shipping[state]" name="shipping[state]" v-model="address.shipping.state" v-if="haveStates('shipping')" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.state') }}&quot;">
<select
class="control" id="shipping[state]"
name="shipping[state]"
v-model="address.shipping.state"
v-validate=""
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.state') }}&quot;"
v-if="haveStates('shipping')">
<option value="">{{ __('shop::app.checkout.onepage.select-state') }}</option>
<option v-for='(state, index) in countryStates[address.shipping.country]' :value="state.code">
@{{ state.default_name }}
</option>
</select>
<span class="control-error" v-if="errors.has('address-form.shipping[state]')">
@{{ errors.first('address-form.shipping[state]') }}
<span
class="control-error"
v-text="errors.first('address-form.shipping[state]')"
v-if="errors.has('address-form.shipping[state]')">
</span>
</div>
<div class="control-group" :class="[errors.has('address-form.shipping[postcode]') ? 'has-error' : '']">
<label for="shipping[postcode]" class="required">
<label for="shipping[postcode]" class="{{ core()->isPostCodeRequired() ? 'required' : '' }}">
{{ __('shop::app.checkout.onepage.postcode') }}
</label>
<input type="text" v-validate="'required'" class="control" id="shipping[postcode]" name="shipping[postcode]" v-model="address.shipping.postcode" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.postcode') }}&quot;"/>
<input
class="control"
id="shipping[postcode]"
type="text"
name="shipping[postcode]"
v-model="address.shipping.postcode"
v-validate="'{{ core()->isPostCodeRequired() ? 'required' : '' }}'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.postcode') }}&quot;"/>
<span class="control-error" v-if="errors.has('address-form.shipping[postcode]')">
@{{ errors.first('address-form.shipping[postcode]') }}
<span
class="control-error"
v-text="errors.first('address-form.shipping[postcode]')"
v-if="errors.has('address-form.shipping[postcode]')">
</span>
</div>
@ -452,24 +648,37 @@
{{ __('shop::app.checkout.onepage.phone') }}
</label>
<input type="text" v-validate="'required|numeric'" class="control" id="shipping[phone]" name="shipping[phone]" v-model="address.shipping.phone" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.phone') }}&quot;"/>
<input
class="control"
id="shipping[phone]"
type="text"
name="shipping[phone]"
v-model="address.shipping.phone"
v-validate="'required|numeric'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.phone') }}&quot;"/>
<span class="control-error" v-if="errors.has('address-form.shipping[phone]')">
@{{ errors.first('address-form.shipping[phone]') }}
<span
class="control-error"
v-text="errors.first('address-form.shipping[phone]')"
v-if="errors.has('address-form.shipping[phone]')">
</span>
</div>
@auth('customer')
<div class="control-group">
<span class="checkbox">
<input type="checkbox" id="shipping[save_as_address]" name="shipping[save_as_address]" v-model="address.shipping.save_as_address"/>
<input
id="shipping[save_as_address]"
type="checkbox"
name="shipping[save_as_address]"
v-model="address.shipping.save_as_address"/>
<label class="checkbox-view" for="shipping[save_as_address]"></label>
{{ __('shop::app.checkout.onepage.save_as_address') }}
</span>
</div>
@endauth
</div>
@endif
</form>
</form>

View File

@ -4,36 +4,60 @@
<script type="text/x-template" id="country-state-template">
<div>
<div class="control-group" :class="[errors.has('country') ? 'has-error' : '']">
<label for="country" class="required">
<label for="country" class="{{ core()->isCountryRequired() ? 'required' : '' }}">
{{ __('shop::app.customer.account.address.create.country') }}
</label>
<select type="text" v-validate="'required'" class="control" id="country" name="country" v-model="country" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.country') }}&quot;">
<select
class="control"
id="country"
type="text"
name="country"
v-model="country"
v-validate="'{{ core()->isCountryRequired() ? 'required' : '' }}'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.country') }}&quot;">
<option value=""></option>
@foreach (core()->countries() as $country)
<option {{ $country->code === $defaultCountry ? 'selected' : '' }} value="{{ $country->code }}">{{ $country->name }}</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('country')">
@{{ errors.first('country') }}
<span
class="control-error"
v-text="errors.first('country')"
v-if="errors.has('country')">
</span>
</div>
<div class="control-group" :class="[errors.has('state') ? 'has-error' : '']">
<label for="state" class="required">
<label for="state" class="{{ core()->isStateRequired() ? 'required' : '' }}">
{{ __('shop::app.customer.account.address.create.state') }}
</label>
<input type="text" v-validate="'required'" class="control" id="state" name="state" v-model="state" v-if="!haveStates()" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.state') }}&quot;"/>
<select v-validate="'required'" class="control" id="state" name="state" v-model="state" v-if="haveStates()" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.state') }}&quot;">
<input
class="control"
id="state"
type="text"
name="state"
v-model="state"
v-validate="'{{ core()->isStateRequired() ? 'required' : '' }}'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.state') }}&quot;"
v-if="! haveStates()"/>
<select
class="control"
id="state"
name="state"
v-model="state"
v-validate="'{{ core()->isStateRequired() ? 'required' : '' }}'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.state') }}&quot;"
v-if="haveStates()">
<option value="">{{ __('shop::app.customer.account.address.create.select-state') }}</option>
<option v-for='(state, index) in countryStates[country]' :value="state.code">
@{{ state.default_name }}
</option>
</select>
<span class="control-error" v-if="errors.has('state')">
@ -45,7 +69,6 @@
<script>
Vue.component('country-state', {
template: '#country-state-template',
inject: ['$validator'],
@ -70,4 +93,4 @@
}
});
</script>
@endpush
@endpush

View File

@ -11,7 +11,9 @@
@section('account-content')
<div class="account-layout">
<div class="account-head mb-15">
<span class="back-icon"><a href="{{ route('customer.address.index') }}"><i class="icon icon-menu-back"></i></a></span>
<span class="back-icon">
<a href="{{ route('customer.address.index') }}"><i class="icon icon-menu-back"></i></a>
</span>
<span class="account-heading">{{ __('shop::app.customer.account.address.create.title') }}</span>
@ -29,9 +31,18 @@
<div class="control-group" :class="[errors.has('company_name') ? 'has-error' : '']">
<label for="company_name">{{ __('shop::app.customer.account.address.create.company_name') }}</label>
<input value="{{ old('company_name') }}" type="text" class="control" name="company_name" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.company_name') }}&quot;">
<input
class="control"
type="text"
name="company_name"
value="{{ old('company_name') }}"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.company_name') }}&quot;">
<span class="control-error" v-if="errors.has('company_name')">@{{ errors.first('company_name') }}</span>
<span
class="control-error"
v-text="errors.first('company_name')"
v-if="errors.has('company_name')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.company_name.after') !!}
@ -39,9 +50,19 @@
<div class="control-group" :class="[errors.has('first_name') ? 'has-error' : '']">
<label for="first_name" class="required">{{ __('shop::app.customer.account.address.create.first_name') }}</label>
<input value="{{ old('first_name') ?? $currentCustomer->first_name }}" type="text" class="control" name="first_name" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.first_name') }}&quot;">
<input
class="control"
type="text"
name="first_name"
value="{{ old('first_name') ?? $currentCustomer->first_name }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.first_name') }}&quot;">
<span class="control-error" v-if="errors.has('first_name')">@{{ errors.first('first_name') }}</span>
<span
class="control-error"
v-text="errors.first('first_name')"
v-if="errors.has('first_name')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.first_name.after') !!}
@ -49,9 +70,19 @@
<div class="control-group" :class="[errors.has('last_name') ? 'has-error' : '']">
<label for="last_name" class="required">{{ __('shop::app.customer.account.address.create.last_name') }}</label>
<input value="{{ old('last_name') ?? $currentCustomer->last_name }}" type="text" class="control" name="last_name" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.last_name') }}&quot;">
<input
class="control"
type="text"
name="last_name"
value="{{ old('last_name') ?? $currentCustomer->last_name }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.last_name') }}&quot;">
<span class="control-error" v-if="errors.has('last_name')">@{{ errors.first('last_name') }}</span>
<span
class="control-error"
v-text="errors.first('last_name')"
v-if="errors.has('last_name')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.last_name.after') !!}
@ -69,7 +100,11 @@
v-validate="''"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.vat_id') }}&quot;">
<span class="control-error" v-if="errors.has('vat_id')">@{{ errors.first('vat_id') }}</span>
<span
class="control-error"
v-text="errors.first('vat_id')"
v-if="errors.has('vat_id')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.vat_id.after') !!}
@ -81,41 +116,75 @@
<div class="control-group {{ $errors->has('address1.*') ? 'has-error' : '' }}">
<label for="address1" class="required">{{ __('shop::app.customer.account.address.create.street-address') }}</label>
<input type="text" class="control" name="address1[]" value="{{ $addresses[0] ?? '' }}" id="address1" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.street-address') }}&quot;">
<input
class="control"
id="address1"
type="text"
name="address1[]"
value="{{ $addresses[0] ?? '' }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.street-address') }}&quot;">
<span class="control-error" v-text="'{{ $errors->first('address1.*') }}'"></span>
<span
class="control-error"
v-text="'{{ $errors->first('address1.*') }}'">
</span>
</div>
@if (core()->getConfigData('customer.settings.address.street_lines') && core()->getConfigData('customer.settings.address.street_lines') > 1)
<div class="control-group" style="margin-top: -25px;">
@for ($i = 1; $i < core()->getConfigData('customer.settings.address.street_lines'); $i++)
<input type="text" class="control" name="address1[{{ $i }}]" id="address_{{ $i }}">
<input
class="control"
id="address_{{ $i }}"
type="text"
name="address1[{{ $i }}]">
@endfor
</div>
@endif
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.street-address.after') !!}
@include ('shop::customers.account.address.country-state', ['countryCode' => old('country'), 'stateCode' => old('state')])
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.country-state.after') !!}
<div class="control-group" :class="[errors.has('city') ? 'has-error' : '']">
<label for="city" class="required">{{ __('shop::app.customer.account.address.create.city') }}</label>
<input value="{{ old('city') }}" type="text" class="control" name="city" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.city') }}&quot;">
<input
class="control"
type="text"
name="city"
value="{{ old('city') }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.city') }}&quot;">
<span class="control-error" v-if="errors.has('city')">@{{ errors.first('city') }}</span>
<span
class="control-error"
v-text="errors.first('city')"
v-if="errors.has('city')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.city.after') !!}
@include ('shop::customers.account.address.country-state', ['countryCode' => old('country'), 'stateCode' => old('state')])
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.country-state.after') !!}
<div class="control-group" :class="[errors.has('postcode') ? 'has-error' : '']">
<label for="postcode" class="required">{{ __('shop::app.customer.account.address.create.postcode') }}</label>
<label for="postcode" class="{{ core()->isPostCodeRequired() ? 'required' : '' }}">{{ __('shop::app.customer.account.address.create.postcode') }}</label>
<input value="{{ old('postcode') }}" type="text" class="control" name="postcode" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.postcode') }}&quot;">
<input
class="control"
type="text"
name="postcode"
value="{{ old('postcode') }}"
v-validate="'{{ core()->isPostCodeRequired() ? 'required' : '' }}'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.postcode') }}&quot;">
<span class="control-error" v-if="errors.has('postcode')">@{{ errors.first('postcode') }}</span>
<span
class="control-error"
v-text="errors.first('postcode')"
v-if="errors.has('postcode')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.postcode.after') !!}
@ -123,16 +192,29 @@
<div class="control-group" :class="[errors.has('phone') ? 'has-error' : '']">
<label for="phone" class="required">{{ __('shop::app.customer.account.address.create.phone') }}</label>
<input value="{{ old('phone') }}" type="text" class="control" name="phone" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.phone') }}&quot;">
<input
class="control"
type="text"
name="phone"
value="{{ old('phone') }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.phone') }}&quot;">
<span class="control-error" v-if="errors.has('phone')">@{{ errors.first('phone') }}</span>
<span
class="control-error"
v-text="errors.first('phone')"
v-if="errors.has('phone')"></span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.after') !!}
<div class="control-group">
<span class="checkbox">
<input type="checkbox" class="control" id="default_address" name="default_address" {{ old('default_address') ? 'checked' : '' }} >
<input
class="control"
id="default_address"
type="checkbox"
name="default_address" {{ old('default_address') ? 'checked' : '' }} >
<label class="checkbox-view" for="default_address"></label>
@ -148,4 +230,4 @@
{!! view_render_event('bagisto.shop.customers.account.address.create.after') !!}
</div>
@endsection
@endsection

View File

@ -7,7 +7,9 @@
@section('account-content')
<div class="account-layout">
<div class="account-head mb-15">
<span class="back-icon"><a href="{{ route('customer.address.index') }}"><i class="icon icon-menu-back"></i></a></span>
<span class="back-icon">
<a href="{{ route('customer.address.index') }}"><i class="icon icon-menu-back"></i></a>
</span>
<span class="account-heading">{{ __('shop::app.customer.account.address.edit.title') }}</span>
@ -28,9 +30,18 @@
<div class="control-group" :class="[errors.has('company_name') ? 'has-error' : '']">
<label for="company_name">{{ __('shop::app.customer.account.address.edit.company_name') }}</label>
<input type="text" value="{{ old('company_name') ?: $address->company_name }}" class="control" name="company_name" data-vv-as="&quot;{{ __('shop::app.customer.account.address.edit.company_name') }}&quot;">
<input
class="control"
type="text"
name="company_name"
value="{{ old('company_name') ?: $address->company_name }}"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.edit.company_name') }}&quot;">
<span class="control-error" v-if="errors.has('company_name')">@{{ errors.first('company_name') }}</span>
<span
class="control-error"
v-text="errors.first('company_name')"
v-if="errors.has('company_name')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.company_name.after') !!}
@ -38,9 +49,19 @@
<div class="control-group" :class="[errors.has('first_name') ? 'has-error' : '']">
<label for="first_name" class="required">{{ __('shop::app.customer.account.address.create.first_name') }}</label>
<input type="text" class="control" name="first_name" v-validate="'required'" value="{{ old('first_name') ?: $address->first_name }}" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.first_name') }}&quot;">
<input
class="control"
type="text"
name="first_name"
value="{{ old('first_name') ?: $address->first_name }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.first_name') }}&quot;">
<span class="control-error" v-if="errors.has('first_name')">@{{ errors.first('first_name') }}</span>
<span
class="control-error"
v-text="errors.first('first_name')"
v-if="errors.has('first_name')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.first_name.after') !!}
@ -48,9 +69,19 @@
<div class="control-group" :class="[errors.has('last_name') ? 'has-error' : '']">
<label for="last_name" class="required">{{ __('shop::app.customer.account.address.create.last_name') }}</label>
<input type="text" class="control" name="last_name" v-validate="'required'" value="{{ old('last_name') ?: $address->last_name }}" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.last_name') }}&quot;">
<input
class="control"
type="text"
name="last_name"
value="{{ old('last_name') ?: $address->last_name }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.last_name') }}&quot;">
<span class="control-error" v-if="errors.has('last_name')">@{{ errors.first('last_name') }}</span>
<span
class="control-error"
v-text="errors.first('last_name')"
v-if="errors.has('last_name')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.last_name.after') !!}
@ -61,13 +92,18 @@
</label>
<input
type="text"
class="control"
type="text"
name="vat_id"
value="{{ old('vat_id') ?: $address->vat_id }}"
v-validate="''" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.vat_id') }}&quot;">
v-validate="''"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.vat_id') }}&quot;">
<span class="control-error" v-if="errors.has('vat_id')">@{{ errors.first('vat_id') }}</span>
<span
class="control-error"
v-text="errors.first('vat_id')"
v-if="errors.has('vat_id')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.vat_id.after') !!}
@ -77,7 +113,14 @@
<div class="control-group {{ $errors->has('address1.*') ? 'has-error' : '' }}">
<label for="address_0" class="required">{{ __('shop::app.customer.account.address.edit.street-address') }}</label>
<input type="text" class="control" name="address1[]" id="address_0" v-validate="'required'" value="{{ $addresses[0] ?? '' }}" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.street-address') }}&quot;">
<input
class="control"
id="address_0"
type="text"
name="address1[]"
value="{{ $addresses[0] ?? '' }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.street-address') }}&quot;">
<span class="control-error">{{ $errors->first('address1.*') }}</span>
</div>
@ -85,33 +128,58 @@
@if (core()->getConfigData('customer.settings.address.street_lines') && core()->getConfigData('customer.settings.address.street_lines') > 1)
<div class="control-group" style="margin-top: -25px;">
@for ($i = 1; $i < core()->getConfigData('customer.settings.address.street_lines'); $i++)
<input type="text" class="control" name="address1[{{ $i }}]" id="address_{{ $i }}" value="{{ $addresses[$i] ?? '' }}">
<input
class="control"
id="address_{{ $i }}"
type="text"
name="address1[{{ $i }}]"
value="{{ $addresses[$i] ?? '' }}">
@endfor
</div>
@endif
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.street-addres.after') !!}
@include ('shop::customers.account.address.country-state', ['countryCode' => old('country') ?? $address->country, 'stateCode' => old('state') ?? $address->state])
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.country-state.after') !!}
<div class="control-group" :class="[errors.has('city') ? 'has-error' : '']">
<label for="city" class="required">{{ __('shop::app.customer.account.address.create.city') }}</label>
<input type="text" class="control" name="city" v-validate="'required|regex:^[a-zA-Z \-]*$'" value="{{ old('city') ?: $address->city }}" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.city') }}&quot;">
<input
class="control"
type="text"
name="city"
value="{{ old('city') ?: $address->city }}"
v-validate="'required|regex:^[a-zA-Z \-]*$'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.city') }}&quot;">
<span class="control-error" v-if="errors.has('city')">@{{ errors.first('city') }}</span>
<span
class="control-error"
v-text="errors.first('city')"
v-if="errors.has('city')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.create.after') !!}
@include ('shop::customers.account.address.country-state', ['countryCode' => old('country') ?? $address->country, 'stateCode' => old('state') ?? $address->state])
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.country-state.after') !!}
<div class="control-group" :class="[errors.has('postcode') ? 'has-error' : '']">
<label for="postcode" class="required">{{ __('shop::app.customer.account.address.create.postcode') }}</label>
<label for="postcode" class="{{ core()->isPostCodeRequired() ? 'required' : '' }}">{{ __('shop::app.customer.account.address.create.postcode') }}</label>
<input type="text" class="control" name="postcode" v-validate="'required'" value="{{ old('postcode') ?: $address->postcode }}" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.postcode') }}&quot;">
<input
type="text"
class="control"
name="postcode"
v-validate="'{{ core()->isPostCodeRequired() ? 'required' : '' }}'"
value="{{ old('postcode') ?: $address->postcode }}"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.postcode') }}&quot;">
<span class="control-error" v-if="errors.has('postcode')">@{{ errors.first('postcode') }}</span>
<span
class="control-error"
v-text="errors.first('postcode')"
v-if="errors.has('postcode')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.postcode.after') !!}
@ -119,16 +187,31 @@
<div class="control-group" :class="[errors.has('phone') ? 'has-error' : '']">
<label for="phone" class="required">{{ __('shop::app.customer.account.address.create.phone') }}</label>
<input type="text" class="control" name="phone" v-validate="'required'" value="{{ old('phone') ?: $address->phone }}" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.phone') }}&quot;">
<input
class="control"
type="text"
name="phone"
value="{{ old('phone') ?: $address->phone }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.phone') }}&quot;">
<span class="control-error" v-if="errors.has('phone')">@{{ errors.first('phone') }}</span>
<span
class="control-error"
v-text="errors.first('phone')"
v-if="errors.has('phone')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.after', ['address' => $address]) !!}
<div class="control-group">
<span class="checkbox">
<input type="checkbox" class="control" id="default_address" name="default_address" {{ $address->default_address ? 'checked' : '' }} >
<input
class="control"
id="default_address"
type="checkbox"
name="default_address"
{{ $address->default_address ? 'checked' : '' }}>
<label class="checkbox-view" for="default_address"></label>
@ -146,4 +229,4 @@
{!! view_render_event('bagisto.shop.customers.account.address.edit.after', ['address' => $address]) !!}
</div>
@endsection
@endsection

View File

@ -56,7 +56,7 @@
</li>
<li class="mt-5">
{{ $address->address1 }},
{{ $address->address1 }}
</li>
<li class="mt-5">
@ -91,6 +91,7 @@
<form id="deleteAddressForm" action="{{ route('address.delete', $address->id) }}" method="post">
@method('delete')
@csrf
</form>
</span>

View File

@ -5,7 +5,12 @@ return [
'key' => 'taxes',
'name' => 'tax::app.admin.system.taxes.taxes',
'sort' => 6,
], [
],
/**
* Catalog.
*/
[
'key' => 'taxes.catalogue',
'name' => 'tax::app.admin.system.taxes.catalogue',
'sort' => 1,
@ -15,12 +20,12 @@ return [
'sort' => 1,
'fields' => [
[
'name' => 'tax_inclusive',
'title' => 'tax::app.admin.system.taxes.tax-inclusive',
'type' => 'boolean',
'name' => 'tax_inclusive',
'title' => 'tax::app.admin.system.taxes.tax-inclusive',
'type' => 'boolean',
'validation' => 'required',
'default' => false
]
'default' => false,
],
],
], [
'key' => 'taxes.catalogue.default-location-calculation',
@ -44,7 +49,7 @@ return [
'title' => 'tax::app.admin.system.taxes.default-post-code',
'type' => 'text',
'default' => '',
]
],
],
]
];
],
];

View File

@ -1,33 +1,34 @@
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch-poll": "npm run watch -- --watch-poll",
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"axios": "^0.21.0",
"cross-env": "^6.0.3",
"flatpickr": "^4.6.3",
"jquery": "^3.4.1",
"laravel-mix": "^5.0.0",
"laravel-mix-merge-manifest": "^0.1.2",
"sass": "^1.24.4",
"sass-loader": "^8.0.2",
"vue": "^2.6.14",
"vue-template-compiler": "^2.6.14"
},
"dependencies": {
"@babel/polyfill": "^7.7.0",
"tooltip.js": "^1.3.1",
"url-polyfill": "^1.1.5",
"url-search-params-polyfill": "^6.0.0",
"v-tooltip": "^2.0.3",
"vue-multiselect": "^2.1.6",
"vue-swatches": "^1.0.3"
}
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch-poll": "npm run watch -- --watch-poll",
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"axios": "^0.21.0",
"cross-env": "^6.0.3",
"flatpickr": "^4.6.3",
"jquery": "^3.4.1",
"laravel-mix": "^5.0.0",
"laravel-mix-merge-manifest": "^0.1.2",
"sass": "^1.24.4",
"sass-loader": "^8.0.2",
"vue": "^2.6.14",
"vue-template-compiler": "^2.6.14"
},
"dependencies": {
"@babel/polyfill": "^7.7.0",
"tooltip.js": "^1.3.1",
"url-polyfill": "^1.1.5",
"url-search-params-polyfill": "^6.0.0",
"v-tooltip": "^2.0.3",
"vue-multiselect": "^2.1.6",
"vue-swatches": "^1.0.3",
"vuedraggable": "^2.24.3"
}
}

File diff suppressed because one or more lines are too long

View File

@ -30,3 +30,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**!
* Sortable 1.10.2
* @author RubaXa <trash@rubaxa.org>
* @author owenm <owen23355@gmail.com>
* @license MIT
*/

View File

@ -1,4 +1,4 @@
{
"/js/ui.js": "/js/ui.js?id=99de3c7f62be5fb50eaf",
"/js/ui.js": "/js/ui.js?id=3ffc4240fed473cc24f1",
"/css/ui.css": "/css/ui.css?id=57354f5eea4eb6f616e9"
}

View File

@ -1,79 +1,81 @@
import VTooltip from "v-tooltip";
import { Multiselect } from "vue-multiselect";
import Draggable from 'vuedraggable';
import { Multiselect } from 'vue-multiselect';
import VTooltip from 'v-tooltip';
import Accordian from "./components/accordian";
import DatagridPlus from "./components/datagrid/datagrid-plus";
import DateComponent from "./components/date";
import DatetimeComponent from "./components/datetime";
import Flash from "./components/flash";
import FlashWrapper from "./components/flash-wrapper";
import ImageItem from "./components/image/image-item";
import ImageUpload from "./components/image/image-upload";
import ImageWrapper from "./components/image/image-wrapper";
import Modal from "./components/modal";
import OverlayLoader from "./components/overlay-loader";
import SwatchPicker from "./components/swatch-picker";
import DefaultImage from "./components/default-image";
import Tab from "./components/tabs/tab";
import Tabs from "./components/tabs/tabs";
import TimeComponent from "./components/time";
import TreeCheckbox from "./components/tree-view/tree-checkbox";
import TreeItem from "./components/tree-view/tree-item";
import TreeRadio from "./components/tree-view/tree-radio";
import TreeView from "./components/tree-view/tree-view";
import Alert from "./directives/alert";
import Code from "./directives/code";
import Debounce from "./directives/debounce";
import Slugify from "./directives/slugify";
import SlugifyTarget from "./directives/slugify-target";
import Accordian from './components/accordian';
import DatagridPlus from './components/datagrid/datagrid-plus';
import DateComponent from './components/date';
import DatetimeComponent from './components/datetime';
import Flash from './components/flash';
import FlashWrapper from './components/flash-wrapper';
import ImageItem from './components/image/image-item';
import ImageUpload from './components/image/image-upload';
import ImageWrapper from './components/image/image-wrapper';
import Modal from './components/modal';
import OverlayLoader from './components/overlay-loader';
import SwatchPicker from './components/swatch-picker';
import DefaultImage from './components/default-image';
import Tab from './components/tabs/tab';
import Tabs from './components/tabs/tabs';
import TimeComponent from './components/time';
import TreeCheckbox from './components/tree-view/tree-checkbox';
import TreeItem from './components/tree-view/tree-item';
import TreeRadio from './components/tree-view/tree-radio';
import TreeView from './components/tree-view/tree-view';
import Alert from './directives/alert';
import Code from './directives/code';
import Debounce from './directives/debounce';
import Slugify from './directives/slugify';
import SlugifyTarget from './directives/slugify-target';
/* config section */
VTooltip.options.defaultDelay = 0;
Vue.config.productionTip = false;
/* component section */
Vue.directive("tooltip", VTooltip.VTooltip);
Vue.component("datagrid-plus", DatagridPlus);
Vue.component("flash-wrapper", FlashWrapper);
Vue.component("flash", Flash);
Vue.component("tabs", Tabs);
Vue.component("tab", Tab);
Vue.component("accordian", Accordian);
Vue.component("tree-view", TreeView);
Vue.component("tree-item", TreeItem);
Vue.component("tree-checkbox", TreeCheckbox);
Vue.component("tree-radio", TreeRadio);
Vue.component("modal", Modal);
Vue.component("image-upload", ImageUpload);
Vue.component("image-wrapper", ImageWrapper);
Vue.component("image-item", ImageItem);
Vue.directive("slugify", Slugify);
Vue.directive("slugify-target", SlugifyTarget);
Vue.directive("code", Code);
Vue.directive("alert", Alert);
Vue.component("datetime", DatetimeComponent);
Vue.component("date", DateComponent);
Vue.component("time-component", TimeComponent);
Vue.component("swatch-picker", SwatchPicker);
Vue.directive("debounce", Debounce);
Vue.component("overlay-loader", OverlayLoader);
Vue.component("multiselect", Multiselect);
Vue.component("default-image", DefaultImage);
Vue.directive('tooltip', VTooltip.VTooltip);
Vue.component('datagrid-plus', DatagridPlus);
Vue.component('flash-wrapper', FlashWrapper);
Vue.component('flash', Flash);
Vue.component('tabs', Tabs);
Vue.component('tab', Tab);
Vue.component('accordian', Accordian);
Vue.component('tree-view', TreeView);
Vue.component('tree-item', TreeItem);
Vue.component('tree-checkbox', TreeCheckbox);
Vue.component('tree-radio', TreeRadio);
Vue.component('modal', Modal);
Vue.component('image-upload', ImageUpload);
Vue.component('image-wrapper', ImageWrapper);
Vue.component('image-item', ImageItem);
Vue.directive('slugify', Slugify);
Vue.directive('slugify-target', SlugifyTarget);
Vue.directive('code', Code);
Vue.directive('alert', Alert);
Vue.component('datetime', DatetimeComponent);
Vue.component('date', DateComponent);
Vue.component('time-component', TimeComponent);
Vue.component('swatch-picker', SwatchPicker);
Vue.directive('debounce', Debounce);
Vue.component('overlay-loader', OverlayLoader);
Vue.component('multiselect', Multiselect);
Vue.component('default-image', DefaultImage);
Vue.component('draggable', Draggable);
/* filter section */
Vue.filter("truncate", function(value, limit, trail) {
if (!value) value = "";
Vue.filter('truncate', function(value, limit, trail) {
if (!value) value = '';
limit = limit ? limit : 20;
trail = trail ? trail : "...";
trail = trail ? trail : '...';
return value.length > limit ? value.substring(0, limit) + trail : value;
});
/* require section */
require("flatpickr/dist/flatpickr.css");
require("vue-swatches/dist/vue-swatches.min.css");
require("vue-multiselect/dist/vue-multiselect.min.css");
require("@babel/polyfill");
require("url-search-params-polyfill");
require("url-polyfill");
require('flatpickr/dist/flatpickr.css');
require('vue-swatches/dist/vue-swatches.min.css');
require('vue-multiselect/dist/vue-multiselect.min.css');
require('@babel/polyfill');
require('url-search-params-polyfill');
require('url-polyfill');

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,7 @@
"/js/velocity.js": "/js/velocity.js?id=ac05caeb5e4b0566a4ab",
"/js/manifest.js": "/js/manifest.js?id=3cded37ef514b0fb89b1",
"/js/components.js": "/js/components.js?id=d16d70d3905f32644901",
"/css/velocity.css": "/css/velocity.css?id=4ec74ee99bea554c475f",
"/css/velocity.css": "/css/velocity.css?id=1a21fa2c015a3f30dc05",
"/css/velocity-admin.css": "/css/velocity-admin.css?id=b67a82956e53163b5e3f",
"/images/icon-calendar.svg": "/images/icon-calendar.svg?id=870d0f733a5837742276",
"/images/icon-camera.svg": "/images/icon-camera.svg?id=b2fd2f9e17e1ccee96e2",

View File

@ -957,12 +957,6 @@
.card {
height: 100%;
ul {
li {
display: inline-block;
}
}
}
}
@ -1342,12 +1336,6 @@
font-size: 14px;
}
ul {
li {
display: inline-block;
}
}
.add-address-button {
height: 100%;
display: table;
@ -2489,7 +2477,7 @@
}
@media only screen and (max-width: 425px) {
.cart-details {
.cart-content {

View File

@ -27,34 +27,30 @@
class="step-content shipping"
id="shipping-section"
v-if="showShippingSection">
<shipping-section
:key="shippingComponentKey"
@onShippingMethodSelected="shippingMethodSelected($event)">
</shipping-section>
</div>
<div
class="step-content payment"
v-if="showPaymentSection"
id="payment-section">
<payment-section @onPaymentMethodSelected="paymentMethodSelected($event)">
id="payment-section"
v-if="showPaymentSection">
<payment-section
@onPaymentMethodSelected="paymentMethodSelected($event)">
</payment-section>
<coupon-component
@onApplyCoupon="getOrderSummary"
@onRemoveCoupon="getOrderSummary">
</coupon-component>
</div>
<div
class="step-content review"
v-if="showSummarySection"
id="summary-section">
id="summary-section"
v-if="showSummarySection">
<review-section :key="reviewComponentKey">
<div slot="summary-section">
<summary-section
@ -79,7 +75,6 @@
</div>
</div>
</review-section>
</div>
</div>
@ -296,7 +291,13 @@
if (value == ""
&& element.id != 'sign-btn'
&& element.id != 'billing[company_name]'
&& element.id != 'billing[country]'
&& element.id != 'billing[state]'
&& element.id != 'billing[postcode]'
&& element.id != 'shipping[company_name]'
&& element.id != 'shipping[country]'
&& element.id != 'shipping[state]'
&& element.id != 'shipping[postcode]'
) {
// check for multiple line address
if (elementId.match('billing_address_')

View File

@ -1,5 +1,5 @@
<form data-vv-scope="address-form" class="custom-form">
<div class="form-container" v-if="!this.new_billing_address">
<div class="form-container" v-if="! this.new_billing_address">
<accordian
:active="true"
:title="'{{ __('shop::app.checkout.onepage.billing-address') }}'">
@ -8,6 +8,7 @@
<h3 class="fw6 display-inbl">
{{ __('shop::app.checkout.onepage.billing-address') }}
</h3>
<i class="rango-arrow"></i>
</div>
@ -19,34 +20,31 @@
v-for='(addresses, index) in this.allAddress'>
<div class="card">
<div class="card-body row">
<div class="col-1">
<input
type="radio"
v-validate="'required'"
name="billing[address_id]"
:value="addresses.id"
v-model="address.billing.address_id"
@change="validateForm('address-form')"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.billing-address') }}&quot;" />
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.billing-address') }}&quot;"
@change="validateForm('address-form')" />
<span class="checkmark"></span>
</div>
<div class="col-10">
<h5 class="card-title fw6">
@{{ addresses.first_name }} @{{ addresses.last_name }},
</h5>
<h5 class="card-title fw6" v-text="`${addresses.first_name} ${addresses.last_name}`"></h5>
<ul type="none">
<li>@{{ addresses.address1 }},</li>
<li>@{{ addresses.postcode }} @{{ addresses.city }},</li>
<li>@{{ addresses.state }},</li>
<li>@{{ addresses.country }}</li>
<li v-text="addresses.address1"></li>
<li v-text="addresses.city"></li>
<li v-text="addresses.state"></li>
<li>
{{ __('shop::app.customer.account.address.index.contact') }} : @{{ addresses.phone }}
<span v-text="addresses.country"></span>
<span v-text="addresses.postcode"></span>
</li>
<li>{{ __('shop::app.customer.account.address.index.contact') }} : @{{ addresses.phone }}</li>
</ul>
</div>
</div>
@ -59,9 +57,8 @@
@click="validateFormAfterAction"
class="card-body add-address-button">
<div class="cursor-pointer" @click="newBillingAddress()">
<i class="material-icons">
add_circle_outline
</i>
<i class="material-icons">add_circle_outline</i>
<span>{{ __('shop::app.checkout.onepage.new-address') }}</span>
</div>
</div>
@ -81,11 +78,11 @@
<div class="mt10 mb10" v-if="address.billing.address_id">
<span class="checkbox fs16 display-inbl">
<input
type="checkbox"
id="billing[use_for_shipping]"
type="checkbox"
name="billing[use_for_shipping]"
@change="validateFormAfterAction"
v-model="address.billing.use_for_shipping" />
v-model="address.billing.use_for_shipping"
@change="validateFormAfterAction" />
<span>
{{ __('shop::app.checkout.onepage.use_for_shipping') }}
@ -101,13 +98,12 @@
<accordian :title="'{{ __('shop::app.checkout.onepage.billing-address') }}'" :active="true">
<div class="form-header" slot="header">
<h3 class="fw6 display-inbl">
{{ __('shop::app.checkout.onepage.billing-address') }}
{{ __('shop::app.checkout.onepage.billing-address') }}
</h3>
<i class="rango-arrow"></i>
</div>
<div class="col-12 no-padding" slot="body">
@auth('customer')
@if(count(auth('customer')->user()->addresses))
@ -120,9 +116,7 @@
@endif
@endauth
@include('shop::checkout.onepage.customer-new-form', [
'billing' => true
])
@include('shop::checkout.onepage.customer-new-form', ['billing' => true])
</div>
</accordian>
</div>
@ -130,7 +124,7 @@
@if ($cart->haveStockableItems())
<div
class="form-container"
v-if="!address.billing.use_for_shipping && !this.new_shipping_address">
v-if="! address.billing.use_for_shipping && ! this.new_shipping_address">
<accordian
:active="true"
@ -140,6 +134,7 @@
<h3 class="fw6 display-inbl">
{{ __('shop::app.checkout.onepage.shipping-address') }}
</h3>
<i class="rango-arrow"></i>
</div>
@ -153,29 +148,28 @@
<div class="col-1">
<input
type="radio"
v-validate="'required'"
:value="addresses.id"
name="shipping[address_id]"
:value="addresses.id"
v-model="address.shipping.address_id"
@change="validateForm('address-form')"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.shipping-address') }}&quot;" />
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.checkout.onepage.shipping-address') }}&quot;"
@change="validateForm('address-form')" />
<span class="checkmark"></span>
</div>
<div class="col-10">
<h5 class="card-title fw6">
@{{ addresses.first_name }} @{{ addresses.last_name }},
</h5>
<h5 class="card-title fw6" v-text="`${addresses.first_name} ${addresses.last_name}`"></h5>
<ul type="none">
<li>@{{ addresses.address1 }},</li>
<li>@{{ addresses.city }},</li>
<li>@{{ addresses.state }},</li>
<li>@{{ addresses.country }} @{{ addresses.postcode }}</li>
<li v-text="addresses.address1"></li>
<li v-text="addresses.city"></li>
<li v-text="addresses.state"></li>
<li>
{{ __('shop::app.customer.account.address.index.contact') }} : @{{ addresses.phone }}
<span v-text="addresses.country"></span>
<span v-text="addresses.postcode"></span>
</li>
<li>{{ __('shop::app.customer.account.address.index.contact') }} : @{{ addresses.phone }}</li>
</ul>
</div>
</div>
@ -191,6 +185,7 @@
<i class="material-icons">
add_circle_outline
</i>
<span>{{ __('shop::app.checkout.onepage.new-address') }}</span>
</div>
</div>
@ -206,7 +201,7 @@
<div
class="form-container"
v-if="!address.billing.use_for_shipping && this.new_shipping_address">
v-if="! address.billing.use_for_shipping && this.new_shipping_address">
<accordian
:active="true"
@ -216,6 +211,7 @@
<h3 class="fw6 display-inbl">
{{ __('shop::app.checkout.onepage.shipping-address') }}
</h3>
<i class="rango-arrow"></i>
</div>
@ -231,9 +227,7 @@
@endif
@endauth
@include('shop::checkout.onepage.customer-new-form', [
'shipping' => true
])
@include('shop::checkout.onepage.customer-new-form', ['shipping' => true])
</div>
</accordian>
</div>

View File

@ -1,16 +1,23 @@
<country-state></country-state>
@push('scripts')
<script type="text/x-template" id="country-state-template">
<div>
<div class="control-group" :class="[errors.has('country') ? 'has-error' : '']">
<label for="country" class="mandatory">
<label for="country" class="{{ core()->isCountryRequired() ? 'mandatory' : '' }}">
{{ __('shop::app.customer.account.address.create.country') }}
</label>
<select type="text" v-validate="'required'" class="control styled-select" id="country" name="country" v-model="country" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.country') }}&quot;">
<option value=""></option>
<select
class="control styled-select"
id="country"
type="text"
name="country"
v-model="country"
v-validate="'{{ core()->isCountryRequired() ? 'required' : '' }}'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.country') }}&quot;">
<option value="">{{ __('Select Country') }}</option>
@foreach (core()->countries() as $country)
<option {{ $country->code === $defaultCountry ? 'selected' : '' }} value="{{ $country->code }}">{{ $country->name }}</option>
@endforeach
@ -20,31 +27,35 @@
<span class="select-icon rango-arrow-down"></span>
</div>
<span class="control-error" v-if="errors.has('country')" v-text="errors.first('country')"></span>
<span
class="control-error"
v-text="errors.first('country')"
v-if="errors.has('country')">
</span>
</div>
<div class="control-group" :class="[errors.has('state') ? 'has-error' : '']">
<label for="state" class="mandatory">
<label for="state" class="{{ core()->isStateRequired() ? 'mandatory' : '' }}">
{{ __('shop::app.customer.account.address.create.state') }}
</label>
<input
class="control"
id="state"
type="text"
name="state"
v-model="state"
class="control"
v-if="!haveStates()"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.state') }}&quot;" />
v-validate="'{{ core()->isStateRequired() ? 'required' : '' }}'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.state') }}&quot;"
v-if="! haveStates()"/>
<template v-if="haveStates()">
<select
class="styled-select"
id="state"
name="state"
v-model="state"
class="styled-select"
v-validate="'required'"
v-validate="'{{ core()->isStateRequired() ? 'required' : '' }}'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.state') }}&quot;">
<option value="">{{ __('shop::app.customer.account.address.create.select-state') }}</option>
@ -59,19 +70,22 @@
</div>
</template>
<span class="control-error" v-if="errors.has('state')" v-text="errors.first('state')"></span>
<span
class="control-error"
v-text="errors.first('state')"
v-if="errors.has('state')">
</span>
</div>
</div>
</script>
<script>
Vue.component('country-state', {
template: '#country-state-template',
inject: ['$validator'],
data() {
data: function () {
return {
country: "{{ $countryCode ?? $defaultCountry }}",
@ -82,7 +96,7 @@
},
methods: {
haveStates() {
haveStates: function () {
if (this.countryStates[this.country] && this.countryStates[this.country].length)
return true;

View File

@ -24,9 +24,18 @@
<div class="control-group" :class="[errors.has('company_name') ? 'has-error' : '']">
<label for="company_name">{{ __('shop::app.customer.account.address.create.company_name') }}</label>
<input type="text" class="control" name="company_name" value="{{ old('company_name') }}" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.company_name') }}&quot;">
<input
class="control"
type="text"
name="company_name"
value="{{ old('company_name') }}"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.company_name') }}&quot;">
<span class="control-error" v-if="errors.has('company_name')" v-text="errors.first('company_name')"></span>
<span
class="control-error"
v-text="errors.first('company_name')"
v-if="errors.has('company_name')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.company_name.after') !!}
@ -34,9 +43,19 @@
<div class="control-group" :class="[errors.has('first_name') ? 'has-error' : '']">
<label for="first_name" class="mandatory">{{ __('shop::app.customer.account.address.create.first_name') }}</label>
<input type="text" class="control" name="first_name" value="{{ old('first_name') ?? $currentCustomer->first_name }}" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.first_name') }}&quot;">
<input
class="control"
type="text"
name="first_name"
value="{{ old('first_name') ?? $currentCustomer->first_name }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.first_name') }}&quot;">
<span class="control-error" v-if="errors.has('first_name')" v-text="errors.first('first_name')"></span>
<span
class="control-error"
v-text="errors.first('first_name')"
v-if="errors.has('first_name')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.first_name.after') !!}
@ -44,9 +63,19 @@
<div class="control-group" :class="[errors.has('last_name') ? 'has-error' : '']">
<label for="last_name" class="mandatory">{{ __('shop::app.customer.account.address.create.last_name') }}</label>
<input type="text" class="control" name="last_name" value="{{ old('last_name') ?? $currentCustomer->last_name }}" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.last_name') }}&quot;">
<input
class="control"
type="text"
name="last_name"
value="{{ old('last_name') ?? $currentCustomer->last_name }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.last_name') }}&quot;">
<span class="control-error" v-if="errors.has('last_name')" v-text="errors.first('last_name')"></span>
<span
class="control-error"
v-text="errors.first('last_name')"
v-if="errors.has('last_name')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.last_name.after') !!}
@ -56,9 +85,19 @@
<span class="help-note">{{ __('shop::app.customer.account.address.create.vat_help_note') }}</span>
</label>
<input type="text" class="control" name="vat_id" value="{{ old('vat_id') }}" v-validate="" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.vat_id') }}&quot;">
<input
class="control"
type="text"
name="vat_id"
value="{{ old('vat_id') }}"
v-validate=""
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.vat_id') }}&quot;">
<span class="control-error" v-if="errors.has('vat_id')" v-text="errors.first('vat_id')"></span>
<span
class="control-error"
v-text="errors.first('vat_id')"
v-if="errors.has('vat_id')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.vat_id.after') !!}
@ -70,15 +109,30 @@
<div class="control-group" :class="[errors.has('address1[]') ? 'has-error' : '']">
<label for="address_0" class="mandatory">{{ __('shop::app.customer.account.address.create.street-address') }}</label>
<input type="text" class="control" name="address1[]" id="address_0" value="{{ $addresses[0] ?: '' }}" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.street-address') }}&quot;">
<input
class="control"
id="address_0"
type="text"
name="address1[]"
value="{{ $addresses[0] ?: '' }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.street-address') }}&quot;">
<span class="control-error" v-text="'{{ $errors->first('address1.*') }}'"></span>
<span
class="control-error"
v-text="'{{ $errors->first('address1.*') }}'">
</span>
</div>
@if (core()->getConfigData('customer.settings.address.street_lines') && core()->getConfigData('customer.settings.address.street_lines') > 1)
@for ($i = 1; $i < core()->getConfigData('customer.settings.address.street_lines'); $i++)
<div class="control-group" style="margin-top: -25px;">
<input type="text" class="control" name="address1[{{ $i }}]" id="address_{{ $i }}" value="{{ $addresses[$i] ?? '' }}">
<input
class="control"
id="address_{{ $i }}"
type="text"
name="address1[{{ $i }}]"
value="{{ $addresses[$i] ?? '' }}">
</div>
@endfor
@endif
@ -92,19 +146,39 @@
<div class="control-group" :class="[errors.has('city') ? 'has-error' : '']">
<label for="city" class="mandatory">{{ __('shop::app.customer.account.address.create.city') }}</label>
<input type="text" class="control" name="city" value="{{ old('city') }}" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.city') }}&quot;">
<input
type="text"
class="control"
name="city"
value="{{ old('city') }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.city') }}&quot;">
<span class="control-error" v-if="errors.has('city')" v-text="errors.first('city')"></span>
<span
class="control-error"
v-text="errors.first('city')"
v-if="errors.has('city')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.city.after') !!}
<div class="control-group" :class="[errors.has('postcode') ? 'has-error' : '']">
<label for="postcode" class="mandatory">{{ __('shop::app.customer.account.address.create.postcode') }}</label>
<label for="postcode" class="{{ core()->isPostCodeRequired() ? 'mandatory' : '' }}">{{ __('shop::app.customer.account.address.create.postcode') }}</label>
<input type="text" class="control" name="postcode" value="{{ old('postcode') }}" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.postcode') }}&quot;">
<input
class="control"
type="text"
name="postcode"
value="{{ old('postcode') }}"
v-validate="'{{ core()->isPostCodeRequired() ? 'required' : '' }}'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.postcode') }}&quot;">
<span class="control-error" v-if="errors.has('postcode')" v-text="errors.first('postcode')"></span>
<span
class="control-error"
v-text="errors.first('postcode')"
v-if="errors.has('postcode')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.postcode.after') !!}
@ -112,15 +186,30 @@
<div class="control-group" :class="[errors.has('phone') ? 'has-error' : '']">
<label for="phone" class="mandatory">{{ __('shop::app.customer.account.address.create.phone') }}</label>
<input type="text" class="control" name="phone" value="{{ old('phone') }}" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.phone') }}&quot;">
<input
class="control"
type="text"
name="phone"
value="{{ old('phone') }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.phone') }}&quot;">
<span class="control-error" v-if="errors.has('phone')" v-text="errors.first('phone')"></span>
<span
class="control-error"
v-text="errors.first('phone')"
v-if="errors.has('phone')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.create_form_controls.after') !!}
<div class="control-group d-flex">
<input type="checkbox" id="default_address" class="w-auto" name="default_address" {{ old('default_address') ? 'checked' : '' }}>
<input
class="w-auto"
id="default_address"
type="checkbox"
name="default_address"
{{ old('default_address') ? 'checked' : '' }}>
<label class="checkbox-view" for="default_address"></label>

View File

@ -24,9 +24,18 @@
<div class="control-group" :class="[errors.has('company_name') ? 'has-error' : '']">
<label for="company_name">{{ __('shop::app.customer.account.address.edit.company_name') }}</label>
<input type="text" class="control" name="company_name" value="{{ old('company_name') ?? $address->company_name }}" data-vv-as="&quot;{{ __('shop::app.customer.account.address.edit.company_name') }}&quot;">
<input
class="control"
type="text"
name="company_name"
value="{{ old('company_name') ?? $address->company_name }}"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.edit.company_name') }}&quot;">
<span class="control-error" v-if="errors.has('company_name')" v-text="errors.first('company_name')"></span>
<span
class="control-error"
v-text="errors.first('company_name')"
v-if="errors.has('company_name')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.company_name.after') !!}
@ -34,9 +43,19 @@
<div class="control-group" :class="[errors.has('first_name') ? 'has-error' : '']">
<label for="first_name" class="mandatory">{{ __('shop::app.customer.account.address.create.first_name') }}</label>
<input type="text" class="control" name="first_name" value="{{ old('first_name') ?? $address->first_name }}" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.first_name') }}&quot;">
<input
type="text"
class="control"
name="first_name"
value="{{ old('first_name') ?? $address->first_name }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.first_name') }}&quot;">
<span class="control-error" v-if="errors.has('first_name')" v-text="errors.first('first_name')"></span>
<span
class="control-error"
v-text="errors.first('first_name')"
v-if="errors.has('first_name')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.first_name.after') !!}
@ -44,9 +63,19 @@
<div class="control-group" :class="[errors.has('last_name') ? 'has-error' : '']">
<label for="last_name" class="mandatory">{{ __('shop::app.customer.account.address.create.last_name') }}</label>
<input type="text" class="control" name="last_name" value="{{ old('last_name') ?? $address->last_name }}" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.last_name') }}&quot;">
<input
class="control"
type="text"
name="last_name"
value="{{ old('last_name') ?? $address->last_name }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.last_name') }}&quot;">
<span class="control-error" v-if="errors.has('last_name')" v-text="errors.first('last_name')"></span>
<span
class="control-error"
v-text="errors.first('last_name')"
v-if="errors.has('last_name')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.last_name.after') !!}
@ -56,9 +85,19 @@
<span class="help-note">{{ __('shop::app.customer.account.address.create.vat_help_note') }}</span>
</label>
<input type="text" class="control" name="vat_id" value="{{ old('vat_id') ?? $address->vat_id }}" v-validate="" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.vat_id') }}&quot;">
<input
class="control"
type="text"
name="vat_id"
value="{{ old('vat_id') ?? $address->vat_id }}"
v-validate=""
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.vat_id') }}&quot;">
<span class="control-error" v-if="errors.has('vat_id')" v-text="errors.first('vat_id')"></span>
<span
class="control-error"
v-text="errors.first('vat_id')"
v-if="errors.has('vat_id')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.vat_id.after') !!}
@ -70,15 +109,30 @@
<div class="control-group" :class="[errors.has('address1[]') ? 'has-error' : '']">
<label for="address_0" class="mandatory">{{ __('shop::app.customer.account.address.edit.street-address') }}</label>
<input type="text" class="control" name="address1[]" value="{{ isset($addresses[0]) ? $addresses[0] : '' }}" id="address_0" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.street-address') }}&quot;">
<input
class="control"
id="address_0"
type="text"
name="address1[]"
value="{{ isset($addresses[0]) ? $addresses[0] : '' }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.street-address') }}&quot;">
<span class="control-error" v-text="'{{ $errors->first('address1.*') }}'"></span>
<span
class="control-error"
v-text="'{{ $errors->first('address1.*') }}'">
</span>
</div>
@if (core()->getConfigData('customer.settings.address.street_lines') && core()->getConfigData('customer.settings.address.street_lines') > 1)
@for ($i = 1; $i < core()->getConfigData('customer.settings.address.street_lines'); $i++)
<div class="control-group" style="margin-top: -25px;">
<input type="text" class="control" name="address1[{{ $i }}]" id="address_{{ $i }}" value="{{ $addresses[$i] ?? '' }}">
<input
class="control"
type="text"
name="address1[{{ $i }}]"
id="address_{{ $i }}"
value="{{ $addresses[$i] ?? '' }}">
</div>
@endfor
@endif
@ -92,19 +146,39 @@
<div class="control-group" :class="[errors.has('city') ? 'has-error' : '']">
<label for="city" class="mandatory">{{ __('shop::app.customer.account.address.create.city') }}</label>
<input type="text" class="control" name="city" value="{{ old('city') ?? $address->city }}" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.city') }}&quot;">
<input
class="control"
type="text"
name="city"
value="{{ old('city') ?? $address->city }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.city') }}&quot;">
<span class="control-error" v-if="errors.has('city')" v-text="errors.first('city')"></span>
<span
class="control-error"
v-text="errors.first('city')"
v-if="errors.has('city')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.create.after') !!}
<div class="control-group" :class="[errors.has('postcode') ? 'has-error' : '']">
<label for="postcode" class="mandatory">{{ __('shop::app.customer.account.address.create.postcode') }}</label>
<label for="postcode" class="{{ core()->isPostCodeRequired() ? 'mandatory' : '' }}">{{ __('shop::app.customer.account.address.create.postcode') }}</label>
<input type="text" class="control" name="postcode" value="{{ old('postcode') ?? $address->postcode }}" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.postcode') }}&quot;">
<input
class="control"
type="text"
name="postcode"
value="{{ old('postcode') ?? $address->postcode }}"
v-validate="'{{ core()->isPostCodeRequired() ? 'required' : '' }}'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.postcode') }}&quot;">
<span class="control-error" v-if="errors.has('postcode')" v-text="errors.first('postcode')"></span>
<span
class="control-error"
v-text="errors.first('postcode')"
v-if="errors.has('postcode')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.postcode.after') !!}
@ -112,15 +186,30 @@
<div class="control-group" :class="[errors.has('phone') ? 'has-error' : '']">
<label for="phone" class="mandatory">{{ __('shop::app.customer.account.address.create.phone') }}</label>
<input type="text" class="control" name="phone" value="{{ old('phone') ?? $address->phone }}" v-validate="'required'" data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.phone') }}&quot;">
<input
class="control"
type="text"
name="phone"
value="{{ old('phone') ?? $address->phone }}"
v-validate="'required'"
data-vv-as="&quot;{{ __('shop::app.customer.account.address.create.phone') }}&quot;">
<span class="control-error" v-if="errors.has('phone')" v-text="errors.first('phone')"></span>
<span
class="control-error"
v-text="errors.first('phone')"
v-if="errors.has('phone')">
</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.address.edit_form_controls.after', ['address' => $address]) !!}
<div class="control-group d-flex">
<input type="checkbox" id="default_address" class="w-auto" name="default_address" {{ $address->default_address ? 'checked' : '' }} >
<input
class="w-auto"
id="default_address"
type="checkbox"
name="default_address"
{{ $address->default_address ? 'checked' : '' }}>
<label class="checkbox-view" for="default_address"></label>

View File

@ -39,13 +39,12 @@
<h5 class="card-title fw6">{{ $address->first_name }} {{ $address->last_name }}</h5>
<ul type="none">
{{-- <li>{{ $address->company_name }}</li> --}}
<li>{{ $address->address1 }},</li>
<li>{{ $address->city }},</li>
<li>{{ $address->state }},</li>
<li>{{ $address->address1 }}</li>
<li>{{ $address->city }}</li>
<li>{{ $address->state }}</li>
<li>{{ core()->country_name($address->country) }} {{ $address->postcode }}</li>
<li>
{{ __('shop::app.customer.account.address.index.contact') }} : {{$address->phone }}
{{ __('shop::app.customer.account.address.index.contact') }} : {{ $address->phone }}
</li>
</ul>
@ -59,6 +58,7 @@
<form id="deleteAddressForm" action="{{ route('address.delete', $address->id) }}" method="post">
@method('delete')
@csrf
</form>
</div>

View File

@ -4,23 +4,26 @@ namespace Tests\Functional\Checkout\Order;
use Faker\Factory;
use FunctionalTester;
use Webkul\Sales\Models\Order;
use Webkul\Core\Models\Channel;
use Webkul\Customer\Models\Customer;
use Webkul\Sales\Models\OrderAddress;
use Webkul\Sales\Models\OrderPayment;
use Webkul\Checkout\Models\CartAddress;
use Webkul\Checkout\Models\CartPayment;
use Webkul\Core\Models\Channel;
use Webkul\Customer\Models\Customer;
use Webkul\Sales\Models\Order;
use Webkul\Sales\Models\OrderAddress;
use Webkul\Sales\Models\OrderPayment;
/**
* Class OrderCest
* OrderCest class.
*
* @package Tests\Functional\Checkout\Cart
*/
class OrderCest
{
/**
* @param \FunctionalTester $I
* Test checkout as customer.
*
* @param \FunctionalTester $I
* @return void
*/
public function testCheckoutAsCustomer(FunctionalTester $I)
{
@ -28,7 +31,7 @@ class OrderCest
$faker = Factory::create();
$addressData = [
$addressData = $this->cleanAllFields([
'city' => $faker->city,
'company_name' => $faker->company,
'country' => $faker->countryCode,
@ -38,16 +41,20 @@ class OrderCest
'phone' => $faker->phoneNumber,
'postcode' => $faker->postcode,
'state' => $faker->state,
];
]);
$mocks = $I->prepareCart([
'customer' => $customer,
]);
// assert that checkout can be reached and generate csrf token
/**
* Assert that checkout can be reached and generate csrf token.
*/
$I->amOnRoute('shop.checkout.onepage.index');
// simulate the entering of the address(es)
/**
* Simulate the entering of the address(es).
*/
$I->sendAjaxPostRequest(route('shop.checkout.save-address'), [
'_token' => csrf_token(),
'billing' => array_merge($addressData, [
@ -98,7 +105,9 @@ class OrderCest
'cart_id' => $mocks['cart']->id,
]);
// simulate click on the 'place order' button at the last step
/**
* Simulate click on the 'place order' button at the last step.
*/
$I->sendAjaxPostRequest(
route('shop.checkout.save-order'),
['_token' => csrf_token()]
@ -143,4 +152,28 @@ class OrderCest
'order_id' => $order->id,
]);
}
/**
* Clean all fields.
*
* @param array $fields
* @return array
*/
private function cleanAllFields(array $fields)
{
return collect($fields)->map(function ($field, $key) {
return $this->cleanField($field);
})->toArray();
}
/**
* Clean fields.
*
* @param string $field
* @return string
*/
private function cleanField($field)
{
return preg_replace('/[^A-Za-z0-9 ]/', '', $field);
}
}