Resolve conflicts

This commit is contained in:
jitendra 2021-01-04 21:43:35 +05:30
commit 65d37fe6de
142 changed files with 4293 additions and 1416 deletions

View File

@ -66,7 +66,7 @@ Take advantage of two of the hottest frameworks used in this project -- Laravel
* **OS**: Ubuntu 16.04 LTS or higher / Windows 7 or Higher (WampServer / XAMPP).
* **SERVER**: Apache 2 or NGINX.
* **RAM**: 3 GB or higher.
* **PHP**: 7.2.0 or higher.
* **PHP**: 7.3 or higher.
* **Processor**: Clock Cycle 1 Ghz or higher.
* **For MySQL users**: 5.7.23 or higher.
* **For MariaDB users**: 10.2.7 or Higher.

View File

@ -14,7 +14,7 @@ class Kernel extends HttpKernel
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Webkul\Core\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,

View File

@ -13,7 +13,7 @@ class AuthServiceProvider extends ServiceProvider
* @var array
*/
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
// 'App\Model' => 'App\Policies\ModelPolicy',
];
/**

View File

@ -23,6 +23,7 @@
"babenkoivan/elastic-scout-driver": "^1.1",
"bagisto/bagisto-package-generator": "9999999-dev",
"bagistobrasil/bagisto-product-social-share": "^0.1.2",
"barryvdh/laravel-debugbar": "^3.1",
"barryvdh/laravel-dompdf": "0.8.6",
"doctrine/dbal": "2.9.2",
"fideloper/proxy": "^4.2",
@ -45,7 +46,6 @@
},
"require-dev": {
"barryvdh/laravel-debugbar": "^3.1",
"codeception/codeception": "4.1.1",
"codeception/module-asserts": "^1.1",
"codeception/module-filesystem": "^1.0",
@ -154,6 +154,13 @@
"vendor/bin/codecept run unit",
"vendor/bin/codecept run functional",
"vendor/bin/codecept run trigger"
],
"test-win": [
"@set -e",
"@php artisan migrate:fresh --env=testing",
"vendor\\bin\\codecept.bat run unit",
"vendor\\bin\\codecept.bat run functional",
"vendor\\bin\\codecept.bat run trigger"
]
},
"config": {

2619
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,9 +2,9 @@
namespace Webkul\API\Providers;
use Konekt\Concord\BaseModuleServiceProvider;
use Webkul\Core\Providers\CoreModuleServiceProvider;
class ModuleServiceProvider extends BaseModuleServiceProvider
class ModuleServiceProvider extends CoreModuleServiceProvider
{
protected $models = [
];

View File

@ -218,6 +218,10 @@ return [
],
],
'channel_based' => true,
], [
'name' => 'buy_now_button_display',
'title' => 'admin::app.admin.system.buy-now-button-display',
'type' => 'boolean',
]
],
], [

View File

@ -2,18 +2,61 @@
namespace Webkul\Admin\DataGrids;
use Illuminate\Support\Facades\DB;
use Webkul\Ui\DataGrid\DataGrid;
use Webkul\Core\Repositories\ChannelRepository;
class ChannelDataGrid extends DataGrid
{
/**
* Assign primary key.
*/
protected $index = 'id';
/**
* Sort order.
*/
protected $sortOrder = 'desc';
/**
* Filter Locale.
*/
protected $locale;
/**
* ChannelRepository $channelRepository
*
* @var \Webkul\Core\Repositories\ChannelRepository
*/
protected $channelRepository;
/**
* Create a new datagrid instance.
*
* @param \Webkul\Core\Repositories\ChannelRepository $channelRepository
* @return void
*/
public function __construct(
ChannelRepository $channelRepository
)
{
parent::__construct();
$this->locale = request()->get('locale') ?? app()->getLocale();
$this->channelRepository = $channelRepository;
}
public function prepareQueryBuilder()
{
$queryBuilder = DB::table('channels')->addSelect('id', 'code', 'name', 'hostname');
$queryBuilder = $this->channelRepository->query()
->leftJoin('channel_translations', 'channel_translations.channel_id', '=', 'channels.id')
->addSelect('channels.id', 'channels.code', 'channel_translations.locale', 'channel_translations.name as translated_name', 'channels.hostname')
->where('channel_translations.locale', '=', $this->locale);
$this->addFilter('id', 'channels.id');
$this->addFilter('code', 'channels.code');
$this->addFilter('hostname', 'channels.hostname');
$this->addFilter('translated_name', 'channel_translations.name');
$this->setQueryBuilder($queryBuilder);
}
@ -39,7 +82,7 @@ class ChannelDataGrid extends DataGrid
]);
$this->addColumn([
'index' => 'name',
'index' => 'translated_name',
'label' => trans('admin::app.datagrid.name'),
'type' => 'string',
'searchable' => true,

View File

@ -2,12 +2,13 @@
namespace Webkul\Admin\DataGrids;
use Illuminate\Support\Facades\DB;
use Webkul\Core\Models\Channel;
use Webkul\Ui\DataGrid\DataGrid;
use Illuminate\Support\Facades\DB;
class SliderDataGrid extends DataGrid
{
protected $index = 'slider_id';
protected $index = 'id';
protected $sortOrder = 'desc';
@ -15,7 +16,11 @@ class SliderDataGrid extends DataGrid
protected $channel = 'all';
/** @var string[] contains the keys for which extra filters to render */
/**
* Contains the keys for which extra filters to render.
*
* @var string[]
**/
protected $extraFilters = [
'channels',
'locales',
@ -26,25 +31,32 @@ class SliderDataGrid extends DataGrid
parent::__construct();
$this->locale = request()->get('locale') ?? 'all';
$this->channel = request()->get('channel') ?? 'all';
$this->channel = request()->get('channel')
? Channel::find(request()->get('channel'))->code
: 'all';
}
public function prepareQueryBuilder()
{
$queryBuilder = DB::table('sliders as sl')
->addSelect('sl.id as slider_id', 'sl.title', 'sl.locale', 'ch.name', 'ch.code')
->leftJoin('channels as ch', 'sl.channel_id', '=', 'ch.id');
->select('sl.id', 'sl.title', 'sl.locale', 'ct.channel_id', 'ct.name', 'ch.code')
->leftJoin('channels as ch', 'sl.channel_id', '=', 'ch.id')
->leftJoin('channel_translations as ct', 'ch.id', '=', 'ct.channel_id')
->where('ct.locale', app()->getLocale());
if ($this->locale !== 'all') {
$queryBuilder->where('locale', $this->locale);
$queryBuilder->where('sl.locale', $this->locale);
}
if ($this->channel !== 'all') {
$queryBuilder->where('ch.code', $this->channel);
}
$this->addFilter('slider_id', 'sl.id');
$this->addFilter('channel_name', 'ch.name');
$this->addFilter('id', 'sl.id');
$this->addFilter('title', 'sl.title');
$this->addFilter('locale', 'sl.locale');
$this->addFilter('channel_name', 'ct.name');
$this->addFilter('code', 'ch.code');
$this->setQueryBuilder($queryBuilder);
}
@ -52,7 +64,7 @@ class SliderDataGrid extends DataGrid
public function addColumns()
{
$this->addColumn([
'index' => 'slider_id',
'index' => 'id',
'label' => trans('admin::app.datagrid.id'),
'type' => 'number',
'searchable' => false,

View File

@ -0,0 +1,23 @@
<?php
namespace Webkul\Admin\Listeners;
use Illuminate\Support\Facades\Artisan;
class ChannelSettingsChange
{
/**
* Check for maintenance mode and set according to settings.
*
* @param \Webkul\Core\Models\Channel $channel
* @return void
*/
public function checkForMaintenaceMode($channel)
{
if ((bool) $channel->is_maintenance_on) {
Artisan::call('down');
} else {
Artisan::call('up');
}
}
}

View File

@ -35,7 +35,7 @@ class Order
/* email to admin */
$configKey = 'emails.general.notifications.emails.general.notifications.new-admin';
if (core()->getConfigData($configKey)) {
$this->prepareMail(env('APP_LOCALE'), new NewAdminNotification($order));
$this->prepareMail(config('app.locale'), new NewAdminNotification($order));
}
} catch (\Exception $e) {
report($e);
@ -112,7 +112,7 @@ class Order
/* email to admin */
$configKey = 'emails.general.notifications.emails.general.notifications.new-inventory-source';
if (core()->getConfigData($configKey)) {
$this->prepareMail(env('APP_LOCALE'), new NewInventorySourceNotification($shipment));
$this->prepareMail(config('app.locale'), new NewInventorySourceNotification($shipment));
}
} catch (\Exception $e) {
report($e);
@ -137,7 +137,7 @@ class Order
/* email to admin */
$configKey = 'emails.general.notifications.emails.general.notifications.new-admin';
if (core()->getConfigData($configKey)) {
$this->prepareMail(env('APP_LOCALE'), new CancelOrderAdminNotification($order));
$this->prepareMail(config('app.locale'), new CancelOrderAdminNotification($order));
}
} catch (\Exception $e) {
report($e);
@ -189,4 +189,4 @@ class Order
app()->setLocale($locale);
Mail::queue($notification);
}
}
}

View File

@ -27,5 +27,7 @@ class EventServiceProvider extends ServiceProvider
Event::listen('sales.refund.save.after','Webkul\Admin\Listeners\Order@sendNewRefundMail');
Event::listen('sales.order.comment.create.after','Webkul\Admin\Listeners\Order@sendOrderCommentMail');
Event::listen('core.channel.update.after','Webkul\Admin\Listeners\ChannelSettingsChange@checkForMaintenaceMode');
}
}

View File

@ -2,9 +2,9 @@
namespace Webkul\Admin\Providers;
use Konekt\Concord\BaseModuleServiceProvider;
use Webkul\Core\Providers\CoreModuleServiceProvider;
class ModuleServiceProvider extends BaseModuleServiceProvider
class ModuleServiceProvider extends CoreModuleServiceProvider
{
protected $models = [
];

View File

@ -816,7 +816,9 @@ return [
'seo-title' => 'عنوان Meta',
'seo-description' => 'وصف Meta',
'seo-keywords' => 'الكلمات الدالة Meta',
'maintenance-mode' => 'Maintenance Mode',
'maintenance-mode-text' => 'Message',
'allowed-ips' => 'Allowed IPs'
],
'sliders' => [
@ -1355,6 +1357,7 @@ return [
'description' => 'وصف',
'rate' => 'معدل',
'status' => 'الحالة',
'calculate-tax' => 'احسب الضريبة',
'type' => 'اكتب',
'payment-methods' => 'طرق الدفع',
'cash-on-delivery' => 'الدفع عند الاستلام',
@ -1446,7 +1449,8 @@ return [
'client-secret' => 'Client Secret',
'client-secret-info' => 'Add your secret key here',
'accepted-currencies' => 'Accepted currencies',
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...'
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...',
'buy-now-button-display' => 'Allow customers to directly buy products'
]
]
];

View File

@ -815,6 +815,9 @@ return [
'seo-title' => 'Meta Titel',
'seo-description' => 'Meta-Beschreibung',
'seo-keywords' => 'Meta-keywords',
'maintenance-mode' => 'Maintenance Mode',
'maintenance-mode-text' => 'Message',
'allowed-ips' => 'Allowed IPs'
],
'sliders' =>
[
@ -1362,6 +1365,7 @@ return [
'description' => 'Beschreibung',
'rate' => 'Rate',
'status' => 'Status',
'calculate-tax' => 'Steuern berechnen',
'type' => 'Typ',
'payment-methods' => 'Zahlungsmethoden',
'cash-on-delivery' => 'Nachnahme',
@ -1421,7 +1425,8 @@ return [
'client-secret' => 'Client Secret',
'client-secret-info' => 'Add your secret key here',
'accepted-currencies' => 'Accepted currencies',
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...'
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...',
'buy-now-button-display' => 'Allow customers to directly buy products'
],
],
];

View File

@ -825,7 +825,9 @@ return [
'seo-title' => 'Meta title',
'seo-description' => 'Meta description',
'seo-keywords' => 'Meta keywords',
'maintenance-mode' => 'Maintenance Mode',
'maintenance-mode-text' => 'Message',
'allowed-ips' => 'Allowed IPs'
],
'sliders' => [
@ -1369,6 +1371,7 @@ return [
'description' => 'Description',
'rate' => 'Rate',
'status' => 'Status',
'calculate-tax' => 'Calculate Tax',
'type' => 'Type',
'payment-methods' => 'Payment Methods',
'cash-on-delivery' => 'Cash On Delivery',
@ -1455,7 +1458,8 @@ return [
'client-secret' => 'Client Secret',
'client-secret-info' => 'Add your secret key here',
'accepted-currencies' => 'Accepted currencies',
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...'
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...',
'buy-now-button-display' => 'Allow customers to directly buy products'
]
]
];

View File

@ -809,7 +809,9 @@ return [
'seo-title' => 'Meta title',
'seo-description' => 'Meta description',
'seo-keywords' => 'Meta keywords',
'maintenance-mode' => 'Maintenance Mode',
'maintenance-mode-text' => 'Message',
'allowed-ips' => 'Allowed IPs'
],
'sliders' => [
@ -1344,6 +1346,7 @@ return [
'description' => 'Descripción',
'rate' => 'Tasa',
'status' => 'Estado',
'calculate-tax' => 'Calcular impuestos',
'type' => 'Tipo',
'payment-methods' => 'Métodos de pago',
'cash-on-delivery' => 'Pago contraentrega',
@ -1402,7 +1405,8 @@ return [
'client-secret' => 'Client Secret',
'client-secret-info' => 'Add your secret key here',
'accepted-currencies' => 'Accepted currencies',
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...'
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...',
'buy-now-button-display' => 'Allow customers to directly buy products'
]
]
];

View File

@ -814,7 +814,9 @@ return [
'seo-title' => 'عنوان Meta',
'seo-description' => 'شرح Meta',
'seo-keywords' => 'کلید واژه ها Meta',
'maintenance-mode' => 'Maintenance Mode',
'maintenance-mode-text' => 'Message',
'allowed-ips' => 'Allowed IPs'
],
'sliders' => [
@ -1352,6 +1354,7 @@ return [
'description' => 'توضیحات',
'rate' => 'نرخ',
'status' => 'وضعیت',
'calculate-tax' => 'محاسبه مالیات',
'type' => 'نوع',
'payment-methods' => 'روش های پرداخت',
'cash-on-delivery' => 'پرداخت در محل',
@ -1440,7 +1443,8 @@ return [
'client-secret' => 'Client Secret',
'client-secret-info' => 'Add your secret key here',
'accepted-currencies' => 'Accepted currencies',
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...'
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...',
'buy-now-button-display' => 'Allow customers to directly buy products'
]
]
];

View File

@ -818,7 +818,9 @@ return [
'seo-title' => 'Meta title',
'seo-description' => 'Meta description',
'seo-keywords' => 'Meta keywords',
'maintenance-mode' => 'Maintenance Mode',
'maintenance-mode-text' => 'Message',
'allowed-ips' => 'Allowed IPs'
],
'sliders' => [
@ -1355,6 +1357,7 @@ return [
'description' => 'Descrizione',
'rate' => 'Tasso',
'status' => 'Stato',
'calculate-tax' => 'Calcola le tasse',
'type' => 'Tipo',
'payment-methods' => 'Metodi di Pagamento',
'cash-on-delivery' => 'Contrassegno',
@ -1443,7 +1446,8 @@ return [
'client-secret' => 'Client Secret',
'client-secret-info' => 'Add your secret key here',
'accepted-currencies' => 'Accepted currencies',
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...'
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...',
'buy-now-button-display' => 'Allow customers to directly buy products'
]
]
];

View File

@ -815,7 +815,9 @@ return [
'seo-title' => 'Meta titel',
'seo-description' => 'Meta omschrijving',
'seo-keywords' => 'Meta trefwoorden',
'maintenance-mode' => 'Maintenance Mode',
'maintenance-mode-text' => 'Message',
'allowed-ips' => 'Allowed IPs'
],
'sliders' => [
@ -1351,6 +1353,7 @@ return [
'description' => 'Omschrijving',
'rate' => 'Tarief',
'status' => 'Toestand',
'calculate-tax' => 'Beregn skat',
'type' => 'Type',
'payment-methods' => 'Betaalmethodes',
'cash-on-delivery' => 'Rembours',
@ -1438,7 +1441,8 @@ return [
'client-secret' => 'Client Secret',
'client-secret-info' => 'Add your secret key here',
'accepted-currencies' => 'Accepted currencies',
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...'
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...',
'buy-now-button-display' => 'Allow customers to directly buy products'
]
]
];

View File

@ -816,7 +816,9 @@ return [
'seo-title' => 'Meta tytuł',
'seo-description' => 'Meta opis',
'seo-keywords' => 'Meta słowa kluczowe',
'maintenance-mode' => 'Maintenance Mode',
'maintenance-mode-text' => 'Message',
'allowed-ips' => 'Allowed IPs'
],
'sliders' => [
@ -1352,6 +1354,7 @@ return [
'description' => 'Opis',
'rate' => 'Stawka',
'status' => 'Status',
'calculate-tax' => 'Oblicz podatek',
'type' => 'Rodzaj',
'payment-methods' => 'Metody płatności',
'cash-on-delivery' => 'Za pobraniem',
@ -1427,7 +1430,8 @@ return [
'client-secret' => 'Client Secret',
'client-secret-info' => 'Add your secret key here',
'accepted-currencies' => 'Accepted currencies',
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...'
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...',
'buy-now-button-display' => 'Allow customers to directly buy products'
]
]
];

View File

@ -815,7 +815,9 @@ return [
'seo-title' => 'Meta título',
'seo-description' => 'Meta Descrição',
'seo-keywords' => 'Meta palavras-chave',
'maintenance-mode' => 'Maintenance Mode',
'maintenance-mode-text' => 'Message',
'allowed-ips' => 'Allowed IPs'
],
'sliders' => [
@ -1351,6 +1353,7 @@ return [
'description' => 'Descrição',
'rate' => 'Taxa',
'status' => 'Status',
'calculate-tax' => 'Calcular o imposto',
'type' => 'Tipo',
'payment-methods' => 'Métodos de Pagamento',
'cash-on-delivery' => 'Dinheiro na entrega',
@ -1441,7 +1444,8 @@ return [
'client-secret' => 'Client Secret',
'client-secret-info' => 'Add your secret key here',
'accepted-currencies' => 'Accepted currencies',
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...'
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...',
'buy-now-button-display' => 'Allow customers to directly buy products'
]
]
];

View File

@ -807,7 +807,9 @@ return [
'seo-title' => 'Meta Başlık',
'seo-description' => 'Meta Açıklama',
'seo-keywords' => 'Meta Anahtar Kelimeler',
'maintenance-mode' => 'Maintenance Mode',
'maintenance-mode-text' => 'Message',
'allowed-ips' => 'Allowed IPs'
],
'sliders' => [
@ -1339,6 +1341,7 @@ return [
'description' => 'Açıklama',
'rate' => 'Oran',
'status' => 'Durum',
'calculate-tax' => 'Vergiyi Hesapla',
'type' => 'Tipi',
'payment-methods' => 'Ödeme Türleri',
'cash-on-delivery' => 'Kapıda Ödeme',
@ -1424,7 +1427,8 @@ return [
'client-secret' => 'Client Secret',
'client-secret-info' => 'Add your secret key here',
'accepted-currencies' => 'Accepted currencies',
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...'
'accepted-currencies-info' => 'Add currency code comma seperated e.g. USD,INR,...',
'buy-now-button-display' => 'Allow customers to directly buy products'
]
]
];

View File

@ -127,7 +127,7 @@
@elseif ($field['type'] == 'textarea')
<textarea v-validate="'{{ $validations }}'" class="control" id="{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]" name="{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]" data-vv-as="&quot;{{ trans($field['title']) }}&quot;">{{ old($name) ? core()->getConfigData($name) : (isset($field['default_value']) ? $field['default_value'] : '') }}</textarea>
<textarea v-validate="'{{ $validations }}'" class="control" id="{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]" name="{{ $firstField }}[{{ $secondField }}][{{ $thirdField }}][{{ $field['name'] }}]" data-vv-as="&quot;{{ trans($field['title']) }}&quot;">{{ old($name) ?: core()->getConfigData($name) ?: (isset($field['default_value']) ? $field['default_value'] : '') }}</textarea>
@elseif ($field['type'] == 'select')

View File

@ -20,7 +20,7 @@
</div>
<div class="error-messgae" style="font-size: 24px;color: #5E5E5E">
{{ __('admin::app.error.right-back') }}
{{ core()->getCurrentChannel()->maintenance_mode_text ?: __('admin::app.error.right-back') }}
</div>
</div>

View File

@ -30,6 +30,7 @@
{!! view_render_event('bagisto.admin.settings.channel.create.before') !!}
{{-- general --}}
<accordian :title="'{{ __('admin::app.settings.channels.general') }}'" :active="true">
<div slot="body">
@ -84,6 +85,7 @@
</div>
</accordian>
{{-- currencies and locales --}}
<accordian :title="'{{ __('admin::app.settings.channels.currencies-and-locales') }}'" :active="true">
<div slot="body">
@ -138,6 +140,7 @@
</div>
</accordian>
{{-- design --}}
<accordian :title="'{{ __('admin::app.settings.channels.design') }}'" :active="true">
<div slot="body">
<div class="control-group">
@ -176,6 +179,7 @@
</div>
</accordian>
{{-- home page seo --}}
<accordian :title="'{{ __('admin::app.settings.channels.seo') }}'" :active="true">
<div slot="body">
<div class="control-group" :class="[errors.has('seo_title') ? 'has-error' : '']">
@ -202,6 +206,30 @@
</div>
</accordian>
{{-- maintenance mode --}}
<accordian title="{{ __('admin::app.settings.channels.maintenance-mode') }}" :active="true">
<div slot="body">
<div class="control-group">
<label for="maintenance-mode-status">{{ __('admin::app.status') }}</label>
<label class="switch">
<input type="hidden" name="is_maintenance_on" value="0" />
<input type="checkbox" id="maintenance-mode-status" name="is_maintenance_on" value="1">
<span class="slider round"></span>
</label>
</div>
<div class="control-group">
<label for="maintenance-mode-text">{{ __('admin::app.settings.channels.maintenance-mode-text') }}</label>
<input class="control" id="maintenance-mode-text" name="maintenance_mode_text" value=""/>
</div>
<div class="control-group">
<label for="allowed-ips">{{ __('admin::app.settings.channels.allowed-ips') }}</label>
<input class="control" id="allowed-ips" name="allowed_ips" value=""/>
</div>
</div>
</accordian>
{!! view_render_event('bagisto.admin.settings.channel.create.after') !!}
</div>
</div>

View File

@ -6,8 +6,9 @@
@section('content')
<div class="content">
@php $locale = request()->get('locale') ?: app()->getLocale(); @endphp
<form method="POST" action="{{ route('admin.channels.update', $channel->id) }}" @submit.prevent="onSubmit" enctype="multipart/form-data">
<form method="POST" action="{{ route('admin.channels.update', ['id' => $channel->id, 'locale' => $locale]) }}" @submit.prevent="onSubmit" enctype="multipart/form-data">
<div class="page-header">
<div class="page-title">
<h1>
@ -15,6 +16,18 @@
{{ __('admin::app.settings.channels.edit-title') }}
</h1>
<div class="control-group">
<select class="control" id="locale-switcher" onChange="window.location.href = this.value">
@foreach (core()->getAllLocales() as $localeModel)
<option value="{{ route('admin.channels.edit', $channel->id) . '?locale=' . $localeModel->code }}" {{ ($localeModel->code) == $locale ? 'selected' : '' }}>
{{ $localeModel->name }}
</option>
@endforeach
</select>
</div>
</div>
<div class="page-action">
@ -25,12 +38,14 @@
</div>
<div class="page-content">
<div class="form-container">
@csrf()
<input name="_method" type="hidden" value="PUT">
{!! view_render_event('bagisto.admin.settings.channel.edit.before') !!}
{{-- general --}}
<accordian :title="'{{ __('admin::app.settings.channels.general') }}'" :active="true">
<div slot="body">
@ -41,15 +56,21 @@
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
</div>
<div class="control-group" :class="[errors.has('name') ? 'has-error' : '']">
<label for="name" class="required">{{ __('admin::app.settings.channels.name') }}</label>
<input v-validate="'required'" class="control" id="name" name="name" data-vv-as="&quot;{{ __('admin::app.settings.channels.name') }}&quot;" value="{{ old('name') ?: $channel->name }}"/>
<span class="control-error" v-if="errors.has('name')">@{{ errors.first('name') }}</span>
<div class="control-group" :class="[errors.has('{{$locale}}[name]') ? 'has-error' : '']">
<label for="name" class="required">
{{ __('admin::app.settings.channels.name') }}
<span class="locale">[{{ $locale }}]</span>
</label>
<input v-validate="'required'" class="control" id="name" name="{{$locale}}[name]" data-vv-as="&quot;{{ __('admin::app.settings.channels.name') }}&quot;" value="{{ old($locale)['name'] ?? ($channel->translate($locale)['name'] ?? '') }}"/>
<span class="control-error" v-if="errors.has('{{$locale}}[name]')">@{{ errors.first('{!!$locale!!}[page_title]') }}</span>
</div>
<div class="control-group">
<label for="description">{{ __('admin::app.settings.channels.description') }}</label>
<textarea class="control" id="description" name="description">{{ old('description') ?: $channel->description }}</textarea>
<label for="description">
{{ __('admin::app.settings.channels.description') }}
<span class="locale">[{{ $locale }}]</span>
</label>
<textarea class="control" id="description" name="{{$locale}}[description]">{{ old($locale)['description'] ?? ($channel->translate($locale)['description'] ?? '') }}</textarea>
</div>
<div class="control-group" :class="[errors.has('inventory_sources[]') ? 'has-error' : '']">
@ -88,6 +109,7 @@
</div>
</accordian>
{{-- currencies and locales --}}
<accordian :title="'{{ __('admin::app.settings.channels.currencies-and-locales') }}'" :active="true">
<div slot="body">
@ -95,9 +117,9 @@
<label for="locales" class="required">{{ __('admin::app.settings.channels.locales') }}</label>
<?php $selectedOptionIds = old('locales') ?: $channel->locales->pluck('id')->toArray() ?>
<select v-validate="'required'" class="control" id="locales" name="locales[]" data-vv-as="&quot;{{ __('admin::app.settings.channels.locales') }}&quot;" multiple>
@foreach (core()->getAllLocales() as $locale)
<option value="{{ $locale->id }}" {{ in_array($locale->id, $selectedOptionIds) ? 'selected' : '' }}>
{{ $locale->name }}
@foreach (core()->getAllLocales() as $localeModel)
<option value="{{ $localeModel->id }}" {{ in_array($localeModel->id, $selectedOptionIds) ? 'selected' : '' }}>
{{ $localeModel->name }}
</option>
@endforeach
</select>
@ -108,9 +130,9 @@
<label for="default_locale_id" class="required">{{ __('admin::app.settings.channels.default-locale') }}</label>
<?php $selectedOption = old('default_locale_id') ?: $channel->default_locale_id ?>
<select v-validate="'required'" class="control" id="default_locale_id" name="default_locale_id" data-vv-as="&quot;{{ __('admin::app.settings.channels.default-locale') }}&quot;">
@foreach (core()->getAllLocales() as $locale)
<option value="{{ $locale->id }}" {{ $selectedOption == $locale->id ? 'selected' : '' }}>
{{ $locale->name }}
@foreach (core()->getAllLocales() as $localeModel)
<option value="{{ $localeModel->id }}" {{ $selectedOption == $localeModel->id ? 'selected' : '' }}>
{{ $localeModel->name }}
</option>
@endforeach
</select>
@ -146,6 +168,7 @@
</div>
</accordian>
{{-- design --}}
<accordian :title="'{{ __('admin::app.settings.channels.design') }}'" :active="true">
<div slot="body">
<div class="control-group">
@ -163,13 +186,19 @@
</div>
<div class="control-group">
<label for="home_page_content">{{ __('admin::app.settings.channels.home_page_content') }}</label>
<textarea class="control" id="home_page_content" name="home_page_content">{{ old('home_page_content') ?: $channel->home_page_content }}</textarea>
<label for="home_page_content">
{{ __('admin::app.settings.channels.home_page_content') }}
<span class="locale">[{{ $locale }}]</span>
</label>
<textarea class="control" id="home_page_content" name="{{$locale}}[home_page_content]">{{ old($locale)['home_page_content'] ?? ($channel->translate($locale)['home_page_content'] ?? '') }}</textarea>
</div>
<div class="control-group">
<label for="footer_content">{{ __('admin::app.settings.channels.footer_content') }}</label>
<textarea class="control" id="footer_content" name="footer_content">{{ old('footer_content') ?: $channel->footer_content }}</textarea>
<label for="footer_content">
{{ __('admin::app.settings.channels.footer_content') }}
<span class="locale">[{{ $locale }}]</span>
</label>
<textarea class="control" id="footer_content" name="{{$locale}}[footer_content]">{{ old($locale)['footer_content'] ?? ($channel->translate($locale)['footer_content'] ?? '') }}</textarea>
</div>
<div class="control-group">
@ -188,31 +217,71 @@
</accordian>
@php
$seo = json_decode($channel->home_seo);
$home_seo = $channel->translate($locale)['home_seo'] ?? '{}';
$seo = json_decode($home_seo);
@endphp
{{-- home page seo --}}
<accordian :title="'{{ __('admin::app.settings.channels.seo') }}'" :active="true">
<div slot="body">
<div class="control-group" :class="[errors.has('seo_title') ? 'has-error' : '']">
<label for="seo_title" class="required">{{ __('admin::app.settings.channels.seo-title') }}</label>
<input v-validate="'required'" class="control" id="seo_title" name="seo_title" data-vv-as="&quot;{{ __('admin::app.settings.channels.seo-title') }}&quot;" value="{{ $seo->meta_title ?? old('seo_title') }}"/>
<span class="control-error" v-if="errors.has('seo_title')">@{{ errors.first('seo_title') }}</span>
<div class="control-group" :class="[errors.has('{{$locale}}[seo_title]') ? 'has-error' : '']">
<label for="seo_title" class="required">
{{ __('admin::app.settings.channels.seo-title') }}
<span class="locale">[{{ $locale }}]</span>
</label>
<input v-validate="'required'" class="control" id="seo_title" name="{{$locale}}[seo_title]" data-vv-as="&quot;{{ __('admin::app.settings.channels.seo-title') }}&quot;" value="{{ $seo->meta_title ?? (old($locale)['seo_title'] ?? '') }}"/>
<span class="control-error" v-if="errors.has('{{$locale}}[seo_title]')">@{{ errors.first('{!!$locale!!}[page_title]') }}</span>
</div>
<div class="control-group" :class="[errors.has('seo_description') ? 'has-error' : '']">
<label for="seo_description" class="required">{{ __('admin::app.settings.channels.seo-description') }}</label>
<div class="control-group" :class="[errors.has('{{$locale}}[seo_description]') ? 'has-error' : '']">
<label for="seo_description" class="required">
{{ __('admin::app.settings.channels.seo-description') }}
<span class="locale">[{{ $locale }}]</span>
</label>
<textarea v-validate="'required'" class="control" id="seo_description" name="seo_description" data-vv-as="&quot;{{ __('admin::app.settings.channels.seo-description') }}&quot;">{{ $seo->meta_description ?? old('seo_description') }}</textarea>
<textarea v-validate="'required'" class="control" id="seo_description" name="{{$locale}}[seo_description]" data-vv-as="&quot;{{ __('admin::app.settings.channels.seo-description') }}&quot;">{{ $seo->meta_description ?? (old($locale)['seo_description'] ?? '') }}</textarea>
<span class="control-error" v-if="errors.has('seo_description')">@{{ errors.first('seo_description') }}</span>
<span class="control-error" v-if="errors.has('{{$locale}}[seo_description]')">@{{ errors.first('{!!$locale!!}[page_title]') }}</span>
</div>
<div class="control-group" :class="[errors.has('seo_keywords') ? 'has-error' : '']">
<label for="seo_keywords" class="required">{{ __('admin::app.settings.channels.seo-keywords') }}</label>
<div class="control-group" :class="[errors.has('{{$locale}}[seo_keywords]') ? 'has-error' : '']">
<label for="seo_keywords" class="required">
{{ __('admin::app.settings.channels.seo-keywords') }}
<span class="locale">[{{ $locale }}]</span>
</label>
<textarea v-validate="'required'" class="control" id="seo_keywords" name="seo_keywords" data-vv-as="&quot;{{ __('admin::app.settings.channels.seo-keywords') }}&quot;">{{ $seo->meta_keywords ?? old('seo_keywords') }}</textarea>
<textarea v-validate="'required'" class="control" id="seo_keywords" name="{{$locale}}[seo_keywords]" data-vv-as="&quot;{{ __('admin::app.settings.channels.seo-keywords') }}&quot;">{{ $seo->meta_keywords ?? (old($locale)['seo_keywords'] ?? '') }}</textarea>
<span class="control-error" v-if="errors.has('seo_keywords')">@{{ errors.first('seo_keywords') }}</span>
<span class="control-error" v-if="errors.has('{{$locale}}[seo_keywords]')">@{{ errors.first('{!!$locale!!}[page_title]') }}</span>
</div>
</div>
</accordian>
{{-- maintenance mode --}}
<accordian title="{{ __('admin::app.settings.channels.maintenance-mode') }}" :active="true">
<div slot="body">
<div class="control-group">
<label for="maintenance-mode-status">{{ __('admin::app.status') }}</label>
<label class="switch">
<input type="hidden" name="is_maintenance_on" value="0" />
<input type="checkbox" id="maintenance-mode-status" name="is_maintenance_on" value="1" {{ $channel->is_maintenance_on ? 'checked' : '' }}>
<span class="slider round"></span>
</label>
</div>
<div class="control-group">
<label for="maintenance-mode-text">
{{ __('admin::app.settings.channels.maintenance-mode-text') }}
<span class="locale">[{{ $locale }}]</span>
</label>
<input class="control" id="maintenance-mode-text" name="{{$locale}}[maintenance_mode_text]" value="{{ old('maintenance_mode_text') ?? ($channel->translate($locale)['maintenance_mode_text'] ?? '') }}"/>
</div>
<div class="control-group">
<label for="allowed-ips">{{ __('admin::app.settings.channels.allowed-ips') }}</label>
<input class="control" id="allowed-ips" name="allowed_ips" value="{{ old('allowed_ips') ?: $channel->allowed_ips }}"/>
</div>
</div>
</accordian>

View File

@ -487,7 +487,7 @@ class AttributeTableSeeder extends Seeder
'value_per_channel' => '0',
'is_filterable' => '1',
'is_configurable' => '0',
'is_user_defined' => '0',
'is_user_defined' => '1',
'is_visible_on_front' => '1',
'use_in_flat' => '1',
'created_at' => $now,

View File

@ -0,0 +1,19 @@
<?php
namespace Webkul\Attribute\Repositories;
use Webkul\Core\Eloquent\Repository;
class AttributeOptionTranslationRepository extends Repository
{
/**
* Specify Model class name
*
* @return mixed
*/
function model()
{
return 'Webkul\Attribute\Contracts\AttributeOptionTranslation';
}
}

View File

@ -179,7 +179,7 @@ class CartRule
/** @var \Webkul\CartRule\Models\CartRule $rule */
// Laravel relation is used instead of repository for performance
// reasons (cart_rule_coupon-relation is pre-loaded by self::getCartRuleQuery())
$coupon = $rule->cart_rule_coupon->where('code', $cart->coupon_code)->first();
$coupon = $rule->cart_rule_coupon()->where('code', $cart->coupon_code)->first();
if ($coupon && $coupon->code === $cart->coupon_code) {
if ($coupon->usage_limit && $coupon->times_used >= $coupon->usage_limit) {
@ -275,25 +275,19 @@ class CartRule
break;
case 'cart_fixed':
// if ($this->itemTotals[$rule->id]['total_items'] <= 1) {
// $discountAmount = core()->convertPrice($rule->discount_amount);
if ($this->itemTotals[$rule->id]['total_items'] <= 1) {
$discountAmount = core()->convertPrice($rule->discount_amount);
// $baseDiscountAmount = min($item->base_price * $quantity, $rule->discount_amount);
// } else {
// $discountRate = $item->base_price * $quantity / $this->itemTotals[$rule->id]['base_total_price'];
$baseDiscountAmount = min($item->base_price * $quantity, $rule->discount_amount);
} else {
$discountRate = $item->base_price * $quantity / $this->itemTotals[$rule->id]['base_total_price'];
// $maxDiscount = $rule->discount_amount * $discountRate;
$maxDiscount = $rule->discount_amount * $discountRate;
// $discountAmount = core()->convertPrice($maxDiscount);
$discountAmount = core()->convertPrice($maxDiscount);
// $baseDiscountAmount = min($item->base_price * $quantity, $maxDiscount);
// }
$discountAmount = core()->convertPrice($rule->discount_amount);
$baseDiscountAmount = min($item->base_price * $quantity, $rule->discount_amount);
$discountAmount = min($item->price * $quantity, $discountAmount);
$baseDiscountAmount = min($item->base_price * $quantity, $maxDiscount);
}
break;
@ -537,7 +531,7 @@ class CartRule
}
$coupons = $this->cartRuleCouponRepository->where(['code' => $cart->coupon_code])->get();
foreach ($coupons as $coupon) {
if (in_array($coupon->cart_rule_id, explode(',', $cart->applied_cart_rule_ids))) {
return true;

View File

@ -558,14 +558,6 @@ class Cart
$cart->grand_total = $cart->sub_total + $cart->tax_total - $cart->discount_amount;
$cart->base_grand_total = $cart->base_sub_total + $cart->base_tax_total - $cart->base_discount_amount;
if ($shipping = $cart->selected_shipping_rate) {
$cart->grand_total = (float)$cart->grand_total + $shipping->price - $shipping->discount_amount;
$cart->base_grand_total = (float)$cart->base_grand_total + $shipping->base_price - $shipping->base_discount_amount;
$cart->discount_amount += $shipping->discount_amount;
$cart->base_discount_amount += $shipping->base_discount_amount;
}
$cart = $this->finalizeCartTotals($cart);
$quantities = 0;
@ -577,7 +569,7 @@ class Cart
$cart->items_count = $cart->items->count();
$cart->items_qty = $quantities;
$cart->cart_currency_code = core()->getCurrentCurrencyCode();
$cart->save();
@ -700,8 +692,20 @@ class Cart
if ($haveTaxRate) {
$item->tax_percent = $rate->tax_rate;
$item->tax_amount = round(($item->total * $rate->tax_rate) / 100, 4);
$item->base_tax_amount = round(($item->base_total * $rate->tax_rate) / 100, 4);
/* getting shipping rate for tax calculation */
$shippingPrice = $shippingBasePrice = 0;
if ($shipping = $cart->selected_shipping_rate) {
if ($shipping->is_calculate_tax) {
$shippingPrice = $shipping->price - $shipping->discount_amount;
$shippingBasePrice = $shipping->base_price - $shipping->base_discount_amount;
}
}
/* now assigning shipping prices for tax calculation */
$item->tax_amount = round((($item->total + $shippingPrice) * $rate->tax_rate) / 100, 4);
$item->base_tax_amount = round((($item->base_total + $shippingBasePrice) * $rate->tax_rate) / 100, 4);
break;
}

View File

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

View File

@ -3,18 +3,20 @@
namespace Webkul\Checkout\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class CustomerAddressForm extends FormRequest
{
protected $rules;
/**
* Rules.
*/
protected $rules = [];
/**
* Determine if the product is authorized to make this request.
*
* @return bool
*/
public function authorize()
public function authorize(): bool
{
return true;
}
@ -24,14 +26,22 @@ class CustomerAddressForm extends FormRequest
*
* @return array
*/
public function rules()
public function rules(): array
{
$customerAddressIds = $this->getCustomerAddressIds();
if (isset($this->get('billing')['address_id'])) {
$this->rules = [
$billingAddressRules = [
'billing.address_id' => ['required'],
];
if (! empty($customerAddressIds)) {
$billingAddressRules['billing.address_id'][] = "in:{$customerAddressIds}";
}
$this->mergeWithRules($billingAddressRules);
} else {
$this->rules = [
$this->mergeWithRules([
'billing.first_name' => ['required'],
'billing.last_name' => ['required'],
'billing.email' => ['required'],
@ -41,16 +51,22 @@ class CustomerAddressForm extends FormRequest
'billing.postcode' => ['required'],
'billing.phone' => ['required'],
'billing.country' => ['required'],
];
]);
}
if (isset($this->get('billing')['use_for_shipping']) && !$this->get('billing')['use_for_shipping']) {
if (isset($this->get('billing')['use_for_shipping']) && ! $this->get('billing')['use_for_shipping']) {
if (isset($this->get('shipping')['address_id'])) {
$this->rules = array_merge($this->rules, [
$shippingAddressRules = [
'shipping.address_id' => ['required'],
]);
];
if (! empty($customerAddressIds)) {
$shippingAddressRules['shipping.address_id'][] = "in:{$customerAddressIds}";
}
$this->mergeWithRules($shippingAddressRules);
} else {
$this->rules = array_merge($this->rules, [
$this->mergeWithRules([
'shipping.first_name' => ['required'],
'shipping.last_name' => ['required'],
'shipping.email' => ['required'],
@ -66,4 +82,28 @@ class CustomerAddressForm extends FormRequest
return $this->rules;
}
/**
* Merge additional rules.
*
* @return string
*/
private function mergeWithRules($additionalRules): void
{
$this->rules = array_merge($this->rules, $additionalRules);
}
/**
* If customer is placing order then fetching all address ids to check with the request ids.
*
* @return string
*/
private function getCustomerAddressIds(): string
{
if ($customer = auth('customer')->user()) {
return $customer->addresses->pluck('id')->join(',');
}
return '';
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace Webkul\Core\Console\Commands;
use Illuminate\Foundation\Console\DownCommand as OriginalCommand;
use Webkul\Core\Models\Channel;
class DownCommand extends OriginalCommand
{
public function handle()
{
$this->downAllChannel();
parent::handle();
}
protected function downAllChannel()
{
$this->comment('All channels are down.');
return Channel::query()->update(['is_maintenance_on' => 1]);
}
}

View File

@ -3,8 +3,8 @@
namespace Webkul\Core\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Artisan;
class Install extends Command
{
@ -33,20 +33,15 @@ class Install extends Command
}
/**
* Install and configure bagisto
* Install and configure bagisto.
*/
public function handle()
{
// check for .env
$this->checkForEnvFile();
// cached new changes
$this->warn('Step: Caching new changes...');
$cached = $this->call('config:cache');
$this->info($cached);
// waiting for 2 seconds
$this->warn('Please wait...');
sleep(2);
// loading values at runtime
$this->loadEnvConfigAtRuntime();
// running `php artisan migrate`
$this->warn('Step: Migrating all tables into database...');
@ -54,25 +49,31 @@ class Install extends Command
$this->info($migrate);
// running `php artisan db:seed`
$this->warn('Step: seeding basic data for bagisto kickstart...');
$this->warn('Step: Seeding basic data for Bagisto kickstart...');
$result = $this->call('db:seed');
$this->info($result);
// running `php artisan vendor:publish --all`
$this->warn('Step: Publishing Assets and Configurations...');
$this->warn('Step: Publishing assets and configurations...');
$result = $this->call('vendor:publish', ['--all']);
$this->info($result);
// running `php artisan storage:link`
$this->warn('Step: Linking Storage directory...');
$this->warn('Step: Linking storage directory...');
$result = $this->call('storage:link');
$this->info($result);
// optimizing stuffs
$this->warn('Step: Optimizing...');
$result = $this->call('optimize');
$this->info($result);
// running `composer dump-autoload`
$this->warn('Step: Composer Autoload...');
$this->warn('Step: Composer autoload...');
$result = shell_exec('composer dump-autoload');
$this->info($result);
// final information
$this->info('-----------------------------');
$this->info('Congratulations!');
$this->info('The installation has been finished and you can now use Bagisto.');
@ -85,28 +86,30 @@ class Install extends Command
/**
* Checking .env file and if not found then create .env file.
* Then ask for database name, password & username to set
* On .env file so that we can easily migrate to our db
* On .env file so that we can easily migrate to our db.
*/
public function checkForEnvFile()
protected function checkForEnvFile()
{
$envExists = File::exists(base_path() . '/.env');
if (! $envExists) {
$this->info('Creating the environment configuration file.');
$this->createEnvFile();
} else {
$this->call('key:generate');
$this->info('Great! your environment configuration file already exists.');
}
$this->call('key:generate');
}
/**
* Create a new .env file.
*/
public function createEnvFile()
protected function createEnvFile()
{
try {
File::copy('.env.example', '.env');
Artisan::call('key:generate');
$default_app_url = 'http://localhost:8000';
$input_app_url = $this->ask('Please Enter the APP URL : ');
$this->envUpdate('APP_URL=', $input_app_url ? $input_app_url : $default_app_url );
@ -125,7 +128,6 @@ class Install extends Command
$currency = $this->choice('Please enter the default currency', ['USD', 'EUR'], 'USD');
$this->envUpdate('APP_CURRENCY=', $currency);
$this->addDatabaseDetails();
} catch (\Exception $e) {
$this->error('Error in creating .env file, please create it manually and then run `php artisan migrate` again.');
@ -135,21 +137,65 @@ class Install extends Command
/**
* Add the database credentials to the .env file.
*/
public function addDatabaseDetails()
protected function addDatabaseDetails()
{
$dbName = $this->ask('What is the database name to be used by bagisto?');
$dbUser = $this->anticipate('What is your database username?', ['root']);
$dbPass = $this->secret('What is your database password?');
$this->envUpdate('DB_DATABASE=', $dbName);
$dbUser = $this->anticipate('What is your database username?', ['root']);
$this->envUpdate('DB_USERNAME=', $dbUser);
$dbPass = $this->secret('What is your database password?');
$this->envUpdate('DB_PASSWORD=', $dbPass);
}
/**
* Load `.env` config at runtime.
*/
protected function loadEnvConfigAtRuntime()
{
$this->warn('Loading configs...');
/* environment directly checked from `.env` so changing in config won't reflect */
app()['env'] = $this->getEnvAtRuntime('APP_ENV');
/* setting for the first time and then `.env` values will be incharged */
config(['database.connections.mysql.database' => $this->getEnvAtRuntime('DB_DATABASE')]);
config(['database.connections.mysql.username' => $this->getEnvAtRuntime('DB_USERNAME')]);
config(['database.connections.mysql.password' => $this->getEnvAtRuntime('DB_PASSWORD')]);
DB::purge('mysql');
$this->info('Configuration loaded..');
}
/**
* Check key in `.env` file because it will help to find values at runtime.
*/
protected static function getEnvAtRuntime($key)
{
$path = base_path() . '/.env';
$data = file($path);
if ($data) {
foreach ($data as $line) {
$line = preg_replace('/\s+/', '', $line);
$rowValues = explode('=', $line);
if (strlen($line) !== 0) {
if (strpos($key, $rowValues[0]) !== false) {
return $rowValues[1];
}
}
}
}
return false;
}
/**
* Update the .env values.
*/
public static function envUpdate($key, $value)
protected static function envUpdate($key, $value)
{
$path = base_path() . '/.env';
$data = file($path);

View File

@ -0,0 +1,22 @@
<?php
namespace Webkul\Core\Console\Commands;
use Illuminate\Foundation\Console\UpCommand as OriginalCommand;
use Webkul\Core\Models\Channel;
class UpCommand extends OriginalCommand
{
public function handle()
{
$this->upAllChannel();
parent::handle();
}
protected function upAllChannel()
{
$this->comment('Activating all channels.');
return Channel::query()->update(['is_maintenance_on' => 0]);
}
}

View File

@ -0,0 +1,7 @@
<?php
namespace Webkul\Core\Contracts;
interface ChannelTranslation
{
}

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddColumnsInChannelsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('channels', function (Blueprint $table) {
$table->boolean('is_maintenance_on')->after('footer_content')->default(0);
$table->text('maintenance_mode_text')->after('is_maintenance_on')->nullable();
$table->text('allowed_ips')->after('maintenance_mode_text')->nullable();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('channels', function (Blueprint $table) {
$table->dropColumn('is_maintenance_on');
$table->dropColumn('maintenance_mode_text');
$table->dropColumn('allowed_ips');
});
}
}

View File

@ -0,0 +1,42 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateChannelTranslationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('channel_translations', function (Blueprint $table) {
$table->id();
$table->integer('channel_id')->unsigned();
$table->string('locale')->index();
$table->string('name');
$table->text('description')->nullable();
$table->text('home_page_content')->nullable();
$table->text('footer_content')->nullable();
$table->text('maintenance_mode_text')->nullable();
$table->json('home_seo')->nullable();
$table->timestamps();
$table->unique(['channel_id', 'locale']);
$table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('channel_translations');
}
}

View File

@ -0,0 +1,37 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RemoveColumnsFromChannelsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('channels', function (Blueprint $table) {
$table->dropColumn('name');
$table->dropColumn('description');
$table->dropColumn('home_page_content');
$table->dropColumn('footer_content');
$table->dropColumn('maintenance_mode_text');
$table->dropColumn('home_seo');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('channels', function (Blueprint $table) {
//
});
}
}

View File

@ -2,8 +2,8 @@
namespace Webkul\Core\Database\Seeders;
use Illuminate\Support\Facades\DB;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
class ChannelTableSeeder extends Seeder
{
@ -14,20 +14,175 @@ class ChannelTableSeeder extends Seeder
DB::table('channels')->insert([
'id' => 1,
'code' => 'default',
'name' => 'Default',
'theme' => 'velocity',
'hostname' => config('app.url'),
'root_category_id' => 1,
'home_page_content' => '<p>@include("shop::home.slider") @include("shop::home.featured-products") @include("shop::home.new-products")</p>
<div class="banner-container">
<div class="left-banner"><img src='.asset("/themes/default/assets/images/1.webp").' data-src='.asset("/themes/default/assets/images/1.webp").' class="lazyload" alt="test" width="720" height="720" /></div>
<div class="right-banner"><img src='. asset("/themes/default/assets/images/2.webp").' data-src='. asset("/themes/default/assets/images/2.webp").' class="lazyload" alt="test" width="460" height="330" /> <img src='.asset("/themes/default/assets/images/3.webp").' data-src='.asset("/themes/default/assets/images/3.webp").' class="lazyload" alt="test" width="460" height="330" /></div>
</div>',
'footer_content' => '<div class="list-container"><span class="list-heading">Quick Links</span><ul class="list-group"><li><a href="@php echo route(\'shop.cms.page\', \'about-us\') @endphp">About Us</a></li><li><a href="@php echo route(\'shop.cms.page\', \'return-policy\') @endphp">Return Policy</a></li><li><a href="@php echo route(\'shop.cms.page\', \'refund-policy\') @endphp">Refund Policy</a></li><li><a href="@php echo route(\'shop.cms.page\', \'terms-conditions\') @endphp">Terms and conditions</a></li><li><a href="@php echo route(\'shop.cms.page\', \'terms-of-use\') @endphp">Terms of Use</a></li><li><a href="@php echo route(\'shop.cms.page\', \'contact-us\') @endphp">Contact Us</a></li></ul></div><div class="list-container"><span class="list-heading">Connect With Us</span><ul class="list-group"><li><a href="#"><span class="icon icon-facebook"></span>Facebook </a></li><li><a href="#"><span class="icon icon-twitter"></span> Twitter </a></li><li><a href="#"><span class="icon icon-instagram"></span> Instagram </a></li><li><a href="#"> <span class="icon icon-google-plus"></span>Google+ </a></li><li><a href="#"> <span class="icon icon-linkedin"></span>LinkedIn </a></li></ul></div>',
'name' => 'Default',
'default_locale_id' => 1,
'base_currency_id' => 1,
'home_seo' => '{"meta_title": "Demo store", "meta_keywords": "Demo store meta keyword", "meta_description": "Demo store meta description"}',
]);
DB::table('channel_translations')->insert([
[
'id' => 1,
'channel_id' => 1,
'locale' => 'en',
'name' => 'Default',
'home_page_content' => '
<p>@include("shop::home.slider") @include("shop::home.featured-products") @include("shop::home.new-products")</p>
<div class="banner-container">
<div class="left-banner">
<img src='.asset("/themes/default/assets/images/1.webp").' data-src='.asset("/themes/default/assets/images/1.webp").' class="lazyload" alt="test" width="720" height="720" />
</div>
<div class="right-banner">
<img src='. asset("/themes/default/assets/images/2.webp").' data-src='. asset("/themes/default/assets/images/2.webp").' class="lazyload" alt="test" width="460" height="330" />
<img src='.asset("/themes/default/assets/images/3.webp").' data-src='.asset("/themes/default/assets/images/3.webp").' class="lazyload" alt="test" width="460" height="330" />
</div>
</div>
',
'footer_content' => '
<div class="list-container">
<span class="list-heading">Quick Links</span>
<ul class="list-group">
<li><a href="@php echo route(\'shop.cms.page\', \'about-us\') @endphp">About Us</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'return-policy\') @endphp">Return Policy</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'refund-policy\') @endphp">Refund Policy</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'terms-conditions\') @endphp">Terms and conditions</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'terms-of-use\') @endphp">Terms of Use</a></li><li><a href="@php echo route(\'shop.cms.page\', \'contact-us\') @endphp">Contact Us</a></li>
</ul>
</div>
<div class="list-container">
<span class="list-heading">Connect With Us</span>
<ul class="list-group">
<li><a href="#"><span class="icon icon-facebook"></span>Facebook </a></li>
<li><a href="#"><span class="icon icon-twitter"></span> Twitter </a></li>
<li><a href="#"><span class="icon icon-instagram"></span> Instagram </a></li>
<li><a href="#"> <span class="icon icon-google-plus"></span>Google+ </a></li>
<li><a href="#"> <span class="icon icon-linkedin"></span>LinkedIn </a></li>
</ul>
</div>
',
'home_seo' => '{"meta_title": "Demo store", "meta_keywords": "Demo store meta keyword", "meta_description": "Demo store meta description"}',
], [
'id' => 2,
'channel_id' => 1,
'locale' => 'fr',
'name' => 'Default',
'home_page_content' => '
<p>@include("shop::home.slider") @include("shop::home.featured-products") @include("shop::home.new-products")</p>
<div class="banner-container">
<div class="left-banner">
<img src='.asset("/themes/default/assets/images/1.webp").' data-src='.asset("/themes/default/assets/images/1.webp").' class="lazyload" alt="test" width="720" height="720" />
</div>
<div class="right-banner">
<img src='. asset("/themes/default/assets/images/2.webp").' data-src='. asset("/themes/default/assets/images/2.webp").' class="lazyload" alt="test" width="460" height="330" />
<img src='.asset("/themes/default/assets/images/3.webp").' data-src='.asset("/themes/default/assets/images/3.webp").' class="lazyload" alt="test" width="460" height="330" />
</div>
</div>
',
'footer_content' => '
<div class="list-container">
<span class="list-heading">Quick Links</span>
<ul class="list-group">
<li><a href="@php echo route(\'shop.cms.page\', \'about-us\') @endphp">About Us</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'return-policy\') @endphp">Return Policy</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'refund-policy\') @endphp">Refund Policy</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'terms-conditions\') @endphp">Terms and conditions</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'terms-of-use\') @endphp">Terms of Use</a></li><li><a href="@php echo route(\'shop.cms.page\', \'contact-us\') @endphp">Contact Us</a></li>
</ul>
</div>
<div class="list-container">
<span class="list-heading">Connect With Us</span>
<ul class="list-group">
<li><a href="#"><span class="icon icon-facebook"></span>Facebook </a></li>
<li><a href="#"><span class="icon icon-twitter"></span> Twitter </a></li>
<li><a href="#"><span class="icon icon-instagram"></span> Instagram </a></li>
<li><a href="#"> <span class="icon icon-google-plus"></span>Google+ </a></li>
<li><a href="#"> <span class="icon icon-linkedin"></span>LinkedIn </a></li>
</ul>
</div>
',
'home_seo' => '{"meta_title": "Demo store", "meta_keywords": "Demo store meta keyword", "meta_description": "Demo store meta description"}',
], [
'id' => 3,
'channel_id' => 1,
'locale' => 'nl',
'name' => 'Default',
'home_page_content' => '
<p>@include("shop::home.slider") @include("shop::home.featured-products") @include("shop::home.new-products")</p>
<div class="banner-container">
<div class="left-banner">
<img src='.asset("/themes/default/assets/images/1.webp").' data-src='.asset("/themes/default/assets/images/1.webp").' class="lazyload" alt="test" width="720" height="720" />
</div>
<div class="right-banner">
<img src='. asset("/themes/default/assets/images/2.webp").' data-src='. asset("/themes/default/assets/images/2.webp").' class="lazyload" alt="test" width="460" height="330" />
<img src='.asset("/themes/default/assets/images/3.webp").' data-src='.asset("/themes/default/assets/images/3.webp").' class="lazyload" alt="test" width="460" height="330" />
</div>
</div>
',
'footer_content' => '
<div class="list-container">
<span class="list-heading">Quick Links</span>
<ul class="list-group">
<li><a href="@php echo route(\'shop.cms.page\', \'about-us\') @endphp">About Us</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'return-policy\') @endphp">Return Policy</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'refund-policy\') @endphp">Refund Policy</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'terms-conditions\') @endphp">Terms and conditions</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'terms-of-use\') @endphp">Terms of Use</a></li><li><a href="@php echo route(\'shop.cms.page\', \'contact-us\') @endphp">Contact Us</a></li>
</ul>
</div>
<div class="list-container">
<span class="list-heading">Connect With Us</span>
<ul class="list-group">
<li><a href="#"><span class="icon icon-facebook"></span>Facebook </a></li>
<li><a href="#"><span class="icon icon-twitter"></span> Twitter </a></li>
<li><a href="#"><span class="icon icon-instagram"></span> Instagram </a></li>
<li><a href="#"> <span class="icon icon-google-plus"></span>Google+ </a></li>
<li><a href="#"> <span class="icon icon-linkedin"></span>LinkedIn </a></li>
</ul>
</div>
',
'home_seo' => '{"meta_title": "Demo store", "meta_keywords": "Demo store meta keyword", "meta_description": "Demo store meta description"}',
], [
'id' => 4,
'channel_id' => 1,
'locale' => 'tr',
'name' => 'Default',
'home_page_content' => '
<p>@include("shop::home.slider") @include("shop::home.featured-products") @include("shop::home.new-products")</p>
<div class="banner-container">
<div class="left-banner">
<img src='.asset("/themes/default/assets/images/1.webp").' data-src='.asset("/themes/default/assets/images/1.webp").' class="lazyload" alt="test" width="720" height="720" />
</div>
<div class="right-banner">
<img src='. asset("/themes/default/assets/images/2.webp").' data-src='. asset("/themes/default/assets/images/2.webp").' class="lazyload" alt="test" width="460" height="330" />
<img src='.asset("/themes/default/assets/images/3.webp").' data-src='.asset("/themes/default/assets/images/3.webp").' class="lazyload" alt="test" width="460" height="330" />
</div>
</div>
',
'footer_content' => '
<div class="list-container">
<span class="list-heading">Quick Links</span>
<ul class="list-group">
<li><a href="@php echo route(\'shop.cms.page\', \'about-us\') @endphp">About Us</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'return-policy\') @endphp">Return Policy</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'refund-policy\') @endphp">Refund Policy</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'terms-conditions\') @endphp">Terms and conditions</a></li>
<li><a href="@php echo route(\'shop.cms.page\', \'terms-of-use\') @endphp">Terms of Use</a></li><li><a href="@php echo route(\'shop.cms.page\', \'contact-us\') @endphp">Contact Us</a></li>
</ul>
</div>
<div class="list-container">
<span class="list-heading">Connect With Us</span>
<ul class="list-group">
<li><a href="#"><span class="icon icon-facebook"></span>Facebook </a></li>
<li><a href="#"><span class="icon icon-twitter"></span> Twitter </a></li>
<li><a href="#"><span class="icon icon-instagram"></span> Instagram </a></li>
<li><a href="#"> <span class="icon icon-google-plus"></span>Google+ </a></li>
<li><a href="#"> <span class="icon icon-linkedin"></span>LinkedIn </a></li>
</ul>
</div>
',
'home_seo' => '{"meta_title": "Demo store", "meta_keywords": "Demo store meta keyword", "meta_description": "Demo store meta description"}',
]
]);
DB::table('channel_currencies')->insert([

View File

@ -8,7 +8,7 @@ use Webkul\Core\Repositories\ChannelRepository;
class ChannelController extends Controller
{
/**
* Contains route related configuration
* Contains route related configuration.
*
* @var array
*/
@ -61,35 +61,40 @@ class ChannelController extends Controller
*/
public function store()
{
$this->validate(request(), [
'code' => ['required', 'unique:channels,code', new \Webkul\Core\Contracts\Validations\Code],
'name' => 'required',
'locales' => 'required|array|min:1',
'default_locale_id' => 'required|in_array:locales.*',
'currencies' => 'required|array|min:1',
'base_currency_id' => 'required|in_array:currencies.*',
'root_category_id' => 'required',
'logo.*' => 'mimes:bmp,jpeg,jpg,png,webp',
'favicon.*' => 'mimes:bmp,jpeg,jpg,png,webp',
'seo_title' => 'required|string',
'seo_description' => 'required|string',
'seo_keywords' => 'required|string',
'hostname' => 'unique:channels,hostname',
$data = $this->validate(request(), [
/* general */
'code' => ['required', 'unique:channels,code', new \Webkul\Core\Contracts\Validations\Code],
'name' => 'required',
'description' => 'nullable',
'inventory_sources' => 'required|array|min:1',
'root_category_id' => 'required',
'hostname' => 'unique:channels,hostname',
/* currencies and locales */
'locales' => 'required|array|min:1',
'default_locale_id' => 'required|in_array:locales.*',
'currencies' => 'required|array|min:1',
'base_currency_id' => 'required|in_array:currencies.*',
/* design */
'theme' => 'nullable',
'home_page_content' => 'nullable',
'footer_content' => 'nullable',
'logo.*' => 'nullable|mimes:bmp,jpeg,jpg,png,webp',
'favicon.*' => 'nullable|mimes:bmp,jpeg,jpg,png,webp',
/* seo */
'seo_title' => 'required|string',
'seo_description' => 'required|string',
'seo_keywords' => 'required|string',
/* maintenance mode */
'is_maintenance_on' => 'boolean',
'maintenance_mode_text' => 'nullable',
'allowed_ips' => 'nullable'
]);
$data = request()->all();
$data['seo']['meta_title'] = $data['seo_title'];
$data['seo']['meta_description'] = $data['seo_description'];
$data['seo']['meta_keywords'] = $data['seo_keywords'];
unset($data['seo_title']);
unset($data['seo_description']);
unset($data['seo_keywords']);
$data['home_seo'] = json_encode($data['seo']);
unset($data['seo']);
$data = $this->setSEOContent($data);
Event::dispatch('core.channel.create.before');
@ -123,31 +128,42 @@ class ChannelController extends Controller
*/
public function update($id)
{
$this->validate(request(), [
'code' => ['required', 'unique:channels,code,' . $id, new \Webkul\Core\Contracts\Validations\Code],
'name' => 'required',
'locales' => 'required|array|min:1',
'inventory_sources' => 'required|array|min:1',
'default_locale_id' => 'required|in_array:locales.*',
'currencies' => 'required|array|min:1',
'base_currency_id' => 'required|in_array:currencies.*',
'root_category_id' => 'required',
'logo.*' => 'mimes:bmp,jpeg,jpg,png,webp',
'favicon.*' => 'mimes:bmp,jpeg,jpg,png,webp',
'hostname' => 'unique:channels,hostname,' . $id,
$locale = request()->get('locale') ?: app()->getLocale();
$data = $this->validate(request(), [
/* general */
'code' => ['required', 'unique:channels,code,' . $id, new \Webkul\Core\Contracts\Validations\Code],
$locale . '.name' => 'required',
$locale . '.description' => 'nullable',
'inventory_sources' => 'required|array|min:1',
'root_category_id' => 'required',
'hostname' => 'unique:channels,hostname,' . $id,
/* currencies and locales */
'locales' => 'required|array|min:1',
'default_locale_id' => 'required|in_array:locales.*',
'currencies' => 'required|array|min:1',
'base_currency_id' => 'required|in_array:currencies.*',
/* design */
'theme' => 'nullable',
$locale . '.home_page_content' => 'nullable',
$locale . '.footer_content' => 'nullable',
'logo.*' => 'nullable|mimes:bmp,jpeg,jpg,png,webp',
'favicon.*' => 'nullable|mimes:bmp,jpeg,jpg,png,webp',
/* seo */
$locale . '.seo_title' => 'nullable',
$locale . '.seo_description' => 'nullable',
$locale . '.seo_keywords' => 'nullable',
/* maintenance mode */
'is_maintenance_on' => 'boolean',
$locale . '.maintenance_mode_text' => 'nullable',
'allowed_ips' => 'nullable'
]);
$data = request()->all();
$data['seo']['meta_title'] = $data['seo_title'];
$data['seo']['meta_description'] = $data['seo_description'];
$data['seo']['meta_keywords'] = $data['seo_keywords'];
unset($data['seo_title']);
unset($data['seo_description']);
unset($data['seo_keywords']);
$data['home_seo'] = json_encode($data['seo']);
$data = $this->setSEOContent($data, $locale);
Event::dispatch('core.channel.update.before', $id);
@ -188,11 +204,55 @@ class ChannelController extends Controller
return response()->json(['message' => true], 200);
} catch(\Exception $e) {
// session()->flash('warning', trans($e->getMessage()));
session()->flash('error', trans('admin::app.response.delete-failed', ['name' => 'Channel']));
}
}
return response()->json(['message' => false], 400);
}
/**
* Set the seo content and return back the updated array.
*
* @param array $data
* @param string $locale
* @return array
*/
private function setSEOContent(array $data, $locale = null)
{
$editedData = $data;
if ($locale) {
$editedData = $data[$locale];
}
$editedData['home_seo']['meta_title'] = $editedData['seo_title'];
$editedData['home_seo']['meta_description'] = $editedData['seo_description'];
$editedData['home_seo']['meta_keywords'] = $editedData['seo_keywords'];
$editedData['home_seo'] = json_encode($editedData['home_seo']);
$editedData = $this->unsetKeys($editedData, ['seo_title', 'seo_description', 'seo_keywords']);
if ($locale) {
$data[$locale] = $editedData;
$editedData = $data;
}
return $editedData;
}
/**
* Unset keys.
*
* @param array $keys
* @return array
*/
private function unsetKeys($data, $keys)
{
foreach ($keys as $key) {
unset($data[$key]);
}
return $data;
}
}

View File

@ -0,0 +1,119 @@
<?php
namespace Webkul\Core\Http\Middleware;
use Closure;
use Illuminate\Routing\Route;
use Illuminate\Contracts\Foundation\Application;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Original;
class CheckForMaintenanceMode extends Original
{
/**
* The application implementation.
*
* @var \Illuminate\Contracts\Foundation\Application
*/
protected $app;
/**
* Current channel.
*
* @var \Webkul\Core\Models\Channel
*/
protected $channel;
/**
* Exclude route names.
*/
protected $excludedNames = [];
/**
* Exclude route uris.
*/
protected $except = [];
/**
* Exclude ips.
*/
protected $excludedIPs = [];
/**
* Constructor.
*
* @param \Illuminate\Contracts\Foundation\Application $app
*/
public function __construct(Application $app)
{
/* application */
$this->app = $app;
/* current channel */
$this->channel = core()->getCurrentChannel();
/* adding exception for admin routes */
$this->except[] = env('APP_ADMIN_URL', 'admin') . '*';
/* adding exception for ips */
$this->excludedIPs = array_map('trim', explode(',', $this->channel->allowed_ips));
}
/**
* Check for the except routes.
*
* @param \Illuminate\Http\Request $request
* @return boolean
*/
protected function shouldPassThrough($request)
{
foreach ($this->except as $except) {
if ($except !== '/') {
$except = trim($except, '/');
}
if ($request->is($except)) {
return true;
}
}
return false;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
*/
public function handle($request, Closure $next)
{
if ($this->app->isDownForMaintenance()) {
$response = $next($request);
if (in_array($request->ip(), $this->excludedIPs)) {
return $response;
}
$route = $request->route();
if ($route instanceof Route) {
if (in_array($route->getName(), $this->excludedNames)) {
return $response;
}
}
if ($this->shouldPassThrough($request))
{
return $response;
}
throw new HttpException(503);
}
return $next($request);
}
}

View File

@ -2,13 +2,13 @@
namespace Webkul\Core\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
use Webkul\Category\Models\CategoryProxy;
use Webkul\Core\Eloquent\TranslatableModel;
use Webkul\Inventory\Models\InventorySourceProxy;
use Webkul\Core\Contracts\Channel as ChannelContract;
class Channel extends Model implements ChannelContract
class Channel extends TranslatableModel implements ChannelContract
{
protected $fillable = [
'code',
@ -22,6 +22,18 @@ class Channel extends Model implements ChannelContract
'base_currency_id',
'root_category_id',
'home_seo',
'is_maintenance_on',
'maintenance_mode_text',
'allowed_ips'
];
public $translatedAttributes = [
'name',
'description',
'home_page_content',
'footer_content',
'maintenance_mode_text',
'home_seo',
];
/**

View File

@ -0,0 +1,11 @@
<?php
namespace Webkul\Core\Models;
use Illuminate\Database\Eloquent\Model;
use Webkul\Core\Contracts\ChannelTranslation as ChannelTranslationContract;
class ChannelTranslation extends Model implements ChannelTranslationContract
{
protected $guarded = [];
}

View File

@ -0,0 +1,10 @@
<?php
namespace Webkul\Core\Models;
use Konekt\Concord\Proxies\ModelProxy;
class ChannelTranslationProxy extends ModelProxy
{
}

View File

@ -2,23 +2,25 @@
namespace Webkul\Core\Providers;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Illuminate\Database\Eloquent\Factory as EloquentFactory;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\AliasLoader;
use Illuminate\Support\Facades\Event;
use Webkul\Theme\ViewRenderEventManager;
use Webkul\Core\View\Compilers\BladeCompiler;
use Webkul\Core\Console\Commands\BookingCron;
use Webkul\Core\Core;
use Webkul\Core\Exceptions\Handler;
use Webkul\Core\Facades\Core as CoreFacade;
use Webkul\Core\Models\SliderProxy;
use Webkul\Core\Observers\SliderObserver;
use Webkul\Core\Console\Commands\BagistoVersion;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\AliasLoader;
use Illuminate\Support\ServiceProvider;
use Webkul\Theme\ViewRenderEventManager;
use Illuminate\Support\Facades\Validator;
use Webkul\Core\Console\Commands\Install;
use Webkul\Core\Observers\SliderObserver;
use Webkul\Core\Console\Commands\UpCommand;
use Webkul\Core\Facades\Core as CoreFacade;
use Webkul\Core\Console\Commands\BookingCron;
use Webkul\Core\Console\Commands\DownCommand;
use Webkul\Core\View\Compilers\BladeCompiler;
use Illuminate\Contracts\Debug\ExceptionHandler;
use Webkul\Core\Console\Commands\BagistoVersion;
use Webkul\Core\Console\Commands\ExchangeRateUpdate;
use Illuminate\Database\Eloquent\Factory as EloquentFactory;
class CoreServiceProvider extends ServiceProvider
{
@ -65,6 +67,14 @@ class CoreServiceProvider extends ServiceProvider
Event::listen('bagisto.admin.layout.head', static function(ViewRenderEventManager $viewRenderEventManager) {
$viewRenderEventManager->addTemplate('core::blade.tracer.style');
});
$this->app->extend('command.down', function () {
return new DownCommand;
});
$this->app->extend('command.up', function () {
return new UpCommand;
});
}
/**

View File

@ -26,7 +26,17 @@ class ChannelRepository extends Repository
*/
public function create(array $data)
{
$channel = $this->model->create($data);
$model = $this->getModel();
foreach (core()->getAllLocales() as $locale) {
foreach ($model->translatedAttributes as $attribute) {
if (isset($data[$attribute])) {
$data[$locale->code][$attribute] = $data[$attribute];
}
}
}
$channel = parent::create($data);
$channel->locales()->sync($data['locales']);
@ -51,7 +61,7 @@ class ChannelRepository extends Repository
{
$channel = $this->find($id);
$channel->update($data);
$channel = parent::update($data, $id, $attribute);
$channel->locales()->sync($data['locales']);

View File

@ -27,7 +27,7 @@ class VatIdRule implements Rule
{
$validator = new VatValidator();
return $validator->validate($value);
return empty($value) || $validator->validate($value);
}
/**

View File

@ -271,8 +271,8 @@ class ModuleCollector extends DataCollector implements DataCollectorInterface, R
public function getAssets()
{
return [
'base_path' => '/home/jitendra/www/html/laravel/bagisto/packages/Webkul/DebugBar/src/Resources/',
'base_url' => '/home/jitendra/www/html/laravel/bagisto/packages/Webkul/DebugBar/src/Resources/',
'base_path' => __DIR__ . '/../Resources/',
'base_url' => __DIR__ . '/../Resources/',
'css' => 'widgets/modules/widget.css',
'js' => 'widgets/modules/widget.js'
];

View File

@ -2,9 +2,9 @@
namespace Webkul\Payment\Providers;
use Konekt\Concord\BaseModuleServiceProvider;
use Webkul\Core\Providers\CoreModuleServiceProvider;
class ModuleServiceProvider extends BaseModuleServiceProvider
class ModuleServiceProvider extends CoreModuleServiceProvider
{
protected $models = [
];

View File

@ -2,9 +2,9 @@
namespace Webkul\Paypal\Providers;
use Konekt\Concord\BaseModuleServiceProvider;
use Webkul\Core\Providers\CoreModuleServiceProvider;
class ModuleServiceProvider extends BaseModuleServiceProvider
class ModuleServiceProvider extends CoreModuleServiceProvider
{
protected $models = [
];

View File

@ -94,7 +94,7 @@ class Toolbar extends AbstractProduct
} elseif (! isset($params['sort'])) {
$sortBy = core()->getConfigData('catalog.products.storefront.sort_by')
? core()->getConfigData('catalog.products.storefront.sort_by')
: 'created_at-asc';
: 'name-desc';
if ($key == $sortBy) {
return true;
@ -182,6 +182,7 @@ class Toolbar extends AbstractProduct
$viewOption = 'list';
}
return $viewOption;
/* if still default config is not set from the admin then in last needed hardcoded value */
return $viewOption ?? 'grid';
}
}

View File

@ -65,10 +65,12 @@ class ProductForm extends FormRequest
{
$product = $this->productRepository->find($this->id);
$maxVideoFileSize = (core()->getConfigData('catalog.products.attribute.file_attribute_upload_size')) ? core()->getConfigData('catalog.products.attribute.file_attribute_upload_size') : '2048' ;
$this->rules = array_merge($product->getTypeInstance()->getTypeValidationRules(), [
'sku' => ['required', 'unique:products,sku,' . $this->id, new \Webkul\Core\Contracts\Validations\Slug],
'images.*' => 'nullable|mimes:bmp,jpeg,jpg,png,webp',
'videos.*' => 'nullable|mimes:mov,mp4|max:2048',
'videos.*' => "nullable|mimes:mov,mp4|max:$maxVideoFileSize",
'special_price_from' => 'nullable|date',
'special_price_to' => 'nullable|date|after_or_equal:special_price_from',
'special_price' => ['nullable', new \Webkul\Core\Contracts\Validations\Decimal, 'lt:price'],

View File

@ -43,90 +43,64 @@ class ProductFlatRepository extends Repository
->where('product_flat.channel', core()->getCurrentChannelCode())
->where('product_flat.locale', app()->getLocale());
$productArrributes = $qb->leftJoin('product_attribute_values as pa', 'product_flat.product_id', 'pa.product_id')
->pluck('pa.attribute_id')
->toArray();
$productArrributes = $qb->distinct()
->leftJoin('product_attribute_values as pa', 'product_flat.product_id', 'pa.product_id')
->leftJoin('attributes as at', 'pa.attribute_id', 'at.id')
->where('is_filterable', 1);
$productSuperArrributes = $qb->leftJoin('product_super_attributes as ps', 'product_flat.product_id', 'ps.product_id')
$productArrributesIds = $productArrributes->pluck('pa.attribute_id')->toArray();
$productSelectArrributes = $productArrributes
->pluck('integer_value')
->toArray();
$productmultiSelectArrributes = $productArrributes
->pluck('text_value')
->toArray();
$multiSelectArrributes = [];
foreach ($productmultiSelectArrributes as $multi) {
if ($multi) {
$multiSelectArrributes = explode(",", $multi);
}
}
$productSuperArrributesIds = $qb->leftJoin('product_super_attributes as ps', 'product_flat.product_id', 'ps.product_id')
->pluck('ps.attribute_id')
->toArray();
$productCategoryArrributes = array_unique(array_merge($productArrributes, $productSuperArrributes));
$productCategoryArrributes['attributeOptions'] = array_filter(array_unique(array_merge($productSelectArrributes, $multiSelectArrributes)));
$productCategoryArrributes['attributes'] = array_filter(array_unique(array_merge($productArrributesIds, $productSuperArrributesIds)));
return $productCategoryArrributes;
}
/**
* get Filterable Attributes.
* filter attributes according to products
*
* @param array $category
* @param array $products
* @return \Illuminate\Support\Collection
*/
public function getFilterableAttributes($category, $products) {
$filterAttributes = [];
public function getProductsRelatedFilterableAttributes($category)
{
$categoryFilterableAttributes = $category->filterableAttributes->pluck('id')->toArray();
if (count($category->filterableAttributes) > 0 ) {
$filterAttributes = $category->filterableAttributes;
} else {
$categoryProductAttributes = $this->getCategoryProductAttribute($category->id);
$productCategoryArrributes = $this->getCategoryProductAttribute($category->id);
if ($categoryProductAttributes) {
foreach (app('Webkul\Attribute\Repositories\AttributeRepository')->getFilterAttributes() as $filterAttribute) {
if (in_array($filterAttribute->id, $categoryProductAttributes)) {
$filterAttributes[] = $filterAttribute;
} else if ($filterAttribute ['code'] == 'price') {
$filterAttributes[] = $filterAttribute;
}
}
$allFilterableAttributes = array_filter(array_unique(array_merge($categoryFilterableAttributes, $productCategoryArrributes['attributes'])));
$filterAttributes = collect($filterAttributes);
$attributes = app('Webkul\Attribute\Repositories\AttributeRepository')->getModel()::with(['options' => function($query) use ($productCategoryArrributes) {
return $query->whereIn('id', $productCategoryArrributes['attributeOptions']);
}
}
return $filterAttributes;
}
/**
* filter attributes according to products
*
* @param array $category
* @return \Illuminate\Support\Collection
*/
public function getProductsRelatedFilterableAttributes($category) {
$products = app('Webkul\Product\Repositories\ProductRepository')->getProductsRelatedToCategory($category->id);
$filterAttributes = $this->getFilterableAttributes($category, $products);
$allProductAttributeOptionsCode = [];
foreach ($products as $key => $product) {
foreach ($filterAttributes as $attribute) {
if ($attribute->code <> 'price') {
if (isset($product[$attribute->code])) {
if (! in_array($product[$attribute->code], $allProductAttributeOptionsCode)) {
array_push($allProductAttributeOptionsCode, $product[$attribute->code]);
}
}
}
}
}
foreach ($filterAttributes as $attribute) {
foreach ($attribute->options as $key => $option) {
if (! in_array($option->id, $allProductAttributeOptionsCode)) {
unset($attribute->options[$key]);
}
}
}
return $filterAttributes;
])->whereIn('id', $allFilterableAttributes)->get();
return $attributes;
}
/**
* update product_flat custom column
*
*
* @param \Webkul\Attribute\Models\Attribute $attribute
* @param \Webkul\Product\Listeners\ProductFlat $listener
*/
@ -139,5 +113,4 @@ class ProductFlatRepository extends Repository
->on('v.attribute_id', '=', \DB::raw($attribute->id));
})->update(['product_flat.'.$attribute->code => \DB::raw($listener->attributeTypeFields[$attribute->type] .'_value')]);
}
}

View File

@ -16,6 +16,7 @@ use Illuminate\Pagination\LengthAwarePaginator;
use Webkul\Product\Models\ProductAttributeValueProxy;
use Webkul\Attribute\Repositories\AttributeRepository;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Storage;
class ProductRepository extends Repository
{
@ -569,8 +570,11 @@ class ProductRepository extends Repository
if ($attribute->code === 'price') {
$query->orderBy('min_price', $direction);
} else {
$query->orderBy($sort === 'created_at' ? 'product_flat.created_at' : $attribute->code, $direction);
$query->orderBy($attribute->code, $direction);
}
} else {
/* `created_at` is not an attribute so it will be in else case */
$query->orderBy('product_flat.created_at', $direction);
}
return $query;
@ -731,13 +735,17 @@ class ProductRepository extends Repository
if (! in_array('images', $attributesToSkip)) {
foreach ($originalProduct->images as $image) {
$copiedProduct->images()->save($image->replicate());
$copiedProductImage = $copiedProduct->images()->save($image->replicate());
$this->copyProductImageVideo($image, $copiedProduct, $copiedProductImage);
}
}
if (! in_array('videos', $attributesToSkip)) {
foreach ($originalProduct->videos as $video) {
$copiedProduct->videos()->save($video->replicate());
$copiedProductVideo = $copiedProduct->videos()->save($video->replicate());
$this->copyProductImageVideo($video, $copiedProduct, $copiedProductVideo);
}
}
@ -768,4 +776,24 @@ class ProductRepository extends Repository
]);
}
}
/**
* @object $data
* @object $copiedProduct
* @object $copiedProductImageVideo
*/
private function copyProductImageVideo($data, $copiedProduct, $copiedProductImageVideo): void
{
$path = explode("/", $data->path);
$path = 'product/' . $copiedProduct->id .'/'. end($path);
$copiedProductImageVideo->path = $path;
$copiedProductImageVideo->save();
Storage::makeDirectory('product/' . $copiedProduct->id);
Storage::copy($data->path, $copiedProductImageVideo->path);
}
}

View File

@ -2,9 +2,9 @@
namespace Webkul\Rule\Providers;
use Konekt\Concord\BaseModuleServiceProvider;
use Webkul\Core\Providers\CoreModuleServiceProvider;
class ModuleServiceProvider extends BaseModuleServiceProvider
class ModuleServiceProvider extends CoreModuleServiceProvider
{
protected $models = [
];

View File

@ -40,6 +40,7 @@ class FlatRate extends AbstractShipping
$object->method = 'flatrate_flatrate';
$object->method_title = $this->getConfigData('title');
$object->method_description = $this->getConfigData('description');
$object->is_calculate_tax = $this->getConfigData('is_calculate_tax');
$object->price = 0;
$object->base_price = 0;

View File

@ -37,6 +37,7 @@ class Free extends AbstractShipping
$object->method = 'free_free';
$object->method_title = $this->getConfigData('title');
$object->method_description = $this->getConfigData('description');
$object->is_calculate_tax = $this->getConfigData('is_calculate_tax');
$object->price = 0;
$object->base_price = 0;

View File

@ -2,21 +2,23 @@
return [
'flatrate' => [
'code' => 'flatrate',
'title' => 'Flat Rate',
'description' => 'Flat Rate Shipping',
'active' => true,
'default_rate' => '10',
'type' => 'per_unit',
'class' => 'Webkul\Shipping\Carriers\FlatRate',
'code' => 'flatrate',
'title' => 'Flat Rate',
'description' => 'Flat Rate Shipping',
'active' => true,
'is_calculate_tax' => true,
'default_rate' => '10',
'type' => 'per_unit',
'class' => 'Webkul\Shipping\Carriers\FlatRate',
],
'free' => [
'code' => 'free',
'title' => 'Free Shipping',
'description' => 'Free Shipping',
'active' => true,
'default_rate' => '0',
'class' => 'Webkul\Shipping\Carriers\Free',
'code' => 'free',
'title' => 'Free Shipping',
'description' => 'Free Shipping',
'active' => true,
'is_calculate_tax' => true,
'default_rate' => '0',
'class' => 'Webkul\Shipping\Carriers\Free',
]
];

View File

@ -35,6 +35,13 @@ return [
'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,
]
]
], [
@ -86,6 +93,13 @@ return [
'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,
]
]
], [

View File

@ -2,9 +2,9 @@
namespace Webkul\Shipping\Providers;
use Konekt\Concord\BaseModuleServiceProvider;
use Webkul\Core\Providers\CoreModuleServiceProvider;
class ModuleServiceProvider extends BaseModuleServiceProvider
class ModuleServiceProvider extends CoreModuleServiceProvider
{
protected $models = [
];

View File

@ -350,4 +350,21 @@ class OnepageController extends Controller
], 422);
}
}
/**
* Check for minimum order.
*
* @return \Illuminate\Http\Response
*/
public function checkMinimumOrder()
{
$minimumOrderAmount = (float) core()->getConfigData('sales.orderSettings.minimum-order.minimum_order_amount') ?? 0;
$status = Cart::checkMinimumOrder();
return response()->json([
'status' => ! $status ? false : true,
'message' => ! $status ? trans('shop::app.checkout.cart.minimum-order-message', ['amount' => core()->currency($minimumOrderAmount)]) : 'Success',
]);
}
}

View File

@ -76,6 +76,9 @@ Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function
//Checkout Save Payment Method Form
Route::post('/checkout/save-payment', 'Webkul\Shop\Http\Controllers\OnepageController@savePayment')->name('shop.checkout.save-payment');
/* check minimum order */
Route::post('/checkout/check-minimum-order', 'Webkul\Shop\Http\Controllers\OnepageController@checkMinimumOrder')->name('shop.checkout.check-minimum-order');
//Checkout Save Order
Route::post('/checkout/save-order', 'Webkul\Shop\Http\Controllers\OnepageController@saveOrder')->name('shop.checkout.save-order');

View File

@ -2,9 +2,9 @@
namespace Webkul\Shop\Providers;
use Konekt\Concord\BaseModuleServiceProvider;
use Webkul\Core\Providers\CoreModuleServiceProvider;
class ModuleServiceProvider extends BaseModuleServiceProvider
class ModuleServiceProvider extends CoreModuleServiceProvider
{
protected $models = [
];

View File

@ -388,14 +388,14 @@ return [
],
'products' => [
'layered-nav-title' => 'Einkaufen bei',
'layered-nav-title' => 'Filtern nach',
'price-label' => 'Angebotspreis von',
'remove-filter-link-title' => 'Alles löschen',
'filter-to' => 'bis',
'sort-by' => 'Sortieren',
'from-a-z' => 'Von A-Z',
'from-z-a' => 'Von Z-A',
'newest-first' => 'Neuste zuerst',
'newest-first' => 'Neueste zuerst',
'oldest-first' => 'Älteste zuerst',
'cheapest-first' => 'Günstigste zuerst',
'expensive-first' => 'Teuerste zuerst',
@ -522,7 +522,7 @@ return [
'shipping-method' => 'Versandart wählen',
'payment-methods' => 'Zahlungsmethode wählen',
'payment-method' => 'Zahlungsmethode',
'summary' => 'Bestellübersichty',
'summary' => 'Bestellübersicht',
'price' => 'Preis',
'quantity' => 'Menge',
'billing-address' => 'Rechnungsadresse',

View File

@ -19,7 +19,7 @@
</div>
<div class="error-messgae" style="font-size: 24px;color: #5E5E5E">
{{ __('admin::app.error.right-back') }}
{{ core()->getCurrentChannel()->maintenance_mode_text ?: __('admin::app.error.right-back') }}
</div>
</div>

View File

@ -250,7 +250,7 @@
data: function() {
return {
uploaded_image_url: '',
image_search_status: "{{core()->getConfigData('general.content.shop.image_search') == '1' ? true : false}}"
image_search_status: "{{core()->getConfigData('general.content.shop.image_search') == '1' ? 'true' : 'false'}}" == 'true'
}
},

View File

@ -1,6 +1,11 @@
{!! view_render_event('bagisto.shop.products.add_to_cart.before', ['product' => $product]) !!}
<button type="submit" class="btn btn-lg btn-primary addtocart" {{ ! $product->isSaleable() ? 'disabled' : '' }}>
@php
$width = (core()->getConfigData('catalog.products.storefront.buy_now_button_display') == 1) ? '49' : '95';
@endphp
<button type="submit" class="btn btn-lg btn-primary addtocart" {{ ! $product->isSaleable() ? 'disabled' : '' }}
style="width: <?php echo $width.'%';?>;">
{{ ($product->type == 'booking') ? __('shop::app.products.book-now') : __('shop::app.products.add-to-cart') }}
</button>

View File

@ -9,8 +9,6 @@
$maxPrice = 0;
if (isset($category)) {
$products = $productRepository->getAll($category->id);
$filterAttributes = $productFlatRepository->getProductsRelatedFilterableAttributes($category);
$maxPrice = core()->convertPrice($productFlatRepository->getCategoryProductMaximumPrice($category));
@ -19,18 +17,6 @@
if (! count($filterAttributes) > 0) {
$filterAttributes = $attributeRepository->getFilterAttributes();
}
foreach ($filterAttributes as $attribute) {
if ($attribute->code <> 'price') {
if (! $attribute->options->isEmpty()) {
$attributes[] = $attribute;
}
} else {
$attributes[] = $attribute;
}
}
$filterAttributes = collect($attributes);
?>
<div class="layered-filter-wrapper">

View File

@ -3,7 +3,9 @@
<div class="add-to-buttons">
@include ('shop::products.add-to-cart', ['product' => $product])
@include ('shop::products.buy-now')
@if (core()->getConfigData('catalog.products.storefront.buy_now_button_display'))
@include ('shop::products.buy-now')
@endif
</div>
{!! view_render_event('bagisto.shop.products.view.product-add.after', ['product' => $product]) !!}

View File

@ -71,7 +71,7 @@ class CustomerSocialAccountRepository extends Repository
if ($account) {
return $account->customer;
} else {
$customer = $this->customerRepository->findOneByField('email', $providerUser->getEmail());
$customer = $providerUser->getEmail() ? $this->customerRepository->findOneByField('email', $providerUser->getEmail()) : null;
if (! $customer) {
$names = $this->getFirstLastName($providerUser->getName());
@ -115,4 +115,4 @@ class CustomerSocialAccountRepository extends Repository
'last_name' => $lastName,
];
}
}
}

View File

@ -2,9 +2,9 @@
namespace Webkul\Theme\Providers;
use Konekt\Concord\BaseModuleServiceProvider;
use Webkul\Core\Providers\CoreModuleServiceProvider;
class ModuleServiceProvider extends BaseModuleServiceProvider
class ModuleServiceProvider extends CoreModuleServiceProvider
{
protected $models = [
];

View File

@ -715,6 +715,7 @@ abstract class DataGrid
'enableMassActions' => $this->enableMassAction,
'enableActions' => $this->enableAction,
'paginated' => $this->paginate,
'itemsPerPage' => $this->itemsPerPage,
'norecords' => __('ui::app.datagrid.no-records'),
'extraFilters' => $necessaryExtraFilters
]);

View File

@ -2,9 +2,9 @@
namespace Webkul\Ui\Providers;
use Konekt\Concord\BaseModuleServiceProvider;
use Webkul\Core\Providers\CoreModuleServiceProvider;
class ModuleServiceProvider extends BaseModuleServiceProvider
class ModuleServiceProvider extends CoreModuleServiceProvider
{
protected $models = [
];

View File

@ -101,11 +101,7 @@
<select id="perPage" name="perPage" class="control" v-model="perPage"
v-on:change="paginate">
<option value="10"> 10</option>
<option value="20"> 20</option>
<option value="30"> 30</option>
<option value="40"> 40</option>
<option value="50"> 50</option>
<option v-for="index in this.perPageProduct" :key="index" :value="index"> @{{ index }} </option>
</select>
</div>
</div>
@ -306,7 +302,8 @@
booleanConditionSelect: false,
numberConditionSelect: false,
datetimeConditionSelect: false,
perPage: 10,
perPage: {{ $results['itemsPerPage'] ?: 10 }},
perPageProduct: [10, 20, 30, 40, 50],
extraFilters: @json($results['extraFilters']),
}
},
@ -321,6 +318,10 @@
}
}
}
if (this.perPageProduct.indexOf(parseInt(this.perPage)) === -1) {
this.perPageProduct.unshift(this.perPage);
}
},
methods: {

View File

@ -17,7 +17,7 @@ class RolesTableSeeder extends Seeder
DB::table('roles')->insert([
'id' => 1,
'name' => 'Administrator',
'description' => 'Administrator rolem',
'description' => 'Administrator role',
'permission_type' => 'all',
]);
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
{
"/js/velocity.js": "/js/velocity.js?id=08a2c62f552381e1627c",
"/js/velocity.js": "/js/velocity.js?id=d5391a65146f1d0f4ca1",
"/css/velocity-admin.css": "/css/velocity-admin.css?id=4322502d80a0e4a0affd",
"/css/velocity.css": "/css/velocity.css?id=e41e400c39a3cb5bc551"
"/css/velocity.css": "/css/velocity.css?id=69e21a90a84bca6263e5"
}

View File

@ -221,7 +221,7 @@ class Helper extends Review
}
if (! $channel) {
$channel = request()->get('channel') ?: 'default';
$channel = request()->get('channel') ?: core()->getCurrentChannelCode() ?: 'default';
}
try {

View File

@ -35,7 +35,7 @@ class ShopController extends Controller
'details' => [
'name' => $product->name,
'urlKey' => $product->url_key,
'priceHTML' => $product->getTypeInstance()->getPriceHtml(),
'priceHTML' => view('shop::products.price', ['product' => $product])->render(),
'totalReviews' => $productReviewHelper->getTotalReviews($product),
'rating' => ceil($productReviewHelper->getAverageRating($product)),
'image' => $galleryImages['small_image_url'],

View File

@ -67,12 +67,12 @@ class VelocityServiceProvider extends ServiceProvider
protected function registerFacades()
{
$loader = AliasLoader::getInstance();
$loader->alias('velocity', VelocityFacade::class);
}
/**
* this function will provide global variables shared by view (blade files)
* This method will load all publishables.
*
* @return boolean
*/
@ -85,24 +85,26 @@ class VelocityServiceProvider extends ServiceProvider
$this->publishes([
__DIR__ . '/../Resources/views/shop' => resource_path('themes/velocity/views'),
]);
$this->publishes([__DIR__.'/../Resources/lang' => resource_path('lang/vendor/velocity')]);
return true;
}
/**
* this function will provide global variables shared by view (blade files)
* This method will provide global variables shared by view (blade files).
*
* @return boolean
*/
private function loadGloableVariables()
{
$velocityHelper = app('Webkul\Velocity\Helpers\Helper');
$velocityMetaData = $velocityHelper->getVelocityMetaData();
view()->composer('*', function ($view) {
$velocityHelper = app('Webkul\Velocity\Helpers\Helper');
$velocityMetaData = $velocityHelper->getVelocityMetaData();
view()->share('showRecentlyViewed', true);
view()->share('velocityMetaData', $velocityMetaData);
$view->with('showRecentlyViewed', true);
$view->with('velocityMetaData', $velocityMetaData);
});
return true;
}

View File

@ -1,22 +1,36 @@
<template>
<div :class="currentType == 'video' ? '' : 'magnifier'">
<video :key="activeImageVideoURL" v-if="currentType == 'video'" width="100%" height="100%" controls>
<div class="video-container" v-if="currentType == 'video'">
<video :key="activeImageVideoURL" width="100%" controls>
<source :src="activeImageVideoURL" type="video/mp4">
</video>
<img v-else
:src="activeImageVideoURL"
:data-zoom-image="activeImageVideoURL"
class="main-product-image">
</div>
<div class="image-container" v-else>
<div class="magnifier">
<img :src="activeImageVideoURL" :data-zoom-image="activeImageVideoURL"
class="main-product-image">
</div>
</div>
</template>
<style lang="scss">
.magnifier {
> img {
max-width: 100%;
min-height: 530px;
max-height: 530px;
.image-container {
.magnifier {
> img {
max-width: 100%;
min-height: 530px;
max-height: 530px;
}
}
}
.video-container {
min-height: 530px;
max-height: 530px;
video {
top: 50%;
position: relative;
transform: translateY(-50%);
}
}
</style>
@ -28,18 +42,12 @@
data: function () {
return {
activeImage: null,
activeImageVideoURL: '',
currentType: '',
activeImageVideoURL: this.src,
currentType: this.type,
}
},
mounted: function () {
/* type checking for media type */
this.currentType = this.type;
/* getting url */
this.activeImageVideoURL = this.src;
/* binding should be with class as ezplus is having bug of creating multiple containers */
this.activeImage = $('.main-product-image');
this.activeImage.attr('src', this.activeImageVideoURL);
@ -53,18 +61,22 @@
$('.zoomContainer').remove();
this.activeImage.removeData('elevateZoom');
/* getting url */
this.activeImageVideoURL = largeImageUrl;
/* type checking for media type */
this.currentType = currentType;
/* getting url */
this.activeImageVideoURL = largeImageUrl;
/* waiting added for image because image element takes time load when switching from video */
this.waitForElement('.main-product-image', () => {
/* update source for images */
this.activeImage = $('.main-product-image');
this.activeImage.attr('src', smallImageUrl);
this.activeImage.data('zoom-image', largeImageUrl);
/* update source for images */
this.activeImage.attr('src', smallImageUrl);
this.activeImage.data('zoom-image', largeImageUrl);
/* reinitialize zoom */
this.elevateZoom();
/* reinitialize zoom */
this.elevateZoom();
});
});
},
@ -78,6 +90,16 @@
zoomWindowHeight: 250,
});
},
waitForElement: function (selector, callback) {
if (jQuery(selector).length) {
callback();
} else {
setTimeout(() => {
this.waitForElement(selector, callback);
}, 100);
}
},
}
}
</script>

View File

@ -7,7 +7,6 @@
v-if="cartItems.length > 0"
class="modal-content sensitive-modal cart-modal-content hide">
<!--Body-->
<div class="mini-cart-container">
<div class="row small-card-container" :key="index" v-for="(item, index) in cartItems">
<div class="col-3 product-image-container mr15">
@ -40,13 +39,12 @@
</div>
</div>
<!--Footer-->
<div class="modal-footer">
<h2 class="col-6 text-left fw6">
<h5 class="col-6 text-left fw6">
{{ subtotalText }}
</h2>
</h5>
<h2 class="col-6 text-right fw6 no-padding">{{ cartInformation.base_sub_total }}</h2>
<h5 class="col-6 text-right fw6 no-padding">{{ cartInformation.base_sub_total }}</h5>
</div>
<div class="modal-footer">
@ -66,6 +64,12 @@
</div>
</template>
<style lang="scss">
.hide {
display: none !important;
}
</style>
<script>
export default {
props: [
@ -74,8 +78,7 @@
'checkoutUrl',
'checkoutText',
'subtotalText',
'isMinimumOrderCompleted',
'minimumOrderMessage'
'checkMinimumOrderUrl'
],
data: function () {
@ -123,10 +126,16 @@
},
checkMinimumOrder: function (e) {
if (! Boolean(this.isMinimumOrderCompleted)) {
e.preventDefault();
window.showAlert(`alert-warning`, 'Warning', this.minimumOrderMessage);
}
e.preventDefault();
this.$http.post(this.checkMinimumOrderUrl)
.then(({ data }) => {
if (! data.status) {
window.showAlert(`alert-warning`, 'Warning', data.message);
} else {
window.location.href = this.checkoutUrl;
}
});
}
}
}

View File

@ -11,7 +11,7 @@
<div class="row" :class="localeDirection">
<div
class="col-md-12 no-padding carousel-products"
:class="showRecentlyViewed ? 'with-recent-viewed col-lg-9' : 'col-lg-12'">
:class="showRecentlyViewed ? 'with-recent-viewed col-lg-9' : 'without-recent-viewed col-lg-12'">
<carousel-component
:slides-per-page="slidesPerPage"
navigation-enabled="hide"
@ -85,6 +85,7 @@
});
this.getProducts();
this.setWindowWidth();
this.setSlidesPerPage(this.windowWidth);
},
@ -122,17 +123,46 @@
})
},
/* waiting for element */
waitForElement: function (selector, callback) {
if (jQuery(selector).length) {
callback();
} else {
setTimeout(() => {
this.waitForElement(selector, callback);
}, 100);
}
},
/* setting window width */
setWindowWidth: function () {
let windowClass = this.getWindowClass();
this.waitForElement(windowClass, () => {
this.windowWidth = $(windowClass).width();
});
},
/* get window class */
getWindowClass: function () {
return this.showRecentlyViewed ? '.with-recent-viewed' : '.without-recent-viewed';
},
/* on resize set window width */
onResize: function () {
this.windowWidth = window.innerWidth;
this.windowWidth = $(this.getWindowClass()).width();
},
/* setting slides on the basis of window width */
setSlidesPerPage: function (width) {
if (width >= 992) {
if (width >= 1200) {
this.slidesPerPage = 6;
} else if (width < 992 && width >= 420) {
} else if (width < 1200 && width >= 992) {
this.slidesPerPage = 5;
} else if (width < 992 && width >= 822) {
this.slidesPerPage = 4;
} else if (width < 822 && width >= 626) {
this.slidesPerPage = 3;
} else {
this.slidesPerPage = 2;
}

View File

@ -2,50 +2,52 @@
<div class="modal-parent scrollable">
<div class="cd-quick-view">
<template v-if="showProductDetails || true">
<div class="col-lg-6 product-gallery">
<ul class="cd-slider" type="none">
<carousel-component
slides-per-page="1"
navigation-enabled="hide"
:slides-count="product.galleryImages.length">
<div class="row">
<div class="col-lg-6">
<ul class="cd-slider" type="none">
<carousel-component
slides-per-page="1"
navigation-enabled="hide"
:slides-count="product.galleryImages.length">
<slide
:key="index"
:slot="`slide-${index}`"
title=" "
v-for="(image, index) in product.galleryImages">
<slide
:key="index"
:slot="`slide-${index}`"
title=" "
v-for="(image, index) in product.galleryImages">
<li class="selected" @click="showProductDetails = false">
<img :src="image.medium_image_url" :alt="product.name" />
</li>
</slide>
</carousel-component>
</ul>
</div>
<div class="col-lg-6 fs16">
<h2 class="fw6 quick-view-name">{{ product.name }}</h2>
<div class="product-price" v-html="product.priceHTML"></div>
<div
class="product-rating"
v-if="product.totalReviews && product.totalReviews > 0">
<star-ratings :ratings="product.avgRating"></star-ratings>
<a class="pl10 unset active-hover" :href="`${$root.baseUrl}/reviews/${product.slug}`">
{{ __('products.reviews-count', {'totalReviews': product.totalReviews}) }}
</a>
<li class="selected" @click="showProductDetails = false">
<img :src="image.medium_image_url" :alt="product.name" />
</li>
</slide>
</carousel-component>
</ul>
</div>
<div class="product-rating" v-else>
<span class="fs14" v-text="product.firstReviewText"></span>
</div>
<div class="col-lg-6 fs16">
<h2 class="fw6 quick-view-name">{{ product.name }}</h2>
<p class="pt14 fs14 description-text" v-html="product.shortDescription"></p>
<div class="product-price" v-html="product.priceHTML"></div>
<div class="product-actions">
<vnode-injector :nodes="getDynamicHTML(product.addToCartHtml)"></vnode-injector>
<div
class="product-rating"
v-if="product.totalReviews && product.totalReviews > 0">
<star-ratings :ratings="product.avgRating"></star-ratings>
<a class="pl10 unset active-hover" :href="`${$root.baseUrl}/reviews/${product.slug}`">
{{ __('products.reviews-count', {'totalReviews': product.totalReviews}) }}
</a>
</div>
<div class="product-rating" v-else>
<span class="fs14" v-text="product.firstReviewText"></span>
</div>
<p class="pt14 fs14 description-text" v-html="product.shortDescription"></p>
<div class="product-actions">
<vnode-injector :nodes="getDynamicHTML(product.addToCartHtml)"></vnode-injector>
</div>
</div>
</div>

View File

@ -6,7 +6,7 @@
</div>
</div>
<div :class="`recetly-viewed-products-wrapper ${addClassWrapper}`">
<div :class="`recently-viewed-products-wrapper ${addClassWrapper}`">
<div
:key="Math.random()"
class="row small-card-container"

View File

@ -33,7 +33,7 @@
<span class="category-title">{{ category['name'] }}</span>
<i
class="rango-arrow-right pr15 pull-right"
class="rango-arrow-right pr15 float-right"
@mouseout="toggleSidebar(id, $event, 'mouseout')"
@mouseover="toggleSidebar(id, $event, 'mouseover')"
v-if="category.children.length && category.children.length > 0">

View File

@ -5,7 +5,7 @@
type="number"
:value="showFilled"
name="rating"
class="hidden" />
class="d-none" />
<i
:class="`material-icons ${editable ? 'cursor-pointer' : ''}`"

View File

@ -4,7 +4,7 @@
*/
@import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro&display=swap');
//velocity variables
/* velocity variables */
$white-color: #FFFFFF;
$black-color: #111111;
$font-color: rgba(0,0,0,0.83);
@ -30,9 +30,10 @@ $light-link-color: #28557B;
$grey-clr: rgba(0,0,0,0.53);
$light-grey-clr: rgb(158, 158, 158);
$light-background: #F7F7F9;
/* other stuffs */
$sidebar-width: 230px;
$box-shadow: 0 10px 20px rgba(0, 0, 0, 0.19), 0 6px 6px rgba(0, 0, 0, 0.23);
$material-icons-font-path: "../material-icons/iconfont/" !default;
$material-icons-font-path: '../material-icons/iconfont/' !default;
$border-normal: 1px solid $border-dark;
$font-family-pro: 'Source Sans Pro', sans-serif;

View File

@ -12,7 +12,6 @@
@import "components/rtl";
@import "static/material-icons";
@import "node_modules/bootstrap-sass/assets/stylesheets/bootstrap";
* {
margin: 0;
@ -196,6 +195,7 @@ body {
display: table;
min-width: 150px;
cursor: pointer;
float: right;
text-align: right;
padding-top: 5px;
@ -207,8 +207,6 @@ body {
}
+ .account-modal {
@extend .modal-dialog;
top: 40px;
right: 10px;
z-index: 101;
@ -414,7 +412,7 @@ header {
width: 210px;
.select-icon {
top: 9px;
top: -30px;
right: 8px;
z-index: 10;
font-size: 18px;
@ -485,6 +483,7 @@ header {
.mini-cart-container {
height: 50px;
padding: 5px 17px;
display: inline-block;
#mini-cart {
.mini-cart-content {
@ -514,15 +513,14 @@ header {
}
}
}
// transform: scale(1) rotateZ(-180deg);
// transition: transform .15s,opacity .15s;
}
}
~ .compare-btn,
~ .wishlist-btn {
.left-wrapper {
float: right;
.compare-btn, .wishlist-btn {
height: 50px;
float: right;
font-size: 18px;
font-weight: 600;
padding: 10px 16px 6px 16px;
@ -544,6 +542,7 @@ header {
padding: 4px;
min-width: 20px;
position: absolute;
color: $font-color-light;
background: $button-primary-bg;
}
}
@ -888,7 +887,7 @@ header {
text-align: center;
vertical-align: middle;
border-radius: 50%;
background: #21a179;
background: $button-primary-bg;
color: #fff;
padding: 16px;
font: 18px "josefin sans", arial;

View File

@ -230,7 +230,7 @@
}
.product-card-new {
width: 19rem;
width: 12rem;
height: 385px;
border: none !important;
margin: 0 5px 10px 10px;
@ -555,7 +555,8 @@
min-width: 20px;
border-radius: 50%;
position: relative;
background: #21A179;
color: $white-color;
background: $button-primary-bg;
}
}
}
@ -574,6 +575,7 @@
padding: 4px;
min-width: 20px;
position: absolute;
color: $white-color;
background: $button-primary-bg;
}
}
@ -641,7 +643,7 @@
.rango-close {
top: -10px;
left: -10px;
padding: 3px 4px 3px 3px;
padding: 0px 4px 3px 3px;
font-size: 10px;
max-height: 17px;
line-height: 1.3rem;
@ -835,6 +837,7 @@
}
a {
display: block;
padding: 10px 15px;
}
}
@ -1046,7 +1049,7 @@
}
.filter-left {
@extend .pull-left;
float: left;
}
.filter-right {
@ -2051,7 +2054,7 @@
.category-container,
.search-container {
.grid-card {
width: 22rem;
width: 15rem;
}
}
@ -2335,7 +2338,7 @@
position: relative;
}
.recetly-viewed-products-wrapper {
.recently-viewed-products-wrapper {
padding: 2px;
.price-from {

View File

@ -1,4 +1,3 @@
body {
display: none;
overflow-x: hidden;
@ -186,7 +185,7 @@ header #search-form > *:focus {
}
/* advertisements */
.recetly-viewed-items {
.recently-viewed-items {
padding-left: 10px !important;
padding: 0px !important;
}

View File

@ -44,6 +44,7 @@ body {
}
.select-icon {
top: 12px;
left: 8px;
}
}
@ -57,10 +58,18 @@ body {
}
.mini-cart-container {
~ .compare-btn,
~ .wishlist-btn {
float: left;
#mini-cart {
.badge {
top: -8px;
left: 73%;
}
}
}
.left-wrapper {
float: left;
.compare-btn, .wishlist-btn {
.badge-container {
.badge {
top: -28px;
@ -68,21 +77,6 @@ body {
}
}
}
~ .wishlist-btn , ~ .compare-btn {
.badge-container {
.badge {
left: 20px;
}
}
}
#mini-cart {
.badge {
top: -8px;
left: 73%;
}
}
}
}
@ -109,8 +103,8 @@ body {
}
}
.main-content-wrapper .vc-header
.main-content-wrapper
.vc-header
.mini-cart-container {
#mini-cart {
.badge {
@ -123,30 +117,6 @@ body {
vertical-align: top;
}
}
~ .compare-btn,
~ .wishlist-btn {
.badge-container {
top: -6px;
left: 20px;
vertical-align: top;
.badge {
top: 0;
left: 0;
}
}
}
~ .compare-btn {
left: 15%;
float: left;
position: relative;
}
~ .wishlist-btn {
float: right;
}
}
.form-container {
@ -190,15 +160,20 @@ body {
#top {
#account {
.welcome-content {
float: left;
i {
text-align: left;
}
}
+ .account-modal {
left: 0;
right: 0;
margin-left: 0;
width: 100% !important;
right: unset;
.modal-content {
float: left;
}
}
}
@ -207,14 +182,6 @@ body {
right: 20px;
}
}
#account {
+ .account-modal {
.modal-content {
float: left;
}
}
}
}
#cart-modal-content {
@ -349,6 +316,11 @@ body {
> h2, div {
padding-right: 0px;
}
.buynow {
float: left;
margin-right: 10px;
}
}
}

View File

@ -233,7 +233,6 @@
.full-width {
width: 100%;
display: block;
}
.full-image {
@ -598,7 +597,7 @@
padding: 10px 0 !important;
.product-name {
width: 17rem;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;

View File

@ -111,7 +111,17 @@ return [
'advertisement-three' => 'إعلان ثلاث صور',
'images' => 'صور',
'general' => 'جنرال لواء',
'add-image-btn-title' => 'إضافة صورة'
'add-image-btn-title' => 'إضافة صورة',
'footer-middle' => [
'about-us' => 'About Us',
'customer-service' => 'Customer Service',
'whats-new' => 'What\'s New',
'contact-us' => 'Contact Us',
'order-and-returns' => 'Order and Returns',
'payment-policy' => 'Payment Policy',
'shipping-policy' => 'Shipping Policy',
'privacy-and-cookies-policy' => 'Privacy and Cookies Policy'
]
],
'category' => [
'save-btn-title' => 'قائمة الحفظ',

View File

@ -111,7 +111,17 @@ return [
'advertisement-three' => 'Werbung Drei Bilder',
'images' => 'Bilder',
'general' => 'Allgemein',
'add-image-btn-title' => 'Bild hinzufügen'
'add-image-btn-title' => 'Bild hinzufügen',
'footer-middle' => [
'about-us' => 'About Us',
'customer-service' => 'Customer Service',
'whats-new' => 'What\'s New',
'contact-us' => 'Contact Us',
'order-and-returns' => 'Order and Returns',
'payment-policy' => 'Payment Policy',
'shipping-policy' => 'Shipping Policy',
'privacy-and-cookies-policy' => 'Privacy and Cookies Policy'
]
],
'category' => [
'save-btn-title' => 'Menü speichern',

View File

@ -111,7 +111,17 @@ return [
'advertisement-three' => 'Advertisement Three Images',
'images' => 'Images',
'general' => 'General',
'add-image-btn-title' => 'Add Image'
'add-image-btn-title' => 'Add Image',
'footer-middle' => [
'about-us' => 'About Us',
'customer-service' => 'Customer Service',
'whats-new' => 'What\'s New',
'contact-us' => 'Contact Us',
'order-and-returns' => 'Order and Returns',
'payment-policy' => 'Payment Policy',
'shipping-policy' => 'Shipping Policy',
'privacy-and-cookies-policy' => 'Privacy and Cookies Policy'
]
],
'category' => [
'save-btn-title' => 'Save Menu',

View File

@ -111,7 +111,17 @@ return [
'advertisement-three' => 'تبلیغات سه تصویر',
'images' => 'تصاویر',
'general' => 'عمومی',
'add-image-btn-title' => 'تصویر اضافه کن'
'add-image-btn-title' => 'تصویر اضافه کن',
'footer-middle' => [
'about-us' => 'About Us',
'customer-service' => 'Customer Service',
'whats-new' => 'What\'s New',
'contact-us' => 'Contact Us',
'order-and-returns' => 'Order and Returns',
'payment-policy' => 'Payment Policy',
'shipping-policy' => 'Shipping Policy',
'privacy-and-cookies-policy' => 'Privacy and Cookies Policy'
]
],
'category' => [
'save-btn-title' => 'ذخیره منو',

Some files were not shown because too many files have changed in this diff Show More