Merge pull request #17 from bagisto/master

This commit is contained in:
Glenn Hermans 2021-05-02 19:15:16 +02:00 committed by GitHub
commit 2238c660c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 2868 additions and 832 deletions

95
composer.lock generated
View File

@ -2930,16 +2930,16 @@
},
{
"name": "laravel/framework",
"version": "v8.35.1",
"version": "v8.40.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "d118c0df39e7524131176aaf76493eae63a8a602"
"reference": "a654897ad7f97aea9d7ef292803939798c4a02a4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/d118c0df39e7524131176aaf76493eae63a8a602",
"reference": "d118c0df39e7524131176aaf76493eae63a8a602",
"url": "https://api.github.com/repos/laravel/framework/zipball/a654897ad7f97aea9d7ef292803939798c4a02a4",
"reference": "a654897ad7f97aea9d7ef292803939798c4a02a4",
"shasum": ""
},
"require": {
@ -3094,7 +3094,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2021-03-30T21:34:17+00:00"
"time": "2021-04-28T14:38:56+00:00"
},
{
"name": "laravel/legacy-factories",
@ -4627,16 +4627,16 @@
},
{
"name": "opis/closure",
"version": "3.6.1",
"version": "3.6.2",
"source": {
"type": "git",
"url": "https://github.com/opis/closure.git",
"reference": "943b5d70cc5ae7483f6aff6ff43d7e34592ca0f5"
"reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/opis/closure/zipball/943b5d70cc5ae7483f6aff6ff43d7e34592ca0f5",
"reference": "943b5d70cc5ae7483f6aff6ff43d7e34592ca0f5",
"url": "https://api.github.com/repos/opis/closure/zipball/06e2ebd25f2869e54a306dda991f7db58066f7f6",
"reference": "06e2ebd25f2869e54a306dda991f7db58066f7f6",
"shasum": ""
},
"require": {
@ -4686,9 +4686,9 @@
],
"support": {
"issues": "https://github.com/opis/closure/issues",
"source": "https://github.com/opis/closure/tree/3.6.1"
"source": "https://github.com/opis/closure/tree/3.6.2"
},
"time": "2020-11-07T02:01:34+00:00"
"time": "2021-04-09T13:42:10+00:00"
},
{
"name": "paypal/paypal-checkout-sdk",
@ -6220,16 +6220,16 @@
},
{
"name": "symfony/deprecation-contracts",
"version": "v2.2.0",
"version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665"
"reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5fa56b4074d1ae755beb55617ddafe6f5d78f665",
"reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627",
"reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627",
"shasum": ""
},
"require": {
@ -6238,7 +6238,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
"dev-main": "2.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -6267,7 +6267,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/master"
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0"
},
"funding": [
{
@ -6283,7 +6283,7 @@
"type": "tidelift"
}
],
"time": "2020-09-07T11:33:47+00:00"
"time": "2021-03-23T23:28:01+00:00"
},
{
"name": "symfony/error-handler",
@ -6441,16 +6441,16 @@
},
{
"name": "symfony/event-dispatcher-contracts",
"version": "v2.2.0",
"version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
"reference": "0ba7d54483095a198fa51781bc608d17e84dffa2"
"reference": "69fee1ad2332a7cbab3aca13591953da9cdb7a11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/0ba7d54483095a198fa51781bc608d17e84dffa2",
"reference": "0ba7d54483095a198fa51781bc608d17e84dffa2",
"url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/69fee1ad2332a7cbab3aca13591953da9cdb7a11",
"reference": "69fee1ad2332a7cbab3aca13591953da9cdb7a11",
"shasum": ""
},
"require": {
@ -6463,7 +6463,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
"dev-main": "2.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -6500,7 +6500,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.2.0"
"source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.4.0"
},
"funding": [
{
@ -6516,7 +6516,7 @@
"type": "tidelift"
}
],
"time": "2020-09-07T11:33:47+00:00"
"time": "2021-03-23T23:28:01+00:00"
},
{
"name": "symfony/finder",
@ -6581,16 +6581,16 @@
},
{
"name": "symfony/http-client-contracts",
"version": "v2.3.1",
"version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client-contracts.git",
"reference": "41db680a15018f9c1d4b23516059633ce280ca33"
"reference": "7e82f6084d7cae521a75ef2cb5c9457bbda785f4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/41db680a15018f9c1d4b23516059633ce280ca33",
"reference": "41db680a15018f9c1d4b23516059633ce280ca33",
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/7e82f6084d7cae521a75ef2cb5c9457bbda785f4",
"reference": "7e82f6084d7cae521a75ef2cb5c9457bbda785f4",
"shasum": ""
},
"require": {
@ -6601,9 +6601,8 @@
},
"type": "library",
"extra": {
"branch-version": "2.3",
"branch-alias": {
"dev-main": "2.3-dev"
"dev-main": "2.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -6640,7 +6639,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/http-client-contracts/tree/v2.3.1"
"source": "https://github.com/symfony/http-client-contracts/tree/v2.4.0"
},
"funding": [
{
@ -6656,7 +6655,7 @@
"type": "tidelift"
}
],
"time": "2020-10-14T17:08:19+00:00"
"time": "2021-04-11T23:07:08+00:00"
},
{
"name": "symfony/http-foundation",
@ -7877,21 +7876,21 @@
},
{
"name": "symfony/service-contracts",
"version": "v2.2.0",
"version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
"reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1"
"reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1",
"reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb",
"reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb",
"shasum": ""
},
"require": {
"php": ">=7.2.5",
"psr/container": "^1.0"
"psr/container": "^1.1"
},
"suggest": {
"symfony/service-implementation": ""
@ -7899,7 +7898,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.2-dev"
"dev-main": "2.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -7936,7 +7935,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/master"
"source": "https://github.com/symfony/service-contracts/tree/v2.4.0"
},
"funding": [
{
@ -7952,7 +7951,7 @@
"type": "tidelift"
}
],
"time": "2020-09-07T11:33:47+00:00"
"time": "2021-04-01T10:43:52+00:00"
},
{
"name": "symfony/string",
@ -8132,16 +8131,16 @@
},
{
"name": "symfony/translation-contracts",
"version": "v2.3.0",
"version": "v2.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation-contracts.git",
"reference": "e2eaa60b558f26a4b0354e1bbb25636efaaad105"
"reference": "95c812666f3e91db75385749fe219c5e494c7f95"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/e2eaa60b558f26a4b0354e1bbb25636efaaad105",
"reference": "e2eaa60b558f26a4b0354e1bbb25636efaaad105",
"url": "https://api.github.com/repos/symfony/translation-contracts/zipball/95c812666f3e91db75385749fe219c5e494c7f95",
"reference": "95c812666f3e91db75385749fe219c5e494c7f95",
"shasum": ""
},
"require": {
@ -8153,7 +8152,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.3-dev"
"dev-main": "2.4-dev"
},
"thanks": {
"name": "symfony/contracts",
@ -8190,7 +8189,7 @@
"standards"
],
"support": {
"source": "https://github.com/symfony/translation-contracts/tree/v2.3.0"
"source": "https://github.com/symfony/translation-contracts/tree/v2.4.0"
},
"funding": [
{
@ -8206,7 +8205,7 @@
"type": "tidelift"
}
],
"time": "2020-09-28T13:05:58+00:00"
"time": "2021-03-23T23:28:01+00:00"
},
{
"name": "symfony/var-dumper",

View File

@ -150,6 +150,14 @@ class CustomerDataGrid extends DataGrid
'icon' => 'icon note-icon',
'title' => trans('admin::app.customers.note.help-title'),
]);
$this->addAction([
'type' => 'Edit',
'method' => 'GET',
'route' => 'admin.customer.orders.index',
'icon' => 'icon list-icon',
'title' => trans('admin::app.customers.orders.title'),
]);
}
/**

View File

@ -0,0 +1,141 @@
<?php
namespace Webkul\Admin\DataGrids;
use Illuminate\Support\Facades\DB;
use Webkul\Sales\Models\OrderAddress;
use Webkul\Ui\DataGrid\DataGrid;
class CustomerOrderDataGrid extends DataGrid
{
protected $index = 'id';
protected $sortOrder = 'desc';
public function prepareQueryBuilder()
{
$queryBuilder = DB::table('orders')
->leftJoin('addresses as order_address_shipping', function($leftJoin) {
$leftJoin->on('order_address_shipping.order_id', '=', 'orders.id')
->where('order_address_shipping.address_type', OrderAddress::ADDRESS_TYPE_SHIPPING);
})
->leftJoin('addresses as order_address_billing', function($leftJoin) {
$leftJoin->on('order_address_billing.order_id', '=', 'orders.id')
->where('order_address_billing.address_type', OrderAddress::ADDRESS_TYPE_BILLING);
})
->addSelect('orders.id','orders.increment_id', 'orders.base_sub_total', 'orders.base_grand_total', 'orders.created_at', 'channel_name', 'status')
->addSelect(DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_billing.first_name, " ", ' . DB::getTablePrefix() . 'order_address_billing.last_name) as billed_to'))
->addSelect(DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_shipping.first_name, " ", ' . DB::getTablePrefix() . 'order_address_shipping.last_name) as shipped_to'))
->where('orders.customer_id', request('id'));
$this->addFilter('billed_to', DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_billing.first_name, " ", ' . DB::getTablePrefix() . 'order_address_billing.last_name)'));
$this->addFilter('shipped_to', DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_shipping.first_name, " ", ' . DB::getTablePrefix() . 'order_address_shipping.last_name)'));
$this->addFilter('increment_id', 'orders.increment_id');
$this->addFilter('created_at', 'orders.created_at');
$this->setQueryBuilder($queryBuilder);
}
public function addColumns()
{
$this->addColumn([
'index' => 'increment_id',
'label' => trans('admin::app.datagrid.id'),
'type' => 'string',
'searchable' => false,
'sortable' => true,
'filterable' => true,
]);
$this->addColumn([
'index' => 'base_sub_total',
'label' => trans('admin::app.datagrid.sub-total'),
'type' => 'price',
'searchable' => false,
'sortable' => true,
'filterable' => true,
]);
$this->addColumn([
'index' => 'base_grand_total',
'label' => trans('admin::app.datagrid.grand-total'),
'type' => 'price',
'searchable' => false,
'sortable' => true,
'filterable' => true,
]);
$this->addColumn([
'index' => 'created_at',
'label' => trans('admin::app.datagrid.order-date'),
'type' => 'datetime',
'sortable' => true,
'searchable' => false,
'filterable' => true,
]);
$this->addColumn([
'index' => 'channel_name',
'label' => trans('admin::app.datagrid.channel-name'),
'type' => 'string',
'sortable' => true,
'searchable' => true,
'filterable' => true,
]);
$this->addColumn([
'index' => 'status',
'label' => trans('admin::app.datagrid.status'),
'type' => 'string',
'sortable' => true,
'searchable' => true,
'closure' => true,
'filterable' => true,
'wrapper' => function ($value) {
if ($value->status == 'processing') {
return '<span class="badge badge-md badge-success">'. trans('admin::app.sales.orders.order-status-processing') .'</span>';
} elseif ($value->status == 'completed') {
return '<span class="badge badge-md badge-success">'. trans('admin::app.sales.orders.order-status-success') .'</span>';
} elseif ($value->status == "canceled") {
return '<span class="badge badge-md badge-danger">'. trans('admin::app.sales.orders.order-status-canceled') .'</span>';
} elseif ($value->status == "closed") {
return '<span class="badge badge-md badge-info">'. trans('admin::app.sales.orders.order-status-closed') .'</span>';
} elseif ($value->status == "pending") {
return '<span class="badge badge-md badge-warning">'. trans('admin::app.sales.orders.order-status-pending') .'</span>';
} elseif ($value->status == "pending_payment") {
return '<span class="badge badge-md badge-warning">'. trans('admin::app.sales.orders.order-status-pending-payment') .'</span>';
} elseif ($value->status == "fraud") {
return '<span class="badge badge-md badge-danger">'. trans('admin::app.sales.orders.order-status-fraud') . '</span>';
}
},
]);
$this->addColumn([
'index' => 'billed_to',
'label' => trans('admin::app.datagrid.billed-to'),
'type' => 'string',
'searchable' => true,
'sortable' => true,
'filterable' => true,
]);
$this->addColumn([
'index' => 'shipped_to',
'label' => trans('admin::app.datagrid.shipped-to'),
'type' => 'string',
'searchable' => true,
'sortable' => true,
'filterable' => true,
]);
}
public function prepareActions()
{
$this->addAction([
'title' => trans('admin::app.datagrid.view'),
'method' => 'GET',
'route' => 'admin.sales.orders.view',
'icon' => 'icon eye-icon',
]);
}
}

View File

@ -2,12 +2,15 @@
namespace Webkul\Admin\DataGrids;
use Webkul\Ui\DataGrid\DataGrid;
use Illuminate\Support\Facades\DB;
use Webkul\Sales\Models\OrderAddress;
use Webkul\Ui\DataGrid\DataGrid;
use Webkul\Ui\DataGrid\Traits\ProvideDataGridPlus;
class OrderDataGrid extends DataGrid
{
use ProvideDataGridPlus;
protected $index = 'id';
protected $sortOrder = 'desc';
@ -15,15 +18,15 @@ class OrderDataGrid extends DataGrid
public function prepareQueryBuilder()
{
$queryBuilder = DB::table('orders')
->leftJoin('addresses as order_address_shipping', function($leftJoin) {
->leftJoin('addresses as order_address_shipping', function ($leftJoin) {
$leftJoin->on('order_address_shipping.order_id', '=', 'orders.id')
->where('order_address_shipping.address_type', OrderAddress::ADDRESS_TYPE_SHIPPING);
->where('order_address_shipping.address_type', OrderAddress::ADDRESS_TYPE_SHIPPING);
})
->leftJoin('addresses as order_address_billing', function($leftJoin) {
->leftJoin('addresses as order_address_billing', function ($leftJoin) {
$leftJoin->on('order_address_billing.order_id', '=', 'orders.id')
->where('order_address_billing.address_type', OrderAddress::ADDRESS_TYPE_BILLING);
->where('order_address_billing.address_type', OrderAddress::ADDRESS_TYPE_BILLING);
})
->addSelect('orders.id','orders.increment_id', 'orders.base_sub_total', 'orders.base_grand_total', 'orders.created_at', 'channel_name', 'status')
->addSelect('orders.id', 'orders.increment_id', 'orders.base_sub_total', 'orders.base_grand_total', 'orders.created_at', 'channel_name', 'status')
->addSelect(DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_billing.first_name, " ", ' . DB::getTablePrefix() . 'order_address_billing.last_name) as billed_to'))
->addSelect(DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_shipping.first_name, " ", ' . DB::getTablePrefix() . 'order_address_shipping.last_name) as shipped_to'));
@ -92,19 +95,19 @@ class OrderDataGrid extends DataGrid
'filterable' => true,
'wrapper' => function ($value) {
if ($value->status == 'processing') {
return '<span class="badge badge-md badge-success">'. trans('admin::app.sales.orders.order-status-processing') .'</span>';
return '<span class="badge badge-md badge-success">' . trans('admin::app.sales.orders.order-status-processing') . '</span>';
} elseif ($value->status == 'completed') {
return '<span class="badge badge-md badge-success">'. trans('admin::app.sales.orders.order-status-success') .'</span>';
return '<span class="badge badge-md badge-success">' . trans('admin::app.sales.orders.order-status-success') . '</span>';
} elseif ($value->status == "canceled") {
return '<span class="badge badge-md badge-danger">'. trans('admin::app.sales.orders.order-status-canceled') .'</span>';
return '<span class="badge badge-md badge-danger">' . trans('admin::app.sales.orders.order-status-canceled') . '</span>';
} elseif ($value->status == "closed") {
return '<span class="badge badge-md badge-info">'. trans('admin::app.sales.orders.order-status-closed') .'</span>';
return '<span class="badge badge-md badge-info">' . trans('admin::app.sales.orders.order-status-closed') . '</span>';
} elseif ($value->status == "pending") {
return '<span class="badge badge-md badge-warning">'. trans('admin::app.sales.orders.order-status-pending') .'</span>';
return '<span class="badge badge-md badge-warning">' . trans('admin::app.sales.orders.order-status-pending') . '</span>';
} elseif ($value->status == "pending_payment") {
return '<span class="badge badge-md badge-warning">'. trans('admin::app.sales.orders.order-status-pending-payment') .'</span>';
return '<span class="badge badge-md badge-warning">' . trans('admin::app.sales.orders.order-status-pending-payment') . '</span>';
} elseif ($value->status == "fraud") {
return '<span class="badge badge-md badge-danger">'. trans('admin::app.sales.orders.order-status-fraud') . '</span>';
return '<span class="badge badge-md badge-danger">' . trans('admin::app.sales.orders.order-status-fraud') . '</span>';
}
},
]);
@ -137,4 +140,4 @@ class OrderDataGrid extends DataGrid
'icon' => 'icon eye-icon',
]);
}
}
}

View File

@ -301,4 +301,17 @@ class CustomerController extends Controller
session()->flash('error', trans('admin::app.response.order-pending', ['name' => 'Customers']));
return redirect()->back();
}
/**
* Display a listing of the customer orders.
*
* @param int $id
* @return \Illuminate\View\View
*/
public function orders($id)
{
$customer = $this->customerRepository->find($id);
return view($this->_config['view'], compact('customer'));
}
}

View File

@ -3,6 +3,7 @@
namespace Webkul\Admin\Http\Controllers\Sales;
use Illuminate\Support\Facades\Event;
use Webkul\Admin\DataGrids\OrderDataGrid;
use Webkul\Admin\Http\Controllers\Controller;
use Webkul\Sales\Repositories\OrderRepository;
use \Webkul\Sales\Repositories\OrderCommentRepository;
@ -58,6 +59,10 @@ class OrderController extends Controller
*/
public function index()
{
if (request()->ajax()) {
return app(OrderDataGrid::class)->toJson();
}
return view($this->_config['view']);
}

View File

@ -112,6 +112,11 @@ Route::group(['middleware' => ['web']], function () {
'redirect' => 'admin.customer.addresses.index',
])->name('admin.customer.addresses.massdelete');
//customer's orders route
Route::get('customers/{id}/orders', 'Webkul\Admin\Http\Controllers\Customer\CustomerController@orders')->defaults('_config', [
'view' => 'admin::customers.orders.index',
])->name('admin.customer.orders.index');
// Configuration routes
Route::get('configuration/{slug?}/{slug2?}', 'Webkul\Admin\Http\Controllers\ConfigurationController@index')->defaults('_config', [
'view' => 'admin::configuration.index',

View File

@ -2,34 +2,40 @@
namespace Webkul\Admin\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* Bootstrap services.
* The event handler mappings for the application.
*
* @return void
* @var array
*/
public function boot()
{
Event::listen('user.admin.update-password', 'Webkul\Admin\Listeners\PasswordChange@sendUpdatePasswordMail');
Event::listen('checkout.order.save.after', 'Webkul\Admin\Listeners\Order@sendNewOrderMail');
Event::listen('sales.invoice.save.after', 'Webkul\Admin\Listeners\Order@sendNewInvoiceMail');
Event::listen('sales.shipment.save.after', 'Webkul\Admin\Listeners\Order@sendNewShipmentMail');
Event::listen('sales.order.cancel.after', 'Webkul\Admin\Listeners\Order@sendCancelOrderMail');
Event::listen('sales.refund.save.after', 'Webkul\Admin\Listeners\Order@refundOrder');
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');
}
}
protected $listen = [
'user.admin.update-password' => [
'Webkul\Admin\Listeners\PasswordChange@sendUpdatePasswordMail'
],
'checkout.order.save.after' => [
'Webkul\Admin\Listeners\Order@sendNewOrderMail'
],
'sales.invoice.save.after' => [
'Webkul\Admin\Listeners\Order@sendNewInvoiceMail'
],
'sales.shipment.save.after' => [
'Webkul\Admin\Listeners\Order@sendNewShipmentMail'
],
'sales.order.cancel.after' => [
'Webkul\Admin\Listeners\Order@sendCancelOrderMail'
],
'sales.refund.save.after' => [
'Webkul\Admin\Listeners\Order@refundOrder',
'Webkul\Admin\Listeners\Order@sendNewRefundMail',
],
'sales.order.comment.create.after' => [
'Webkul\Admin\Listeners\Order@sendOrderCommentMail'
],
'core.channel.update.after' => [
'Webkul\Admin\Listeners\ChannelSettingsChange@checkForMaintenaceMode'
],
];
}

View File

@ -1029,9 +1029,17 @@ return [
'is_subscribed' => 'Subscribed',
'edit-btn-title' => 'Update Subscriber',
'update-success' => 'Subscriber was successfully updated',
'update-failed' => 'Error! You cannot unsubscribe the subscriber',
'delete' => 'Subscriber was successfully deleted',
'delete-failed' => 'Error! Subscriber cannot be deleted',
'update-failed' => 'Error! You cannot unsubscribe the subscriber',
'delete' => 'Subscriber was successfully deleted',
'delete-failed' => 'Error! Subscriber cannot be deleted'
],
'orders' => [
'list' => ':customer_name\'s orders List',
'title' => 'Orders'
]
],

View File

@ -0,0 +1,27 @@
@extends('admin::layouts.content')
@section('page_title')
{{ __('admin::app.customers.orders.list', ['customer_name' => $customer->first_name . ' ' . $customer->last_name]) }}
@stop
@section('content')
<div class="content">
<div class="page-header">
<div class="page-title">
<h1>
<i class="icon angle-left-icon back-link" onclick="history.length > 1 ? history.go(-1) : window.location = '{{ url('/admin/dashboard') }}';"></i>
{{ __('admin::app.customers.orders.list', ['customer_name' => $customer->first_name . ' ' . $customer->last_name]) }}
</h1>
</div>
</div>
<div class="page-content">
@inject('customerOrderGrid','Webkul\Admin\DataGrids\CustomerOrderDataGrid')
{!! $customerOrderGrid->render() !!}
</div>
</div>
@stop

View File

@ -22,8 +22,7 @@
</div>
<div class="page-content">
@inject('orderGrid', 'Webkul\Admin\DataGrids\OrderDataGrid')
{!! $orderGrid->render() !!}
<datagrid-plus src="{{ route('admin.sales.orders.index') }}"></datagrid-plus>
</div>
</div>
@ -37,5 +36,5 @@
@stop
@push('scripts')
@include('admin::export.export', ['gridName' => $orderGrid])
@include('admin::export.export', ['gridName' => app('Webkul\Admin\DataGrids\OrderDataGrid')])
@endpush

View File

@ -3,12 +3,23 @@
namespace Webkul\BookingProduct\Providers;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use Webkul\Theme\ViewRenderEventManager;
class EventServiceProvider extends ServiceProvider
{
/**
* The event handler mappings for the application.
*
* @var array
*/
protected $listen = [
'checkout.order.save.after' => [
'Webkul\BookingProduct\Listeners\Order@afterPlaceOrder'
],
];
/**
* Bootstrap services.
*
@ -16,12 +27,12 @@ class EventServiceProvider extends ServiceProvider
*/
public function boot()
{
parent::boot();
Event::listen('bagisto.shop.products.view.short_description.after', static function(ViewRenderEventManager $viewRenderEventManager) {
if (View::exists('bookingproduct::shop.' . core()->getCurrentChannel()->theme . '.products.view.booking')) {
$viewRenderEventManager->addTemplate('bookingproduct::shop.' . core()->getCurrentChannel()->theme . '.products.view.booking');
}
});
Event::listen('checkout.order.save.after', 'Webkul\BookingProduct\Listeners\Order@afterPlaceOrder');
}
}
}

View File

@ -2,20 +2,21 @@
namespace Webkul\CartRule\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* Bootstrap services.
* The event handler mappings for the application.
*
* @return void
* @var array
*/
public function boot()
{
Event::listen('checkout.order.save.after', 'Webkul\CartRule\Listeners\Order@manageCartRule');
Event::listen('checkout.cart.collect.totals.before', 'Webkul\CartRule\Listeners\Cart@applyCartRules');
}
}
protected $listen = [
'checkout.order.save.after' => [
'Webkul\CartRule\Listeners\Order@manageCartRule'
],
'checkout.cart.collect.totals.before' => [
'Webkul\CartRule\Listeners\Cart@applyCartRules'
],
];
}

View File

@ -963,7 +963,7 @@ class Cart
}
if (! $wishlistItem->additional) {
$wishlistItem->additional = ['product_id' => $wishlistItem->product_id];
$wishlistItem->additional = ['product_id' => $wishlistItem->product_id, 'quantity' => 1];
}
request()->merge($wishlistItem->additional);

View File

@ -48,6 +48,19 @@ class ProductFlat
*/
protected $attribute;
/**
* Attribute codes that can be fill during flat creation.
*
* @var string[]
*/
protected $fillableAttributeCodes = [
'sku',
'name',
'price',
'weight',
'status',
];
/**
* @var array
*/
@ -212,7 +225,7 @@ class ProductFlat
}
foreach ($familyAttributes[$product->attribute_family->id] as $attribute) {
if ($parentProduct && ! in_array($attribute->code, array_merge($superAttributes[$parentProduct->id], ['sku', 'name', 'price', 'weight', 'status']))) {
if ($parentProduct && ! in_array($attribute->code, array_merge($superAttributes[$parentProduct->id], $this->fillableAttributeCodes))) {
continue;
}

View File

@ -2,26 +2,30 @@
namespace Webkul\Product\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* Bootstrap services.
* The event handler mappings for the application.
*
* @return void
* @var array
*/
public function boot()
{
Event::listen('catalog.attribute.create.after', 'Webkul\Product\Listeners\ProductFlat@afterAttributeCreatedUpdated');
Event::listen('catalog.attribute.update.after', 'Webkul\Product\Listeners\ProductFlat@afterAttributeCreatedUpdated');
Event::listen('catalog.attribute.delete.before', 'Webkul\Product\Listeners\ProductFlat@afterAttributeDeleted');
Event::listen('catalog.product.create.after', 'Webkul\Product\Listeners\ProductFlat@afterProductCreatedUpdated');
Event::listen('catalog.product.update.after', 'Webkul\Product\Listeners\ProductFlat@afterProductCreatedUpdated');
}
}
protected $listen = [
'catalog.attribute.create.after' => [
'Webkul\Product\Listeners\ProductFlat@afterAttributeCreatedUpdated'
],
'catalog.attribute.update.after' => [
'Webkul\Product\Listeners\ProductFlat@afterAttributeCreatedUpdated'
],
'catalog.attribute.delete.before' => [
'Webkul\Product\Listeners\ProductFlat@afterAttributeDeleted'
],
'catalog.product.create.after' => [
'Webkul\Product\Listeners\ProductFlat@afterProductCreatedUpdated'
],
'catalog.product.update.after' => [
'Webkul\Product\Listeners\ProductFlat@afterProductCreatedUpdated'
],
];
}

View File

@ -1,3 +1 @@
/node_modules
/package-lock.json
npm-debug.log
/node_modules

File diff suppressed because one or more lines are too long

View File

@ -1,20 +1,3 @@
/* flatpickr v4.6.6, @license MIT */
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/**
*
*

View File

@ -1,4 +1,4 @@
{
"/js/ui.js": "/js/ui.js?id=be48dc81d004f4655af0",
"/js/ui.js": "/js/ui.js?id=37bd4257e03367bb39c4",
"/css/ui.css": "/css/ui.css?id=6d93a4a052e38d6aa795"
}

View File

@ -3,9 +3,13 @@
namespace Webkul\Ui\DataGrid;
use Illuminate\Support\Facades\Event;
use Webkul\Ui\DataGrid\Traits\ProvideBouncer;
use Webkul\Ui\DataGrid\Traits\ProvideCollection;
abstract class DataGrid
{
use ProvideBouncer, ProvideCollection;
/**
* Set index columns, ex: id.
*
@ -54,9 +58,9 @@ abstract class DataGrid
* Hold query builder instance of the query prepared by executing datagrid
* class method `setQueryBuilder`.
*
* @var array
* @var object
*/
protected $queryBuilder = [];
protected $queryBuilder;
/**
* Final result of the datagrid program that is collection object.
@ -186,10 +190,6 @@ abstract class DataGrid
*/
protected $currentUser;
abstract public function prepareQueryBuilder();
abstract public function addColumns();
/**
* Create datagrid instance.
*
@ -203,48 +203,20 @@ abstract class DataGrid
}
/**
* Parse the URL and get it ready to be used.
*
* @return void
* Abstract method.
*/
private function parseUrl()
{
$parsedUrl = [];
$unparsed = url()->full();
abstract public function prepareQueryBuilder();
$route = request()->route() ? request()->route()->getName() : '';
if ($route == 'admin.datagrid.export') {
$unparsed = url()->previous();
}
$getParametersArr = explode('?', $unparsed);
if (count($getParametersArr) > 1) {
$to_be_parsed = $getParametersArr[1];
$to_be_parsed = urldecode($to_be_parsed);
parse_str($to_be_parsed, $parsedUrl);
unset($parsedUrl['page']);
}
if (isset($parsedUrl['grand_total'])) {
foreach ($parsedUrl['grand_total'] as $key => $value) {
$parsedUrl['grand_total'][$key] = str_replace(',', '.', $parsedUrl['grand_total'][$key]);
}
}
$this->itemsPerPage = isset($parsedUrl['perPage']) ? $parsedUrl['perPage']['eq'] : $this->itemsPerPage;
unset($parsedUrl['perPage']);
return $parsedUrl;
}
/**
* Abstract method.
*/
abstract public function addColumns();
/**
* Add the index as alias of the column and use the column to make things happen.
*
* @param string $alias
* @param string $column
* @param string $alias
* @param string $column
*
* @return void
*/
@ -258,7 +230,7 @@ abstract class DataGrid
/**
* Add column.
*
* @param string $column
* @param string $column
*
* @return void
*/
@ -276,7 +248,7 @@ abstract class DataGrid
/**
* Set complete column details.
*
* @param string $column
* @param string $column
*
* @return void
*/
@ -288,7 +260,7 @@ abstract class DataGrid
/**
* Set query builder.
*
* @param \Illuminate\Database\Query\Builder $queryBuilder
* @param \Illuminate\Database\Query\Builder $queryBuilder
*
* @return void
*/
@ -302,32 +274,20 @@ abstract class DataGrid
* parameters is their. If needs to give an access just pass true
* in second param.
*
* @param array $action
*
* @param bool $specialPermission
*
* @param array $action
* @param bool $specialPermission
* @return void
*/
public function addAction($action, $specialPermission = false)
{
$currentRouteACL = $this->fetchCurrentRouteACL($action);
if (isset($action['title'])) {
$eventName = strtolower($action['title']);
$eventName = explode(' ', $eventName);
$eventName = implode('.', $eventName);
} else {
$eventName = null;
}
if (bouncer()->hasPermission($currentRouteACL['key'] ?? null) || $specialPermission) {
$this->checkPermissions($action, $specialPermission, function ($action, $eventName) {
$this->fireEvent('action.before.' . $eventName);
array_push($this->actions, $action);
$this->actions[] = $action;
$this->enableAction = true;
$this->fireEvent('action.after.' . $eventName);
}
});
}
/**
@ -335,392 +295,22 @@ abstract class DataGrid
* parameters is their. If needs to give an access just pass true
* in second param.
*
* @param array $massAction
*
* @param bool $specialPermission
*
* @param array $massAction
* @param bool $specialPermission
* @return void
*/
public function addMassAction($massAction, $specialPermission = false)
{
$massAction['route'] = $this->getRouteNameFromUrl($massAction['action'], $massAction['method']);
$currentRouteACL = $this->fetchCurrentRouteACL($massAction);
if (isset($massAction['label'])) {
$eventName = strtolower($massAction['label']);
$eventName = explode(' ', $eventName);
$eventName = implode('.', $eventName);
} else {
$eventName = null;
}
if (bouncer()->hasPermission($currentRouteACL['key'] ?? null) || $specialPermission) {
$this->checkPermissions($massAction, $specialPermission, function ($action, $eventName) {
$this->fireEvent('mass.action.before.' . $eventName);
$this->massActions[] = $massAction;
$this->massActions[] = $action;
$this->enableMassAction = true;
$this->fireEvent('mass.action.after.' . $eventName);
}
}
/**
* Get collections.
*
* @return \Illuminate\Support\Collection
*/
public function getCollection()
{
$parsedUrl = $this->parseUrl();
foreach ($parsedUrl as $key => $value) {
if ($key === 'locale') {
if (! is_array($value)) {
unset($parsedUrl[$key]);
}
} elseif (! is_array($value)) {
unset($parsedUrl[$key]);
}
}
if (count($parsedUrl)) {
$filteredOrSortedCollection = $this->sortOrFilterCollection($this->collection = $this->queryBuilder,
$parsedUrl);
if ($this->paginate) {
if ($this->itemsPerPage > 0) {
return $filteredOrSortedCollection->orderBy($this->index,
$this->sortOrder)->paginate($this->itemsPerPage)->appends(request()->except('page'));
}
} else {
return $filteredOrSortedCollection->orderBy($this->index, $this->sortOrder)->get();
}
}
if ($this->paginate) {
if ($this->itemsPerPage > 0) {
$this->collection = $this->queryBuilder->orderBy($this->index,
$this->sortOrder)->paginate($this->itemsPerPage)->appends(request()->except('page'));
}
} else {
$this->collection = $this->queryBuilder->orderBy($this->index, $this->sortOrder)->get();
}
return $this->collection;
}
/**
* To find the alias of the column and by taking the column name.
*
* @param array $columnAlias
*
* @return array
*/
public function findColumnType($columnAlias)
{
foreach ($this->completeColumnDetails as $column) {
if ($column['index'] == $columnAlias) {
return [$column['type'], $column['index']];
}
}
}
/**
* Sort or filter collection.
*
* @param \Illuminate\Support\Collection $collection
* @param array $parseInfo
*
* @return \Illuminate\Support\Collection
*/
public function sortOrFilterCollection($collection, $parseInfo)
{
foreach ($parseInfo as $key => $info) {
$columnType = $this->findColumnType($key)[0] ?? null;
$columnName = $this->findColumnType($key)[1] ?? null;
if ($key === 'sort') {
$count_keys = count(array_keys($info));
if ($count_keys > 1) {
throw new \Exception('Fatal Error! Multiple Sort keys Found, Please Resolve the URL Manually');
}
$columnName = $this->findColumnType(array_keys($info)[0]);
$collection->orderBy(
$columnName[1],
array_values($info)[0]
);
} elseif ($key === 'search') {
$count_keys = count(array_keys($info));
if ($count_keys > 1) {
throw new \Exception('Multiple Search keys Found, Please Resolve the URL Manually');
}
if ($count_keys == 1) {
$collection->where(function ($collection) use ($info) {
foreach ($this->completeColumnDetails as $column) {
if ($column['searchable'] == true) {
if ($this->enableFilterMap && isset($this->filterMap[$column['index']])) {
$collection->orWhere($this->filterMap[$column['index']], 'like',
'%' . $info['all'] . '%');
} elseif ($this->enableFilterMap && ! isset($this->filterMap[$column['index']])) {
$collection->orWhere($column['index'], 'like', '%' . $info['all'] . '%');
} else {
$collection->orWhere($column['index'], 'like', '%' . $info['all'] . '%');
}
}
}
});
}
} else {
foreach ($this->completeColumnDetails as $column) {
if ($column['index'] === $columnName && ! $column['filterable']) {
return $collection;
}
}
if (array_keys($info)[0] === 'like' || array_keys($info)[0] === 'nlike') {
foreach ($info as $condition => $filter_value) {
if ($this->enableFilterMap && isset($this->filterMap[$columnName])) {
$collection->where(
$this->filterMap[$columnName],
$this->operators[$condition],
'%' . $filter_value . '%'
);
} elseif ($this->enableFilterMap && ! isset($this->filterMap[$columnName])) {
$collection->where(
$columnName,
$this->operators[$condition],
'%' . $filter_value . '%'
);
} else {
$collection->where(
$columnName,
$this->operators[$condition],
'%' . $filter_value . '%'
);
}
}
} else {
foreach ($info as $condition => $filter_value) {
if ($condition === 'undefined') {
$condition = '=';
}
if ($columnType === 'datetime') {
if ($this->enableFilterMap && isset($this->filterMap[$columnName])) {
$collection->whereDate(
$this->filterMap[$columnName],
$this->operators[$condition],
$filter_value
);
} elseif ($this->enableFilterMap && ! isset($this->filterMap[$columnName])) {
$collection->whereDate(
$columnName,
$this->operators[$condition],
$filter_value
);
} else {
$collection->whereDate(
$columnName,
$this->operators[$condition],
$filter_value
);
}
} elseif ($columnType === 'boolean') {
if ($this->enableFilterMap && isset($this->filterMap[$columnName])) {
if ($this->operators[$condition] == '=') {
if ($filter_value == 1) {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$this->filterMap[$columnName],
$this->operators[$condition],
$filter_value
)->orWhereNotNull($this->filterMap[$columnName]);
});
} else {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$this->filterMap[$columnName],
$this->operators[$condition],
$filter_value
)->orWhereNull($this->filterMap[$columnName]);
});
}
} elseif ($this->operators[$condition] == '<>') {
if ($filter_value == 1) {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$this->filterMap[$columnName],
$this->operators[$condition],
$filter_value
)->orWhereNull($this->filterMap[$columnName]);
});
} else {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$this->filterMap[$columnName],
$this->operators[$condition],
$filter_value
)->orWhereNotNull($this->filterMap[$columnName]);
});
}
} else {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$this->filterMap[$columnName],
$this->operators[$condition],
$filter_value
);
});
}
} elseif ($this->enableFilterMap && ! isset($this->filterMap[$columnName])) {
if ($this->operators[$condition] == '=') {
if ($filter_value == 1) {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$columnName,
$this->operators[$condition],
$filter_value
)->orWhereNotNull($this->filterMap[$columnName]);
});
} else {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$columnName,
$this->operators[$condition],
$filter_value
)->orWhereNull($this->filterMap[$columnName]);
});
}
} elseif ($this->operators[$condition] == '<>') {
if ($filter_value == 1) {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$columnName,
$this->operators[$condition],
$filter_value
)->orWhereNull($this->filterMap[$columnName]);
});
} else {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$columnName,
$this->operators[$condition],
$filter_value
)->orWhereNotNull($this->filterMap[$columnName]);
});
}
} else {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$columnName,
$this->operators[$condition],
$filter_value
);
});
}
} else {
if ($this->operators[$condition] == '=') {
if ($filter_value == 1) {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$columnName,
$this->operators[$condition],
$filter_value
)->orWhereNotNull($this->filterMap[$columnName]);
});
} else {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$columnName,
$this->operators[$condition],
$filter_value
)->orWhereNull($this->filterMap[$columnName]);
});
}
} elseif ($this->operators[$condition] == '<>') {
if ($filter_value == 1) {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$columnName,
$this->operators[$condition],
$filter_value
)->orWhereNull($this->filterMap[$columnName]);
});
} else {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$columnName,
$this->operators[$condition],
$filter_value
)->orWhereNotNull($this->filterMap[$columnName]);
});
}
} else {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
$query->where(
$columnName,
$this->operators[$condition],
$filter_value
);
});
}
}
} else {
if ($this->enableFilterMap && isset($this->filterMap[$columnName])) {
$collection->where(
$this->filterMap[$columnName],
$this->operators[$condition],
$filter_value
);
} elseif ($this->enableFilterMap && ! isset($this->filterMap[$columnName])) {
$collection->where(
$columnName,
$this->operators[$condition],
$filter_value
);
} else {
$collection->where(
$columnName,
$this->operators[$condition],
$filter_value
);
}
}
}
}
}
}
return $collection;
}
/**
* Trigger event.
*
* @param string $name
*
* @return void
*/
protected function fireEvent($name)
{
if (isset($name)) {
$className = get_class($this->invoker);
$className = last(explode('\\', $className));
$className = strtolower($className);
$eventName = $className . '.' . $name;
Event::dispatch($eventName, $this->invoker);
}
}, 'label');
}
/**
@ -756,30 +346,7 @@ abstract class DataGrid
$this->prepareQueryBuilder();
$necessaryExtraFilters = [];
if (in_array('channels', $this->extraFilters)) {
$necessaryExtraFilters['channels'] = core()->getAllChannels();
}
if (in_array('locales', $this->extraFilters)) {
$necessaryExtraFilters['locales'] = core()->getAllLocales();
}
if (in_array('customer_groups', $this->extraFilters)) {
$necessaryExtraFilters['customer_groups'] = core()->getAllCustomerGroups();
}
return view('ui::datagrid.table')->with('results', [
'records' => $this->getCollection(),
'columns' => $this->completeColumnDetails,
'actions' => $this->actions,
'massactions' => $this->massActions,
'index' => $this->index,
'enableMassActions' => $this->enableMassAction,
'enableActions' => $this->enableAction,
'paginated' => $this->paginate,
'itemsPerPage' => $this->itemsPerPage,
'norecords' => __('ui::app.datagrid.no-records'),
'extraFilters' => $necessaryExtraFilters
]);
return view('ui::datagrid.table')->with('results', $this->prepareViewData());
}
/**
@ -803,30 +370,69 @@ abstract class DataGrid
}
/**
* Fetch current route acl. As no access to acl key, this will fetch acl by route name.
*
* @param $action
* Prepare view data.
*
* @return array
*/
private function fetchCurrentRouteACL($action)
public function prepareViewData()
{
return collect(config('acl'))->filter(function ($acl) use ($action) {
return $acl['route'] === $action['route'];
})->first();
return [
'index' => $this->index,
'records' => $this->getCollection(),
'columns' => $this->completeColumnDetails,
'actions' => $this->actions,
'enableActions' => $this->enableAction,
'massactions' => $this->massActions,
'enableMassActions' => $this->enableMassAction,
'paginated' => $this->paginate,
'itemsPerPage' => $this->itemsPerPage,
'norecords' => __('ui::app.datagrid.no-records'),
'extraFilters' => $this->getNecessaryExtraFilters()
];
}
/**
* Fetch route name from full url, not the current one.
* Trigger event.
*
* @param $action
* @param string $name
* @return void
*/
protected function fireEvent($name)
{
if (isset($name)) {
$className = get_class($this->invoker);
$className = last(explode('\\', $className));
$className = strtolower($className);
$eventName = $className . '.' . $name;
Event::dispatch($eventName, $this->invoker);
}
}
/**
* Get necessary extra details.
*
* @return array
*/
private function getRouteNameFromUrl($action, $method)
protected function getNecessaryExtraFilters()
{
return app('router')->getRoutes()
->match(app('request')->create(str_replace(url('/'), '', $action), $method))
->getName();
$necessaryExtraFilters = [];
$checks = [
'channels' => core()->getAllChannels(),
'locales' => core()->getAllLocales(),
'customer_groups' => core()->getAllCustomerGroups()
];
foreach ($checks as $key => $val) {
if (in_array($key, $this->extraFilters)) {
$necessaryExtraFilters[$key] = $val;
}
}
return $necessaryExtraFilters;
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace Webkul\Ui\DataGrid\Traits;
trait ProvideBouncer
{
use ProvideRouteResolver;
/**
* Check permissions.
*
* @param array $action
* @param bool $specialPermission
* @param \Closure $operation
* @return void
*/
private function checkPermissions($action, $specialPermission, $operation, $nameKey = 'title')
{
$currentRouteACL = $this->fetchCurrentRouteACL($action);
$eventName = isset($action[$nameKey]) ? $this->generateEventName($action[$nameKey]) : null;
if (bouncer()->hasPermission($currentRouteACL['key'] ?? null) || $specialPermission) {
$operation($action, $eventName);
}
}
/**
* Generate event name.
*
* @param string $titleOrLabel
* @return string
*/
private function generateEventName($titleOrLabel)
{
$eventName = explode(' ', strtolower($titleOrLabel));
return implode('.', $eventName);
}
}

View File

@ -0,0 +1,290 @@
<?php
namespace Webkul\Ui\DataGrid\Traits;
trait ProvideCollection
{
use ProvideQueryResolver, ProvideQueryStringParser;
/**
* Get collections.
*
* @return \Illuminate\Support\Collection
*/
public function getCollection()
{
$queryStrings = $this->getQueryStrings();
if (count($queryStrings)) {
$filteredOrSortedCollection = $this->sortOrFilterCollection(
$this->queryBuilder,
$queryStrings
);
return $this->collection = $this->generateResults($filteredOrSortedCollection);
}
return $this->collection = $this->generateResults($this->queryBuilder);
}
/**
* Sort or filter collection.
*
* @param \Illuminate\Support\Collection $collection
* @param array $parseInfo
* @return \Illuminate\Support\Collection
*/
public function sortOrFilterCollection($collection, $parseInfo)
{
foreach ($parseInfo as $key => $info) {
$columnType = $this->findColumnType($key)[0] ?? null;
$columnName = $this->findColumnType($key)[1] ?? null;
if ($key === 'sort') {
$this->sortCollection($collection, $info);
} else if ($key === 'search') {
$this->searchCollection($collection, $info);
} else {
if ($this->exceptionCheckInColumns($columnName)) {
return $collection;
}
$this->filterCollection($collection, $info, $columnType, $columnName);
}
}
return $collection;
}
/**
* Finalyze your collection here.
*
* @return void
*/
public function formatCollection()
{
$this->collection->transform(function ($record) {
$this->transformActions($record);
$this->transformColumns($record);
return $record;
});
}
/**
* To find the alias of the column and by taking the column name.
*
* @param array $columnAlias
* @return array
*/
public function findColumnType($columnAlias)
{
foreach ($this->completeColumnDetails as $column) {
if ($column['index'] == $columnAlias) {
return [$column['type'], $column['index']];
}
}
}
/**
* Generate full results.
*
* @param object $queryBuilderOrCollection
* @return \Illuminate\Support\Collection
*/
private function generateResults($queryBuilderOrCollection)
{
if ($this->paginate) {
if ($this->itemsPerPage > 0) {
return $this->paginatedResults($queryBuilderOrCollection);
}
} else {
return $this->defaultResults($queryBuilderOrCollection);
}
}
/**
* Generate paginated results.
*
* @param object $queryBuilderOrCollection
* @return \Illuminate\Support\Collection
*/
private function paginatedResults($queryBuilderOrCollection)
{
return $queryBuilderOrCollection->orderBy(
$this->index,
$this->sortOrder
)->paginate($this->itemsPerPage)->appends(request()->except('page'));
}
/**
* Generate default results.
*
* @param object $queryBuilderOrCollection
* @return \Illuminate\Support\Collection
*/
private function defaultResults($queryBuilderOrCollection)
{
return $queryBuilderOrCollection->orderBy($this->index, $this->sortOrder)->get();
}
/**
* Sort collection.
*
* @param \Illuminate\Support\Collection $collection
* @param array $info
* @return void
*/
private function sortCollection($collection, $info)
{
$countKeys = count(array_keys($info));
if ($countKeys > 1) {
throw new \Exception(__('ui::app.datagrid.error.multiple-sort-keys-error'));
}
$columnName = $this->findColumnType(array_keys($info)[0]);
$collection->orderBy(
$columnName[1],
array_values($info)[0]
);
}
/**
* Search collection.
*
* @param \Illuminate\Support\Collection $collection
* @param array $info
* @return void
*/
private function searchCollection($collection, $info)
{
$countKeys = count(array_keys($info));
if ($countKeys > 1) {
throw new \Exception(__('ui::app.datagrid.error.multiple-search-keys-error'));
}
if ($countKeys == 1) {
$collection->where(function ($collection) use ($info) {
foreach ($this->completeColumnDetails as $column) {
if ($column['searchable'] == true) {
$this->resolve($collection, $column['index'], 'like', '%' . $info['all'] . '%', 'orWhere');
}
}
});
}
}
/**
* Filter collection.
*
* @param \Illuminate\Support\Collection $collection
* @param array $info
* @param string $columnType
* @param string $columnName
* @return void
*/
private function filterCollection($collection, $info, $columnType, $columnName)
{
if (array_keys($info)[0] === 'like' || array_keys($info)[0] === 'nlike') {
foreach ($info as $condition => $filterValue) {
$this->resolve($collection, $columnName, $condition, '%' . $filterValue . '%');
}
} else {
foreach ($info as $condition => $filterValue) {
$condition = ($condition === 'undefined') ? '=' : $condition;
if ($columnType === 'datetime') {
$this->resolve($collection, $columnName, $condition, $filterValue, 'whereDate');
} else if ($columnType === 'boolean') {
$this->resolve($collection, $columnName, $condition, $filterValue, 'where', 'resolveBooleanQuery');
} else {
$this->resolve($collection, $columnName, $condition, $filterValue);
}
}
}
}
/**
* Transform your columns.
*
* @parma object $record
* @return void
*/
private function transformColumns($record)
{
foreach($this->columns as $column) {
if (isset($column['wrapper'])) {
if (isset($column['closure']) && $column['closure'] == true) {
$record->{$column['index']} = $column['wrapper']($record);
} else {
$record->{$column['index']} = htmlspecialchars($column['wrapper']($record));
}
} else {
if ($column['type'] == 'price') {
if (isset($column['currencyCode'])) {
$record->{$column['index']} = htmlspecialchars(core()->formatPrice($record->{$column['index']}, $column['currencyCode']));
} else {
$record->{$column['index']} = htmlspecialchars(core()->formatBasePrice($record->{$column['index']}));
}
}
}
}
}
/**
* Transform your actions.
*
* @parma object $record
* @return void
*/
private function transformActions($record)
{
foreach($this->actions as $action) {
$toDisplay = (isset($action['condition']) && gettype($action['condition']) == 'object') ? $action['condition']($record) : true;
$toDisplayKey = $this->generateKeyFromActionTitle($action['title'], '_to_display');
$record->$toDisplayKey = $toDisplay;
if ($toDisplay) {
$urlKey = $this->generateKeyFromActionTitle($action['title'], '_url');
$record->$urlKey = route($action['route'], $record->{$action['index'] ?? $this->index});
}
}
}
/**
* Some exceptions check in column details.
*
* @param string $columnName
* @return bool
*/
private function exceptionCheckInColumns($columnName)
{
foreach ($this->completeColumnDetails as $column) {
if ($column['index'] === $columnName && ! $column['filterable']) {
return true;
}
}
return false;
}
/**
* Generate unique key from title.
*
* @param string $title
* @param string $suffix
* @return string
*/
private function generateKeyFromActionTitle($title, $suffix)
{
$validatedStrings = preg_replace('/[^A-Za-z0-9]+/', '_', $title);
return strtolower($validatedStrings) . $suffix;
}
}

View File

@ -0,0 +1,151 @@
<?php
namespace Webkul\Ui\DataGrid\Traits;
trait ProvideDataGridPlus
{
/**
* Get json data.
*
* @return object
*/
public function toJson()
{
$this->addColumns();
$this->prepareActions();
$this->prepareMassActions();
$this->prepareQueryBuilder();
$this->getCollection();
$this->formatCollection();
return response()->json($this->prepareData());
}
/**
* Prepare data for json response.
*
* @return array
*/
public function prepareData()
{
return [
'index' => $this->index,
'records' => $this->collection,
'columns' => $this->completeColumnDetails,
'actions' => $this->actions,
'enableActions' => $this->enableAction,
'massActions' => $this->massActions,
'enableMassActions' => $this->enableMassAction,
'paginated' => $this->paginate,
'itemsPerPage' => $this->itemsPerPage,
'extraFilters' => $this->getExtraFilters(),
'translations' => $this->getTranslations(),
];
}
/**
* Get extra filters.
*
* @return array
*/
public function getExtraFilters()
{
$necessaryExtraFilters = [
'current' => $this->getCurrentExtraFilterValue()
];
$checks = [
'channels' => core()->getAllChannels(),
'locales' => $necessaryExtraFilters['current']['locales'],
'customer_groups' => core()->getAllCustomerGroups()
];
foreach ($checks as $key => $val) {
if (in_array($key, $this->extraFilters)) {
$necessaryExtraFilters[$key] = $val;
}
}
return $necessaryExtraFilters;
}
/**
* Get current extra filter values.
*
* @return array
*/
public function getCurrentExtraFilterValue()
{
/* all locales */
$locales = core()->getAllLocales();
/* request and fallback handling */
$locale = request()->get('locale') ?: app()->getLocale();
$channel = request()->get('channel') ?: (core()->getCurrentChannelCode() ?: core()->getDefaultChannelCode());
$customer_group = request()->get('customer_group');
/* handling cases for new locale if not present in current channel */
if ($channel !== 'all') {
$channelLocales = app('Webkul\Core\Repositories\ChannelRepository')->findOneByField('code', $channel)->locales;
if ($channelLocales->contains('code', $locale)) {
$locales = $channelLocales;
} else {
$channel = 'all';
}
}
/* current values */
return [
'locales' => $locales,
'locale' => $locale,
'channel' => $channel,
'customer_group' => $customer_group
];
}
/**
* Get all translations for json response fully controlled by backend.
*
* @return array
*/
public function getTranslations()
{
return [
'allChannels' => __('admin::app.admin.system.all-channels'),
'allLocales' => __('admin::app.admin.system.all-locales'),
'allCustomerGroups' => __('admin::app.admin.system.all-customer-groups'),
'search' => __('ui::app.datagrid.search'),
'itemsPerPage' => __('ui::app.datagrid.items-per-page'),
'filter' => __('ui::app.datagrid.filter'),
'column' => __('ui::app.datagrid.column'),
'condition' => __('ui::app.datagrid.condition'),
'contains' => __('ui::app.datagrid.contains'),
'ncontains' => __('ui::app.datagrid.ncontains'),
'equals' => __('ui::app.datagrid.equals'),
'nequals' => __('ui::app.datagrid.nequals'),
'greater' => __('ui::app.datagrid.greater'),
'less' => __('ui::app.datagrid.less'),
'greatere' => __('ui::app.datagrid.greatere'),
'lesse' => __('ui::app.datagrid.lesse'),
'true' => __('ui::app.datagrid.true'),
'false' => __('ui::app.datagrid.false'),
'value' => __('ui::app.datagrid.value'),
'valueHere' => __('ui::app.datagrid.value-here'),
'numericValueHere' => __('ui::app.datagrid.numeric-value-here'),
'apply' => __('ui::app.datagrid.apply'),
'submit' => __('ui::app.datagrid.submit'),
'actions' => __('ui::app.datagrid.actions'),
'filterFieldsMissing' => __('ui::app.datagrid.filter-fields-missing'),
'zeroIndex' => __('ui::app.datagrid.zero-index'),
'clickOnAction' => __('ui::app.datagrid.click_on_action'),
'norecords' => __('ui::app.datagrid.no-records'),
'massActionDelete' => __('ui::app.datagrid.massaction.delete'),
];
}
}

View File

@ -0,0 +1,107 @@
<?php
namespace Webkul\Ui\DataGrid\Traits;
trait ProvideQueryResolver
{
/**
* Main resolve method.
*
* @param \Illuminate\Support\Collection $collection
* @param string $columnName
* @param string $condition
* @param string $filterValue
* @param string $clause
* @param string $method
* @return void
*/
private function resolve($collection, $columnName, $condition, $filterValue, $clause = 'where', $method = 'resolveQuery')
{
if ($this->enableFilterMap && isset($this->filterMap[$columnName])) {
$this->$method($collection, $this->filterMap[$columnName], $condition, $filterValue, $clause);
} else if ($this->enableFilterMap && ! isset($this->filterMap[$columnName])) {
$this->$method($collection, $columnName, $condition, $filterValue, $clause);
} else {
$this->$method($collection, $columnName, $condition, $filterValue, $clause);
}
}
/**
* Resolve query.
*
* @param object $query
* @param string $columnName
* @param string $condition
* @param string $filterValue
* @param null|boolean $nullCheck
* @return void
*/
private function resolveQuery($query, $columnName, $condition, $filterValue, $clause = 'where')
{
$query->$clause(
$columnName,
$this->operators[$condition],
$filterValue
);
}
/**
* Resolve boolean query.
*
* @param \Illuminate\Support\Collection $collection
* @param string $columnName
* @param string $condition
* @param string $filterValue
* @return void
*/
private function resolveBooleanQuery($collection, $columnName, $condition, $filterValue)
{
if ($this->operators[$condition] == '=') {
$this->checkFilterValueCondition($collection, $columnName, $condition, $filterValue);
} else if ($this->operators[$condition] == '<>') {
$this->checkFilterValueCondition($collection, $columnName, $condition, $filterValue, true);
} else {
$this->resolveFilterQuery($collection, $columnName, $condition, $filterValue);
}
}
/**
* Resolve filter query.
*
* @param \Illuminate\Support\Collection $collection
* @param string $columnName
* @param string $condition
* @param string $filterValue
* @param null|boolean $nullCheck
* @return void
*/
private function resolveFilterQuery($collection, $columnName, $condition, $filterValue, $nullCheck = null)
{
$clause = is_null($nullCheck) ? null : ( $nullCheck ? 'orWhereNull' : 'whereNotNull' );
$collection->where(function ($query) use ($columnName, $condition, $filterValue, $clause) {
$this->resolveQuery($query, $columnName, $condition, $filterValue);
if (! is_null($clause)) {
$query->$clause($columnName);
}
});
}
/**
* Check filter value condition.
*
* @param \Illuminate\Support\Collection $collection
* @param string $columnName
* @param string $condition
* @param string $filterValue
* @param bool $nullCheck
* @return void
*/
private function checkFilterValueCondition($collection, $columnName, $condition, $filterValue, $nullCheck = false)
{
$filterValue == 1
? $this->resolveFilterQuery($collection, $columnName, $condition, $filterValue, $nullCheck)
: $this->resolveFilterQuery($collection, $columnName, $condition, $filterValue, ! $nullCheck);
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace Webkul\Ui\DataGrid\Traits;
trait ProvideQueryStringParser
{
/**
* Parse the query strings and get it ready to be used.
*
* @return array
*/
private function getQueryStrings()
{
$route = request()->route() ? request()->route()->getName() : '';
$queryString = $this->grabQueryStrings($route == 'admin.datagrid.export' ? url()->previous() : url()->full());
$parsedQueryStrings = $this->parseQueryStrings($queryString);
$this->itemsPerPage = isset($parsedQueryStrings['perPage']) ? $parsedQueryStrings['perPage']['eq'] : $this->itemsPerPage;
unset($parsedQueryStrings['perPage']);
return $this->updateQueryStrings($parsedQueryStrings);
}
/**
* Grab query strings from url.
*
* @param string $fullUrl
* @return string
*/
private function grabQueryStrings($fullUrl)
{
return explode('?', $fullUrl)[1] ?? null;
}
/**
* Parse query strings.
*
* @param string $queryString
* @return array
*/
private function parseQueryStrings($queryString)
{
$parsedQueryStrings = [];
if ($queryString) {
parse_str(urldecode($queryString), $parsedQueryStrings);
unset($parsedQueryStrings['page']);
}
return $parsedQueryStrings;
}
/**
* Update query strings.
*
* @param array $parsedQueryStrings
* @return array
*/
private function updateQueryStrings($parsedQueryStrings)
{
if (isset($parsedQueryStrings['grand_total'])) {
foreach ($parsedQueryStrings['grand_total'] as $key => $value) {
$parsedQueryStrings['grand_total'][$key] = str_replace(',', '.', $parsedQueryStrings['grand_total'][$key]);
}
}
foreach ($parsedQueryStrings as $key => $value) {
if (in_array($key, ['locale'])) {
if (! is_array($value)) {
unset($parsedQueryStrings[$key]);
}
} else if (! is_array($value)) {
unset($parsedQueryStrings[$key]);
}
}
return $parsedQueryStrings;
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Webkul\Ui\DataGrid\Traits;
trait ProvideRouteResolver
{
/**
* Fetch current route acl. As no access to acl key, this will fetch acl by route name.
*
* @param $action
* @return array
*/
private function fetchCurrentRouteACL($action)
{
return collect(config('acl'))->filter(function ($acl) use ($action) {
return $acl['route'] === $action['route'];
})->first();
}
/**
* Fetch route name from full url, not the current one.
*
* @param $action
* @return array
*/
private function getRouteNameFromUrl($action, $method)
{
return app('router')->getRoutes()
->match(app('request')->create(str_replace(url('/'), '', $action), $method))
->getName();
}
}

View File

@ -1,17 +0,0 @@
Event::listen('attributedatagrid.before.add.column.id', function($dataGridInstance) {
$data = [
'index' => 'is_required',
'label' => 'trans',
'type' => 'boolean',
'sortable' => true,
'searchable' => false,
'wrapper' => function ($value) {
if ($value->is_required == 1)
return 'True';
else
return 'False';
}
];
$dataGridInstance->addColumn($data);
});

View File

@ -3,8 +3,3 @@
Route::view('/ui-kit', 'ui::partials.ui-kit');
Route::view('/helper-classess', 'ui::partials.helper-classes')->name('ui.helper.classes');
// Route::get('/users', function () {
// $users = \Webkul\User\Models\Admin::paginate(1);
// echo $users->links();
// });

View File

@ -2,8 +2,8 @@
namespace Webkul\Ui\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\ServiceProvider;
class UiServiceProvider extends ServiceProvider
{
@ -25,7 +25,7 @@ class UiServiceProvider extends ServiceProvider
$this->loadViewsFrom(__DIR__ . '/../Resources/views', 'ui');
Paginator::defaultView('ui::partials.pagination');
Paginator::defaultSimpleView('ui::partials.pagination');
}

Binary file not shown.

View File

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

View File

@ -1,9 +1,17 @@
<template>
<div class="accordian" :class="[isActive ? 'active' : '', className, ! isActive && hasError ? 'error' : '']" :id="id">
<div
:class="[
'accordian',
isActive ? 'active' : '',
className,
!isActive && hasError ? 'error' : ''
]"
:id="id"
>
<div class="accordian-header" @click="toggleAccordian()">
<slot name="header">
{{ title }}
<i class="icon" :class="iconClass"></i>
<i :class="['icon', iconClass]"></i>
</slot>
</div>
@ -14,59 +22,69 @@
</template>
<script>
export default {
props: {
title: String,
id: String,
className: String,
active: Boolean
export default {
props: {
title: String,
id: String,
className: String,
active: Boolean,
downIconClass: {
type: String,
default: "accordian-down-icon"
},
upIconClass: {
type: String,
default: "accordian-up-icon"
}
},
inject: ["$validator"],
data: function() {
return {
isActive: false,
imageData: "",
hasError: false
};
},
mounted: function() {
this.addHasErrorClass();
eventBus.$on("onFormError", this.addHasErrorClass);
this.isActive = this.active;
},
methods: {
toggleAccordian: function() {
this.isActive = !this.isActive;
},
inject: ['$validator'],
addHasErrorClass: function() {
let self = this;
data: function() {
return {
isActive: false,
imageData: '',
hasError: false
}
},
mounted: function() {
this.addHasErrorClass()
eventBus.$on('onFormError', this.addHasErrorClass);
this.isActive = this.active;
},
methods: {
toggleAccordian: function() {
this.isActive = ! this.isActive;
},
addHasErrorClass: function() {
var this_this = this;
setTimeout(function() {
$(this_this.$el).find('.control-group').each(function(index, element) {
if ($(element).hasClass('has-error')) {
this_this.hasError = true;
setTimeout(function() {
$(self.$el)
.find(".control-group")
.each(function(index, element) {
if ($(element).hasClass("has-error")) {
self.hasError = true;
}
});
}, 0);
}
},
}, 0);
}
},
computed: {
iconClass() {
return {
'accordian-down-icon': ! this.isActive,
'accordian-up-icon': this.isActive,
};
}
computed: {
iconClass: function() {
return {
[this.downIconClass]: !this.isActive,
[this.upIconClass]: this.isActive
};
}
}
</script>
};
</script>

File diff suppressed because it is too large Load Diff

View File

@ -2,9 +2,9 @@
<span>
<slot>
<input
class="control"
type="text"
:name="name"
class="control"
:value="value"
data-input
/>
@ -28,6 +28,8 @@ export default {
value: String,
disable: Array,
minDate: String,
maxDate: String,
@ -51,8 +53,11 @@ export default {
setOptions: function() {
let self = this;
let options = {
return {
allowInput: true,
disable: this.disable ?? [],
minDate: this.minDate ?? '',
maxDate: this.maxDate ?? '',
altFormat: "Y-m-d",
dateFormat: "Y-m-d",
weekNumbers: true,
@ -60,16 +65,6 @@ export default {
self.$emit("onChange", dateStr);
}
};
if (this.minDate) {
options.minDate = this.minDate;
}
if (this.maxDate) {
options.maxDate = this.maxDate;
}
return options;
},
activate: function(options) {

View File

@ -2,9 +2,9 @@
<span>
<slot>
<input
class="control"
type="text"
:name="name"
class="control"
:value="value"
data-input
/>
@ -28,6 +28,8 @@ export default {
value: String,
disable: Array,
minDate: String,
maxDate: String,
@ -51,8 +53,11 @@ export default {
setOptions: function() {
let self = this;
let options = {
return {
allowInput: true,
disable: this.disable ?? [],
minDate: this.minDate ?? '',
maxDate: this.maxDate ?? '',
altFormat: "Y-m-d H:i:S",
dateFormat: "Y-m-d H:i:S",
enableTime: true,
@ -62,16 +67,6 @@ export default {
self.$emit("onChange", dateStr);
}
};
if (this.minDate) {
options.minDate = this.minDate;
}
if (this.maxDate) {
options.maxDate = this.maxDate;
}
return options;
},
activate: function(options) {

View File

@ -12,6 +12,11 @@ return [
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'error' => [
'multiple-sort-keys-error' => 'Fatal Error! Multiple sort keys found, please resolve the URL manually',
'multiple-search-keys-error' => 'Multiple search keys found, please resolve the URL manually',
],
'zero-index' => 'يمكن أن تحتوي أعمدة الفهرس على قيم أكبر من الصفر فقط',
'no-records' => 'لا توجد سجلات',
'filter-fields-missing' => 'بعض الحقل المطلوب هو لاغ ، رجاء تفقد عمود ، حالة و قيمة صحيح',

View File

@ -12,6 +12,11 @@ return [
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'error' => [
'multiple-sort-keys-error' => 'Fatal Error! Multiple sort keys found, please resolve the URL manually',
'multiple-search-keys-error' => 'Multiple search keys found, please resolve the URL manually',
],
'zero-index' => 'Indexspalten können nur Werte größer als Null haben',
'no-records' => 'Keine Aufzeichnungen gefunden',
'filter-fields-missing' => 'Einige der erforderlichen Felder sind null. Überprüfen Sie Spalte, Zustand und Wert ordnungsgemäß',

View File

@ -12,6 +12,11 @@ return [
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'error' => [
'multiple-sort-keys-error' => 'Fatal Error! Multiple sort keys found, please resolve the URL manually',
'multiple-search-keys-error' => 'Multiple search keys found, please resolve the URL manually',
],
'zero-index' => 'Index columns can have values greater than zero only',
'no-records' => 'No Records Found',
'filter-fields-missing' => 'Some of the required field is null, please check column, condition and value properly',
@ -38,4 +43,4 @@ return [
'numeric-value-here' => 'Numeric Value here',
'submit' => 'Submit'
]
];
];

View File

@ -12,6 +12,11 @@ return [
'delete-category-product' => 'Las categorías seleccionadas contienen productos. Al realizar esta acción, se eliminarán los productos relacionados. ¿De verdad quieres realizar esta acción?'
],
'error' => [
'multiple-sort-keys-error' => 'Fatal Error! Multiple sort keys found, please resolve the URL manually',
'multiple-search-keys-error' => 'Multiple search keys found, please resolve the URL manually',
],
'zero-index' => 'Las columnas de índice solo pueden tener valores superiores a cero',
'no-records' => 'No se encontraron registros',
'filter-fields-missing' => 'Algunos de los campos obligatorios son nulos, verifique la columna, la condición y el valor correctamente',

View File

@ -12,6 +12,11 @@ return [
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'error' => [
'multiple-sort-keys-error' => 'Fatal Error! Multiple sort keys found, please resolve the URL manually',
'multiple-search-keys-error' => 'Multiple search keys found, please resolve the URL manually',
],
'zero-index' => 'ستون های فهرست می توانند مقادیری بیشتر از صفر داشته باشند',
'no-records' => 'هیچ رکوردی یافت نشد',
'filter-fields-missing' => 'برخی از زمینه های مورد نیاز خالی است ، لطفا ستون ، شرایط و ارزش را به درستی بررسی کنید',

View File

@ -12,6 +12,11 @@ return [
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'error' => [
'multiple-sort-keys-error' => 'Fatal Error! Multiple sort keys found, please resolve the URL manually',
'multiple-search-keys-error' => 'Multiple search keys found, please resolve the URL manually',
],
'zero-index' => 'Le colonnne indice possono avere solo valori maggiori di zero',
'no-records' => 'Nessun risultato trovato',
'filter-fields-missing' => 'Alcuni dei campi obbligatori sono nulli, per favore verificare le colonne, le condizioni e i valori inseriti',

View File

@ -12,6 +12,11 @@ return [
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'error' => [
'multiple-sort-keys-error' => 'Fatal Error! Multiple sort keys found, please resolve the URL manually',
'multiple-search-keys-error' => 'Multiple search keys found, please resolve the URL manually',
],
'zero-index' => 'Index columns can have values greater than zero only',
'no-records' => 'Er zijn geen gegevens gevonden',
'filter-fields-missing' => 'Some of the required field is null, please check column, condition and value properly',

View File

@ -12,6 +12,11 @@ return [
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'error' => [
'multiple-sort-keys-error' => 'Fatal Error! Multiple sort keys found, please resolve the URL manually',
'multiple-search-keys-error' => 'Multiple search keys found, please resolve the URL manually',
],
'zero-index' => 'Kolumny indeksu mogą mieć wartości większe niż tylko zero',
'no-records' => 'Nie znaleziono rekordów',
'filter-fields-missing' => 'Niektóre wymagane pola są puste, proszę sprawdzić kolumnę, warunek i wartość poprawnie',

View File

@ -12,6 +12,11 @@ return [
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'error' => [
'multiple-sort-keys-error' => 'Fatal Error! Multiple sort keys found, please resolve the URL manually',
'multiple-search-keys-error' => 'Multiple search keys found, please resolve the URL manually',
],
'zero-index' => 'Colunas do índice podem ter valores maiores que zero apenas',
'no-records' => 'Nenhum registro foi encontrado',
'filter-fields-missing' => 'Alguns dos campos obrigatórios são nulos, por favor verifique coluna, condição e valor corretamente',

View File

@ -12,6 +12,11 @@ return [
'delete-category-product' => 'The selected categories contains products. Performing this action will remove the related products. Do you really want to perform this action?'
],
'error' => [
'multiple-sort-keys-error' => 'Fatal Error! Multiple sort keys found, please resolve the URL manually',
'multiple-search-keys-error' => 'Multiple search keys found, please resolve the URL manually',
],
'zero-index' => 'Index sütunları sadece sıfırdan büyük değere sahip olmalı',
'no-records' => 'Kayıt Bulunamadı',
'filter-fields-missing' => 'Zorunlu alanlardan bazıları boş, lütfen sütun, durum ve değeri doğru şekilde kontrol edin',

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=dc4db81a8e0add484774",
"/js/velocity.js": "/js/velocity.js?id=bb5f5c71bf1268faecd7",
"/css/velocity-admin.css": "/css/velocity-admin.css?id=4322502d80a0e4a0affd",
"/css/velocity.css": "/css/velocity.css?id=2a47eb7473c12402f399"
"/css/velocity.css": "/css/velocity.css?id=26c2ef7e6af354ff4982"
}

View File

@ -476,6 +476,7 @@ header #search-form > *:focus {
.main-category {
padding: 8px 15px;
border-top: 1px solid $border-common;
border-bottom: 5px solid transparent;
}
.content-list {

View File

@ -98,7 +98,7 @@
</template>
</select>
<div class="select-icon-container">
<div class="select-icon-container d-inline-block float-right">
<span class="select-icon rango-arrow-down"></span>
</div>
</div>

View File

@ -10,37 +10,4 @@
@yield('page-detail-wrapper')
</div>
</div>
@endsection
@push('scripts')
<script>
$(document).ready(function() {
window.updateHeight = () => {
setTimeout(() => {
let sidebarHeight = $('.customer-sidebar').css('height');
let contentHeight = $('.account-layout').css('height');
sidebarHeight = parseInt(sidebarHeight.substring(0, sidebarHeight.length - 2));
contentHeight = parseInt(contentHeight.substring(0, contentHeight.length - 2));
let height = sidebarHeight > contentHeight ? sidebarHeight : contentHeight;
height = (height + 30)+ "px";
$('.account-content').css('height', height);
}, 0);
}
window.updateHeight();
$('input, select').change(() => {
window.updateHeight();
});
$('button').click(() => {
window.updateHeight();
});
$('.accordian-header').click(window.updateHeight);
});
</script>
@endpush
@endsection

View File

@ -15,9 +15,6 @@ class OrderCest
{
public function testIndex(FunctionalTester $I): void
{
/* simple order no further association like address, shipping method, payment method, etc. */
$order = $I->have(Order::class);
/* login as admin */
$I->loginAsAdmin();
@ -29,8 +26,6 @@ class OrderCest
/* now test index page */
$I->seeCurrentRouteIs('admin.sales.orders.index');
$I->see($order->id, '//script[@type="text/x-template"]');
$I->see($order->sub_total, '//script[@type="text/x-template"]');
}
public function testCancelCashOnDeliveryOrder(FunctionalTester $I): void