fixed conflict

This commit is contained in:
prateek srivastava 2021-02-04 16:31:22 +05:30
commit d29b0a69a5
175 changed files with 2424 additions and 2533 deletions

5
.gitignore vendored
View File

@ -18,10 +18,7 @@ package-lock.json
/public/storage
/public/themes
/public/vendor
/resources/themes/velocity/*
/resources/lang/vendor/admin/*
/resources/lang/vendor/shop/*
/resources/lang/vendor/velocity/*
/resources/lang/vendor
/storage/*.key
/storage/dcc-data/
/vendor

View File

@ -63,11 +63,9 @@ Take advantage of two of the hottest frameworks used in this project -- Laravel
### Requirements
* **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.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.
* **Node**: 8.11.3 LTS or higher.
@ -84,13 +82,7 @@ Take advantage of two of the hottest frameworks used in this project -- Laravel
##### b. Extract the contents of zip and execute the project in your browser:
~~~
http(s)://localhost/bagisto/public
~~~
or
~~~
http(s)://example.com/public
http(s)://example.com
~~~
**2. Or you can install Bagisto from your console.**
@ -98,7 +90,7 @@ http(s)://example.com/public
##### Execute these commands below, in order
~~~
1. composer create-project bagisto/bagisto-standard
1. composer create-project bagisto/bagisto
~~~
~~~

View File

@ -1,13 +1,12 @@
{
"name": "bagisto/bagisto",
"description": "Bagisto Laravel ECommerce",
"description": "Bagisto Laravel E-Commerce",
"keywords": [
"framework",
"laravel"
],
"license": "MIT",
"type": "project",
"require": {
"php": "^7.2.5",
"ext-curl": "*",
@ -33,18 +32,18 @@
"intervention/image": "^2.4",
"intervention/imagecache": "^2.3",
"kalnoy/nestedset": "5.0.1",
"khaled.alshamaa/ar-php": "^5.5.2",
"konekt/concord": "^1.2",
"laravel/framework": "^7.0",
"laravel/scout": "^8.0",
"laravel/socialite": "^4.4",
"laravel/tinker": "^2.0",
"laravel/ui": "^2.0",
"maatwebsite/excel": "3.1.19",
"maatwebsite/excel": "^3.1.26",
"paypal/paypal-checkout-sdk": "1.0.1",
"prettus/l5-repository": "^2.6",
"tymon/jwt-auth": "^1.0.0"
},
"require-dev": {
"codeception/codeception": "4.1.1",
"codeception/module-asserts": "^1.1",
@ -56,7 +55,6 @@
"nunomaduro/collision": "^4.1",
"phpunit/phpunit": "^8.5"
},
"replace": {
"bagisto/laravel-user": "v0.1.0",
"bagisto/laravel-admin": "v0.1.0",
@ -78,7 +76,6 @@
"bagisto/laravel-paypal": "v0.1.0",
"bagisto/laravel-discount": "v0.1.0"
},
"autoload": {
"classmap": [
"database/seeds",
@ -115,7 +112,6 @@
"Webkul\\Marketing\\": "packages/Webkul/Marketing/src"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\Acceptance\\": "tests/acceptance/",
@ -124,7 +120,6 @@
"Tests\\Trigger\\": "tests/trigger/"
}
},
"extra": {
"laravel": {
"dont-discover": [
@ -132,22 +127,18 @@
]
}
},
"scripts": {
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"@php artisan key:generate",
"Webkul\\Core\\Events\\ComposerEvents::postCreateProject"
],
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover"
],
"test": [
"set -e",
"@php artisan migrate:fresh --env=testing",
@ -155,7 +146,7 @@
"vendor/bin/codecept run functional",
"vendor/bin/codecept run trigger"
],
"test-win": [
"test-win": [
"@set -e",
"@php artisan migrate:fresh --env=testing",
"vendor\\bin\\codecept.bat run unit",
@ -170,4 +161,4 @@
},
"minimum-stability": "dev",
"prefer-stable": true
}
}

813
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -34,10 +34,12 @@ return [
*/
'storage' => [
'enabled' => true,
'driver' => 'file', // redis, file, pdo, custom
'driver' => 'file', // redis, file, pdo, socket, custom
'path' => storage_path('debugbar'), // For file driver
'connection' => null, // Leave null for default connection (Redis/PDO)
'provider' => '', // Instance of StorageInterface for custom driver
'hostname' => '127.0.0.1', // Hostname to use with the "socket" driver
'port' => 2304, // Port to use with the "socket" driver
],
/*

View File

@ -3,7 +3,6 @@
use Maatwebsite\Excel\Excel;
return [
'exports' => [
/*
@ -24,6 +23,16 @@ return [
*/
'pre_calculate_formulas' => false,
/*
|--------------------------------------------------------------------------
| Enable strict null comparison
|--------------------------------------------------------------------------
|
| When enabling strict null comparison empty cells ('') will
| be added to the sheet.
*/
'strict_null_comparison' => false,
/*
|--------------------------------------------------------------------------
| CSV Settings
@ -40,23 +49,66 @@ return [
'include_separator_line' => false,
'excel_compatibility' => false,
],
/*
|--------------------------------------------------------------------------
| Worksheet properties
|--------------------------------------------------------------------------
|
| Configure e.g. default title, creator, subject,...
|
*/
'properties' => [
'creator' => '',
'lastModifiedBy' => '',
'title' => '',
'description' => '',
'subject' => '',
'keywords' => '',
'category' => '',
'manager' => '',
'company' => '',
],
],
'imports' => [
/*
|--------------------------------------------------------------------------
| Read Only
|--------------------------------------------------------------------------
|
| When dealing with imports, you might only be interested in the
| data that the sheet exists. By default we ignore all styles,
| however if you want to do some logic based on style data
| you can enable it by setting read_only to false.
|
*/
'read_only' => true,
'heading_row' => [
/*
|--------------------------------------------------------------------------
| Ignore Empty
|--------------------------------------------------------------------------
|
| When dealing with imports, you might be interested in ignoring
| rows that have null values or empty strings. By default rows
| containing empty strings or empty values are not ignored but can be
| ignored by enabling the setting ignore_empty to true.
|
*/
'ignore_empty' => false,
/*
|--------------------------------------------------------------------------
| Heading Row Formatter
|--------------------------------------------------------------------------
|
| Configure the heading row formatter.
| Available options: none|slug|custom
|
*/
/*
|--------------------------------------------------------------------------
| Heading Row Formatter
|--------------------------------------------------------------------------
|
| Configure the heading row formatter.
| Available options: none|slug|custom
|
*/
'heading_row' => [
'formatter' => 'slug',
],
@ -69,12 +121,33 @@ return [
|
*/
'csv' => [
'delimiter' => ',',
'enclosure' => '"',
'escape_character' => '\\',
'contiguous' => false,
'input_encoding' => 'UTF-8',
'delimiter' => ',',
'enclosure' => '"',
'escape_character' => '\\',
'contiguous' => false,
'input_encoding' => 'UTF-8',
],
/*
|--------------------------------------------------------------------------
| Worksheet properties
|--------------------------------------------------------------------------
|
| Configure e.g. default title, creator, subject,...
|
*/
'properties' => [
'creator' => '',
'lastModifiedBy' => '',
'title' => '',
'description' => '',
'subject' => '',
'keywords' => '',
'category' => '',
'manager' => '',
'company' => '',
],
],
/*
@ -82,9 +155,8 @@ return [
| Extension detector
|--------------------------------------------------------------------------
|
| Configure here which writer type should be used when
| the package needs to guess the correct type
| based on the extension alone.
| Configure here which writer/reader type should be used when the package
| needs to guess the correct type based on the extension alone.
|
*/
'extension_detector' => [
@ -116,39 +188,93 @@ return [
'pdf' => Excel::DOMPDF,
],
/*
|--------------------------------------------------------------------------
| Value Binder
|--------------------------------------------------------------------------
|
| PhpSpreadsheet offers a way to hook into the process of a value being
| written to a cell. In there some assumptions are made on how the
| value should be formatted. If you want to change those defaults,
| you can implement your own default value binder.
|
| Possible value binders:
|
| [x] Maatwebsite\Excel\DefaultValueBinder::class
| [x] PhpOffice\PhpSpreadsheet\Cell\StringValueBinder::class
| [x] PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder::class
|
*/
'value_binder' => [
/*
|--------------------------------------------------------------------------
| Default Value Binder
|--------------------------------------------------------------------------
|
| PhpSpreadsheet offers a way to hook into the process of a value being
| written to a cell. In there some assumptions are made on how the
| value should be formatted. If you want to change those defaults,
| you can implement your own default value binder.
|
*/
'default' => Maatwebsite\Excel\DefaultValueBinder::class,
],
'transactions' => [
'cache' => [
/*
|--------------------------------------------------------------------------
| Default cell caching driver
|--------------------------------------------------------------------------
|
| By default PhpSpreadsheet keeps all cell values in memory, however when
| dealing with large files, this might result into memory issues. If you
| want to mitigate that, you can configure a cell caching driver here.
| When using the illuminate driver, it will store each value in a the
| cache store. This can slow down the process, because it needs to
| store each value. You can use the "batch" store if you want to
| only persist to the store when the memory limit is reached.
|
| Drivers: memory|illuminate|batch
|
*/
'driver' => 'memory',
/*
|--------------------------------------------------------------------------
| Transaction Handler
| Batch memory caching
|--------------------------------------------------------------------------
|
| By default the import is wrapped in a transaction. This is useful
| for when an import may fail and you want to retry it. With the
| transactions, the previous import gets rolled-back.
|
| You can disable the transaction handler by setting this to null.
| Or you can choose a custom made transaction handler here.
|
| Supported handlers: null|db
| When dealing with the "batch" caching driver, it will only
| persist to the store when the memory limit is reached.
| Here you can tweak the memory limit to your liking.
|
*/
'batch' => [
'memory_limit' => 60000,
],
/*
|--------------------------------------------------------------------------
| Illuminate cache
|--------------------------------------------------------------------------
|
| When using the "illuminate" caching driver, it will automatically use
| your default cache store. However if you prefer to have the cell
| cache on a separate store, you can configure the store name here.
| You can use any store defined in your cache config. When leaving
| at "null" it will use the default store.
|
*/
'illuminate' => [
'store' => null,
],
],
/*
|--------------------------------------------------------------------------
| Transaction Handler
|--------------------------------------------------------------------------
|
| By default the import is wrapped in a transaction. This is useful
| for when an import may fail and you want to retry it. With the
| transactions, the previous import gets rolled-back.
|
| You can disable the transaction handler by setting this to null.
| Or you can choose a custom made transaction handler here.
|
| Supported handlers: null|db
|
*/
'transactions' => [
'handler' => 'db',
],
@ -163,7 +289,7 @@ return [
| storing reading or downloading. Here you can customize that path.
|
*/
'local_path' => sys_get_temp_dir(),
'local_path' => storage_path('framework/laravel-excel'),
/*
|--------------------------------------------------------------------------
@ -179,8 +305,24 @@ return [
| in conjunction with queued imports and exports.
|
*/
'remote_disk' => null,
'remote_prefix' => null,
'remote_disk' => null,
'remote_prefix' => null,
/*
|--------------------------------------------------------------------------
| Force Resync
|--------------------------------------------------------------------------
|
| When dealing with a multi server setup as above, it's possible
| for the clean up that occurs after entire queue has been run to only
| cleanup the server that the last AfterImportJob runs on. The rest of the server
| would still have the local temporary file stored on it. In this case your
| local storage limits can be exceeded and future imports won't be processed.
| To mitigate this you can set this config value to be true, so that after every
| queued chunk is processed the local temporary file is deleted on the server that
| processed it.
|
*/
'force_resync_remote' => null,
],
];

View File

@ -3,7 +3,6 @@
namespace Webkul\API\Http\Resources\Catalog;
use Illuminate\Http\Resources\Json\JsonResource;
use Webkul\Product\Helpers\ProductType;
class Product extends JsonResource
{
@ -16,7 +15,7 @@ class Product extends JsonResource
{
$this->productReviewHelper = app('Webkul\Product\Helpers\Review');
parent::__construct($resource);
$this->wishlistHelper = app('Webkul\Customer\Helpers\Wishlist');
}
/**
@ -27,52 +26,264 @@ class Product extends JsonResource
*/
public function toArray($request)
{
/* assign product */
$product = $this->product ? $this->product : $this;
$prices = $product->getTypeInstance()->getProductPrices();
/* get type instance */
$productTypeInstance = $product->getTypeInstance();
/* generating resource */
return [
/* product's information */
'id' => $product->id,
'sku' => $product->sku,
'type' => $product->type,
'name' => $this->name,
'url_key' => $this->url_key,
'price' => $product->getTypeInstance()->getMinimalPrice(),
'formated_price' => core()->currency($product->getTypeInstance()->getMinimalPrice()),
'short_description' => $this->short_description,
'description' => $this->description,
'sku' => $this->sku,
'name' => $product->name,
'url_key' => $product->url_key,
'price' => $productTypeInstance->getMinimalPrice(),
'formated_price' => core()->currency($productTypeInstance->getMinimalPrice()),
'short_description' => $product->short_description,
'description' => $product->description,
'images' => ProductImage::collection($product->images),
'base_image' => app('Webkul\Product\ProductImage')->getProductBaseImage($product),
'variants' => Self::collection($this->variants),
'in_stock' => $product->haveSufficientQuantity(1),
$this->mergeWhen($product->getTypeInstance()->isComposite(), [
'super_attributes' => Attribute::collection($product->super_attributes),
]),
'special_price' => $this->when(
$product->getTypeInstance()->haveSpecialPrice(),
$product->getTypeInstance()->getSpecialPrice()
),
'formated_special_price' => $this->when(
$product->getTypeInstance()->haveSpecialPrice(),
core()->currency($product->getTypeInstance()->getSpecialPrice())
),
'regular_price' => $this->when(
$product->getTypeInstance()->haveSpecialPrice(),
data_get($prices, 'regular_price.price')
),
'formated_regular_price' => $this->when(
$product->getTypeInstance()->haveSpecialPrice(),
data_get($prices, 'regular_price.formated_price')
),
'created_at' => $product->created_at,
'updated_at' => $product->updated_at,
/* product's reviews */
'reviews' => [
'total' => $total = $this->productReviewHelper->getTotalReviews($product),
'total_rating' => $total ? $this->productReviewHelper->getTotalRating($product) : 0,
'average_rating' => $total ? $this->productReviewHelper->getAverageRating($product) : 0,
'percentage' => $total ? json_encode($this->productReviewHelper->getPercentageRating($product)) : [],
],
/* product's checks */
'in_stock' => $product->haveSufficientQuantity(1),
'is_saved' => false,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
'is_wishlisted' => $this->wishlistHelper->getWishlistProduct($product),
'is_item_in_cart' => \Cart::hasProduct($product),
'show_quantity_changer' => $this->when(
$product->type !== 'grouped',
$product->getTypeInstance()->showQuantityBox()
),
/* product's extra information */
$this->merge($this->allProductExtraInfo()),
/* special price cases */
$this->merge($this->specialPriceInfo()),
/* super attributes */
$this->mergeWhen($productTypeInstance->isComposite(), [
'super_attributes' => Attribute::collection($product->super_attributes),
]),
];
}
/**
* Get special price information.
*
* @return array
*/
private function specialPriceInfo()
{
$product = $this->product ? $this->product : $this;
$productTypeInstance = $product->getTypeInstance();
return [
'special_price' => $this->when(
$productTypeInstance->haveSpecialPrice(),
$productTypeInstance->getSpecialPrice()
),
'formated_special_price' => $this->when(
$productTypeInstance->haveSpecialPrice(),
core()->currency($productTypeInstance->getSpecialPrice())
),
'regular_price' => $this->when(
$productTypeInstance->haveSpecialPrice(),
data_get($productTypeInstance->getProductPrices(), 'regular_price.price')
),
'formated_regular_price' => $this->when(
$productTypeInstance->haveSpecialPrice(),
data_get($productTypeInstance->getProductPrices(), 'regular_price.formated_price')
),
];
}
/**
* Get all product's extra information.
*
* @return array
*/
private function allProductExtraInfo()
{
$product = $this->product ? $this->product : $this;
$productTypeInstance = $product->getTypeInstance();
return [
/* grouped product */
$this->mergeWhen(
$productTypeInstance instanceof \Webkul\Product\Type\Grouped,
$product->type == 'grouped'
? $this->getGroupedProductInfo($product)
: null
),
/* bundle product */
$this->mergeWhen(
$productTypeInstance instanceof \Webkul\Product\Type\Bundle,
$product->type == 'bundle'
? $this->getBundleProductInfo($product)
: null
),
/* configurable product */
$this->mergeWhen(
$productTypeInstance instanceof \Webkul\Product\Type\Configurable,
$product->type == 'configurable'
? $this->getConfigurableProductInfo($product)
: null
),
/* downloadable product */
$this->mergeWhen(
$productTypeInstance instanceof \Webkul\Product\Type\Downloadable,
$product->type == 'downloadable'
? $this->getDownloadableProductInfo($product)
: null
),
/* booking product */
$this->mergeWhen(
$product->type == 'booking',
$product->type == 'booking'
? $this->getBookingProductInfo($product)
: null
),
];
}
/**
* Get grouped product's extra information.
*
* @param \Webkul\Product\Models\Product
* @return array
*/
private function getGroupedProductInfo($product)
{
return [
'grouped_products' => $product->grouped_products->map(function($groupedProduct) {
$associatedProduct = $groupedProduct->associated_product;
$data = $associatedProduct->toArray();
return array_merge($data, [
'qty' => $groupedProduct->qty,
'isSaleable' => $associatedProduct->getTypeInstance()->isSaleable(),
'formated_price' => $associatedProduct->getTypeInstance()->getPriceHtml(),
'show_quantity_changer' => $associatedProduct->getTypeInstance()->showQuantityBox(),
]);
})
];
}
/**
* Get bundle product's extra information.
*
* @param \Webkul\Product\Models\Product
* @return array
*/
private function getBundleProductInfo($product)
{
return [
'currency_options' => core()->getAccountJsSymbols(),
'bundle_options' => app('Webkul\Product\Helpers\BundleOption')->getBundleConfig($product)
];
}
/**
* Get configurable product's extra information.
*
* @param \Webkul\Product\Models\Product
* @return array
*/
private function getConfigurableProductInfo($product)
{
return [
'variants' => $product->variants
];
}
/**
* Get downloadable product's extra information.
*
* @param \Webkul\Product\Models\Product
* @return array
*/
private function getDownloadableProductInfo($product)
{
return [
'downloadable_links' => $product->downloadable_links->map(function ($downloadableLink) {
$data = $downloadableLink->toArray();
if (isset($data['sample_file'])) {
$data['price'] = core()->currency($downloadableLink->price);
$data['sample_download_url'] = route('shop.downloadable.download_sample', ['type' => 'link', 'id' => $downloadableLink['id']]);
}
return $data;
}),
'downloadable_samples' => $product->downloadable_samples->map(function ($downloadableSample) {
$sample = $downloadableSample->toArray();
$data = $sample;
$data['download_url'] = route('shop.downloadable.download_sample', ['type' => 'sample', 'id' => $sample['id']]);
return $data;
})
];
}
/**
* Get booking product's extra information.
*
* @param \Webkul\Product\Models\Product
* @return array
*/
private function getBookingProductInfo($product)
{
$bookingProduct = app('\Webkul\BookingProduct\Repositories\BookingProductRepository')->findOneByField('product_id', $product->id);
$data['slot_index_route'] = route('booking_product.slots.index', $bookingProduct->id);
if ($bookingProduct->type == 'appointment') {
$bookingSlotHelper = app('\Webkul\BookingProduct\Helpers\AppointmentSlot');
$data['today_slots_html'] = $bookingSlotHelper->getTodaySlotsHtml($bookingProduct);
$data['week_slot_durations'] = $bookingSlotHelper->getWeekSlotDurations($bookingProduct);
$data['appointment_slot'] = $bookingProduct->appointment_slot;
}
if ($bookingProduct->type == 'event') {
$bookingSlotHelper = app('\Webkul\BookingProduct\Helpers\EventTicket');
$data['tickets'] = $bookingSlotHelper->getTickets($bookingProduct);
$data['event_date'] = $bookingSlotHelper->getEventDate($bookingProduct);
}
if ($bookingProduct->type == 'rental') {
$data['renting_type'] = $bookingProduct->rental_slot->renting_type;
}
if ($bookingProduct->type == 'table') {
$bookingSlotHelper = app('\Webkul\BookingProduct\Helpers\TableSlot');
$data['today_slots_html'] = $bookingSlotHelper->getTodaySlotsHtml($bookingProduct);
$data['week_slot_durations'] = $bookingSlotHelper->getWeekSlotDurations($bookingProduct);
$data['table_slot'] = $bookingProduct->table_slot;
}
return $data;
}
}

View File

@ -1,12 +1,31 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Dashboard
|--------------------------------------------------------------------------
|
| All ACLs related to dashboard will be placed here.
|
*/
[
'key' => 'dashboard',
'name' => 'admin::app.acl.dashboard',
'route' => 'admin.dashboard.index',
'sort' => 1,
], [
],
/*
|--------------------------------------------------------------------------
| Sales
|--------------------------------------------------------------------------
|
| All ACLs related to sales will be placed here.
|
*/
[
'key' => 'sales',
'name' => 'admin::app.acl.sales',
'route' => 'admin.sales.orders.index',
@ -16,17 +35,72 @@ return [
'name' => 'admin::app.acl.orders',
'route' => 'admin.sales.orders.index',
'sort' => 1,
], [
'key' => 'sales.orders.view',
'name' => 'admin::app.acl.view',
'route' => 'admin.sales.orders.view',
'sort' => 1,
], [
'key' => 'sales.orders.cancel',
'name' => 'admin::app.acl.cancel',
'route' => 'admin.sales.orders.cancel',
'sort' => 2,
], [
'key' => 'sales.invoices',
'name' => 'admin::app.acl.invoices',
'route' => 'admin.sales.invoices.index',
'sort' => 2,
], [
'key' => 'sales.invoices.view',
'name' => 'admin::app.acl.view',
'route' => 'admin.sales.invoices.view',
'sort' => 1,
], [
'key' => 'sales.invoices.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.sales.invoices.create',
'sort' => 2,
], [
'key' => 'sales.shipments',
'name' => 'admin::app.acl.shipments',
'route' => 'admin.sales.shipments.index',
'sort' => 3,
], [
'key' => 'sales.shipments.view',
'name' => 'admin::app.acl.view',
'route' => 'admin.sales.shipments.view',
'sort' => 1,
], [
'key' => 'sales.shipments.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.sales.shipments.create',
'sort' => 2,
], [
'key' => 'sales.refunds',
'name' => 'admin::app.acl.refunds',
'route' => 'admin.sales.refunds.index',
'sort' => 4,
], [
'key' => 'sales.refunds.view',
'name' => 'admin::app.acl.view',
'route' => 'admin.sales.refunds.view',
'sort' => 1,
], [
'key' => 'sales.refunds.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.sales.refunds.create',
'sort' => 2,
],
/*
|--------------------------------------------------------------------------
| Catalog
|--------------------------------------------------------------------------
|
| All ACLs related to catalog will be placed here.
|
*/
[
'key' => 'catalog',
'name' => 'admin::app.acl.catalog',
'route' => 'admin.catalog.index',
@ -41,16 +115,31 @@ return [
'name' => 'admin::app.acl.create',
'route' => 'admin.catalog.products.create',
'sort' => 1,
], [
'key' => 'catalog.products.copy',
'name' => 'admin::app.acl.copy',
'route' => 'admin.catalog.products.copy',
'sort' => 2,
], [
'key' => 'catalog.products.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.catalog.products.edit',
'sort' => 2,
'sort' => 3,
], [
'key' => 'catalog.products.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.catalog.products.delete',
'sort' => 3,
'sort' => 4,
], [
'key' => 'catalog.products.mass-update',
'name' => 'admin::app.acl.mass-update',
'route' => 'admin.catalog.products.massupdate',
'sort' => 5,
], [
'key' => 'catalog.products.mass-delete',
'name' => 'admin::app.acl.mass-delete',
'route' => 'admin.catalog.products.massdelete',
'sort' => 6,
], [
'key' => 'catalog.categories',
'name' => 'admin::app.acl.categories',
@ -71,6 +160,11 @@ return [
'name' => 'admin::app.acl.delete',
'route' => 'admin.catalog.categories.delete',
'sort' => 3,
], [
'key' => 'catalog.categories.mass-delete',
'name' => 'admin::app.acl.mass-delete',
'route' => 'admin.catalog.categories.massdelete',
'sort' => 4,
], [
'key' => 'catalog.attributes',
'name' => 'admin::app.acl.attributes',
@ -91,6 +185,11 @@ return [
'name' => 'admin::app.acl.delete',
'route' => 'admin.catalog.attributes.delete',
'sort' => 3,
], [
'key' => 'catalog.attributes.mass-delete',
'name' => 'admin::app.acl.mass-delete',
'route' => 'admin.catalog.attributes.massdelete',
'sort' => 4,
], [
'key' => 'catalog.families',
'name' => 'admin::app.acl.attribute-families',
@ -111,7 +210,17 @@ return [
'name' => 'admin::app.acl.delete',
'route' => 'admin.catalog.families.delete',
'sort' => 3,
], [
],
/*
|--------------------------------------------------------------------------
| Customers
|--------------------------------------------------------------------------
|
| All ACLs related to customers will be placed here.
|
*/
[
'key' => 'customers',
'name' => 'admin::app.acl.customers',
'route' => 'admin.customer.index',
@ -136,11 +245,46 @@ return [
'name' => 'admin::app.acl.delete',
'route' => 'admin.customer.delete',
'sort' => 3,
], [
'key' => 'customers.customers.mass-update',
'name' => 'admin::app.acl.mass-update',
'route' => 'admin.customer.mass-update',
'sort' => 4,
], [
'key' => 'customers.customers.mass-delete',
'name' => 'admin::app.acl.mass-delete',
'route' => 'admin.customer.mass-delete',
'sort' => 5,
], [
'key' => 'customers.addresses',
'name' => 'admin::app.acl.addresses',
'route' => 'admin.customer.addresses.index',
'sort' => 2,
], [
'key' => 'customers.addresses.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.customer.addresses.create',
'sort' => 1,
], [
'key' => 'customers.addresses.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.customer.addresses.edit',
'sort' => 2,
], [
'key' => 'customers.addresses.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.customer.addresses.delete',
'sort' => 3,
], [
'key' => 'customers.note',
'name' => 'admin::app.acl.note',
'route' => 'admin.customer.note.create',
'sort' => 3,
], [
'key' => 'customers.groups',
'name' => 'admin::app.acl.groups',
'route' => 'admin.groups.index',
'sort' => 2,
'sort' => 4,
], [
'key' => 'customers.groups.create',
'name' => 'admin::app.acl.create',
@ -160,7 +304,7 @@ return [
'key' => 'customers.reviews',
'name' => 'admin::app.acl.reviews',
'route' => 'admin.customer.review.index',
'sort' => 3,
'sort' => 5,
], [
'key' => 'customers.reviews.edit',
'name' => 'admin::app.acl.edit',
@ -172,15 +316,215 @@ return [
'route' => 'admin.customer.review.delete',
'sort' => 2,
], [
'key' => 'configuration',
'name' => 'admin::app.acl.configure',
'route' => 'admin.configuration.index',
'sort' => 5,
'key' => 'customers.reviews.mass-update',
'name' => 'admin::app.acl.mass-update',
'route' => 'admin.customer.review.massupdate',
'sort' => 3,
], [
'key' => 'customers.reviews.mass-delete',
'name' => 'admin::app.acl.mass-delete',
'route' => 'admin.customer.review.massdelete',
'sort' => 4,
],
/*
|--------------------------------------------------------------------------
| Marketing
|--------------------------------------------------------------------------
|
| All ACLs related to marketing will be placed here.
|
*/
[
'key' => 'marketing',
'name' => 'admin::app.acl.marketing',
'route' => 'admin.cart-rules.index',
'sort' => 6,
], [
'key' => 'marketing.promotions',
'name' => 'admin::app.acl.promotions',
'route' => 'admin.cart-rules.index',
'sort' => 6,
], [
'key' => 'marketing.promotions.cart-rules',
'name' => 'admin::app.acl.cart-rules',
'route' => 'admin.cart-rules.index',
'sort' => 1,
], [
'key' => 'marketing.promotions.cart-rules.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.cart-rules.create',
'sort' => 1,
], [
'key' => 'marketing.promotions.cart-rules.copy',
'name' => 'admin::app.acl.copy',
'route' => 'admin.cart-rules.copy',
'sort' => 1,
], [
'key' => 'marketing.promotions.cart-rules.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.cart-rules.edit',
'sort' => 2,
], [
'key' => 'marketing.promotions.cart-rules.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.cart-rules.delete',
'sort' => 3,
], [
'key' => 'marketing.promotions.catalog-rules',
'name' => 'admin::app.acl.catalog-rules',
'route' => 'admin.catalog-rules.index',
'sort' => 1,
], [
'key' => 'marketing.promotions.catalog-rules.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.catalog-rules.index',
'sort' => 1,
], [
'key' => 'marketing.promotions.catalog-rules.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.catalog-rules.edit',
'sort' => 2,
], [
'key' => 'marketing.promotions.catalog-rules.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.catalog-rules.delete',
'sort' => 3,
], [
'key' => 'marketing.email-marketing',
'name' => 'admin::app.acl.email-marketing',
'route' => 'admin.email-templates.index',
'sort' => 7,
], [
'key' => 'marketing.email-marketing.email-templates',
'name' => 'admin::app.acl.email-templates',
'route' => 'admin.email-templates.index',
'sort' => 1,
], [
'key' => 'marketing.email-marketing.email-templates.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.email-templates.create',
'sort' => 1,
], [
'key' => 'marketing.email-marketing.email-templates.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.email-templates.edit',
'sort' => 2,
], [
'key' => 'marketing.email-marketing.email-templates.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.email-templates.delete',
'sort' => 3,
], [
'key' => 'marketing.email-marketing.events',
'name' => 'admin::app.acl.events',
'route' => 'admin.events.index',
'sort' => 1,
], [
'key' => 'marketing.email-marketing.events.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.events.create',
'sort' => 1,
], [
'key' => 'marketing.email-marketing.events.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.events.edit',
'sort' => 2,
], [
'key' => 'marketing.email-marketing.events.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.events.delete',
'sort' => 3,
], [
'key' => 'marketing.email-marketing.campaigns',
'name' => 'admin::app.acl.campaigns',
'route' => 'admin.campaigns.index',
'sort' => 1,
], [
'key' => 'marketing.email-marketing.campaigns.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.campaigns.create',
'sort' => 1,
], [
'key' => 'marketing.email-marketing.campaigns.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.campaigns.edit',
'sort' => 2,
], [
'key' => 'marketing.email-marketing.campaigns.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.campaigns.delete',
'sort' => 3,
], [
'key' => 'marketing.email-marketing.subscribers',
'name' => 'admin::app.acl.subscribers',
'route' => 'admin.customers.subscribers.index',
'sort' => 1,
], [
'key' => 'marketing.email-marketing.subscribers.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.customers.subscribers.edit',
'sort' => 2,
], [
'key' => 'marketing.email-marketing.subscribers.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.customers.subscribers.delete',
'sort' => 3,
],
/*
|--------------------------------------------------------------------------
| CMS
|--------------------------------------------------------------------------
|
| All ACLs related to cms will be placed here.
|
*/
[
'key' => 'cms',
'name' => 'admin::app.layouts.cms',
'route' => 'admin.cms.index',
'sort' => 7,
], [
'key' => 'cms.pages',
'name' => 'admin::app.cms.pages.pages',
'route' => 'admin.cms.index',
'sort' => 7,
], [
'key' => 'cms.pages.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.cms.create',
'sort' => 1,
], [
'key' => 'cms.pages.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.cms.edit',
'sort' => 2,
], [
'key' => 'cms.pages.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.cms.delete',
'sort' => 3,
], [
'key' => 'cms.pages.mass-delete',
'name' => 'admin::app.acl.mass-delete',
'route' => 'admin.cms.mass-delete',
'sort' => 4,
],
/*
|--------------------------------------------------------------------------
| Settings
|--------------------------------------------------------------------------
|
| All ACLs related to settings will be placed here.
|
*/
[
'key' => 'settings',
'name' => 'admin::app.acl.settings',
'route' => 'admin.users.index',
'sort' => 6,
'sort' => 8,
], [
'key' => 'settings.locales',
'name' => 'admin::app.acl.locales',
@ -391,137 +735,20 @@ return [
'name' => 'admin::app.acl.delete',
'route' => 'admin.tax-rates.delete',
'sort' => 3,
], [
'key' => 'marketing',
'name' => 'admin::app.acl.marketing',
'route' => 'admin.cart-rules.index',
'sort' => 7,
], [
'key' => 'marketing.promotions',
'name' => 'admin::app.acl.promotions',
'route' => 'admin.cart-rules.index',
'sort' => 7,
], [
'key' => 'marketing.promotions.cart-rules',
'name' => 'admin::app.acl.cart-rules',
'route' => 'admin.cart-rules.index',
'sort' => 1,
], [
'key' => 'marketing.promotions.cart-rules.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.cart-rules.create',
'sort' => 1,
], [
'key' => 'marketing.promotions.cart-rules.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.cart-rules.edit',
'sort' => 2,
], [
'key' => 'marketing.promotions.cart-rules.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.cart-rules.delete',
'sort' => 3,
], [
'key' => 'marketing.promotions.catalog-rules',
'name' => 'admin::app.acl.catalog-rules',
'route' => 'admin.catalog-rules.index',
'sort' => 1,
], [
'key' => 'marketing.promotions.catalog-rules.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.catalog-rules.index',
'sort' => 1,
], [
'key' => 'marketing.promotions.catalog-rules.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.catalog-rules.edit',
'sort' => 2,
], [
'key' => 'marketing.promotions.catalog-rules.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.catalog-rules.delete',
'sort' => 3,
], [
'key' => 'marketing.email-marketing',
'name' => 'admin::app.acl.email-marketing',
'route' => 'admin.email-templates.index',
'sort' => 7,
], [
'key' => 'marketing.email-marketing.email-templates',
'name' => 'admin::app.acl.email-templates',
'route' => 'admin.email-templates.index',
'sort' => 1,
], [
'key' => 'marketing.email-marketing.email-templates.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.email-templates.create',
'sort' => 1,
], [
'key' => 'marketing.email-marketing.email-templates.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.email-templates.edit',
'sort' => 2,
], [
'key' => 'marketing.email-marketing.email-templates.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.email-templates.delete',
'sort' => 3,
], [
'key' => 'marketing.email-marketing.events',
'name' => 'admin::app.acl.events',
'route' => 'admin.events.index',
'sort' => 1,
], [
'key' => 'marketing.email-marketing.events.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.events.create',
'sort' => 1,
], [
'key' => 'marketing.email-marketing.events.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.events.edit',
'sort' => 2,
], [
'key' => 'marketing.email-marketing.events.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.events.delete',
'sort' => 3,
], [
'key' => 'marketing.email-marketing.campaigns',
'name' => 'admin::app.acl.campaigns',
'route' => 'admin.campaigns.index',
'sort' => 1,
], [
'key' => 'marketing.email-marketing.campaigns.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.campaigns.create',
'sort' => 1,
], [
'key' => 'marketing.email-marketing.campaigns.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.campaigns.edit',
'sort' => 2,
], [
'key' => 'marketing.email-marketing.campaigns.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.campaigns.delete',
'sort' => 3,
], [
'key' => 'marketing.email-marketing.subscribers',
'name' => 'admin::app.acl.subscribers',
'route' => 'admin.subscribers.index',
'sort' => 1,
], [
'key' => 'marketing.email-marketing.subscribers.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.subscribers.edit',
'sort' => 2,
], [
'key' => 'marketing.email-marketing.subscribers.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.subscribers.delete',
'sort' => 3,
],
/*
|--------------------------------------------------------------------------
| Configuration
|--------------------------------------------------------------------------
|
| All ACLs related to configuration will be placed here.
|
*/
[
'key' => 'configuration',
'name' => 'admin::app.acl.configure',
'route' => 'admin.configuration.index',
'sort' => 9,
]
];
?>

View File

@ -166,6 +166,11 @@ return [
'type' => 'number',
'validation' => 'min:0',
],
[
'name' => 'out_of_stock_items',
'title' => 'admin::app.admin.system.allow-out-of-stock-items',
'type' => 'boolean',
],
],
], [
'key' => 'catalog.products.storefront',

View File

@ -98,7 +98,7 @@ class AddressDataGrid extends DataGrid
'sortable' => true,
'filterable' => true,
]);
$this->addColumn([
'index' => 'city',
'label' => trans('admin::app.customers.addresses.city'),
@ -167,7 +167,7 @@ class AddressDataGrid extends DataGrid
'type' => 'delete',
'label' => trans('admin::app.customers.addresses.delete'),
'action' => route('admin.customer.addresses.massdelete', request('id')),
'method' => 'DELETE',
'method' => 'POST',
]);
}
}

View File

@ -17,6 +17,10 @@ class AttributeDataGrid extends DataGrid
->select('id')
->addSelect('id', 'code', 'admin_name', 'type', 'is_required', 'is_unique', 'value_per_locale', 'value_per_channel');
$this->addFilter('is_unique', 'is_unique');
$this->addFilter('value_per_locale', 'value_per_locale');
$this->addFilter('value_per_channel', 'value_per_channel');
$this->setQueryBuilder($queryBuilder);
}
@ -146,7 +150,7 @@ class AttributeDataGrid extends DataGrid
'action' => route('admin.catalog.attributes.massdelete'),
'label' => trans('admin::app.datagrid.delete'),
'index' => 'admin_name',
'method' => 'DELETE',
'method' => 'POST',
]);
}
}

View File

@ -78,7 +78,7 @@ class CMSPageDataGrid extends DataGrid
'type' => 'delete',
'label' => trans('admin::app.datagrid.delete'),
'action' => route('admin.cms.mass-delete'),
'method' => 'DELETE',
'method' => 'POST',
]);
}
}

View File

@ -12,7 +12,7 @@ class CartRuleCouponDataGrid extends DataGrid
protected $sortOrder = 'desc';
public function prepareQueryBuilder()
{
{
$route = request()->route() ? request()->route()->getName() : "" ;
$cartRuleId = $route == 'admin.cart-rules.edit' ? collect(request()->segments())->last() : last(explode("/", url()->previous()));
@ -20,7 +20,7 @@ class CartRuleCouponDataGrid extends DataGrid
$queryBuilder = DB::table('cart_rule_coupons')
->addSelect('id', 'code', 'created_at', 'expired_at', 'times_used')
->where('cart_rule_coupons.cart_rule_id', $cartRuleId);
$this->setQueryBuilder($queryBuilder);
}
@ -78,7 +78,7 @@ class CartRuleCouponDataGrid extends DataGrid
'type' => 'delete',
'action' => route('admin.cart-rule-coupons.mass-delete'),
'label' => trans('admin::app.datagrid.delete'),
'method' => 'DELETE',
'method' => 'POST',
]);
}
}

View File

@ -62,6 +62,8 @@ class CartRuleDataGrid extends DataGrid
$queryBuilder->where('cart_rule_channels.channel_id', $this->channel);
}
$this->addFilter('status', 'status');
$this->setQueryBuilder($queryBuilder);
}
@ -120,9 +122,9 @@ class CartRuleDataGrid extends DataGrid
'sortable' => true,
'filterable' => true,
'wrapper' => function ($value) {
if ($value->status == 'active') {
if ($value->status == 1) {
return trans('admin::app.datagrid.active');
} else if ($value->status == 'inactive') {
} else if ($value->status == 0) {
return trans('admin::app.datagrid.inactive');
} else {
return trans('admin::app.datagrid.draft');

View File

@ -16,6 +16,9 @@ class CatalogRuleDataGrid extends DataGrid
$queryBuilder = DB::table('catalog_rules')
->addSelect('catalog_rules.id', 'name', 'status', 'starts_from', 'ends_till', 'sort_order');
$this->addFilter('status', 'status');
$this->setQueryBuilder($queryBuilder);
}

View File

@ -24,6 +24,7 @@ class CategoryDataGrid extends DataGrid
->groupBy('cat.id');
$this->addFilter('status', 'cat.status');
$this->addFilter('category_id', 'cat.id');
$this->setQueryBuilder($queryBuilder);
@ -106,7 +107,7 @@ class CategoryDataGrid extends DataGrid
'type' => 'delete',
'label' => trans('admin::app.datagrid.delete'),
'action' => route('admin.catalog.categories.massdelete'),
'method' => 'DELETE',
'method' => 'POST',
]);
}
}

View File

@ -2,8 +2,8 @@
namespace Webkul\Admin\DataGrids;
use Illuminate\Support\Facades\DB;
use Webkul\Ui\DataGrid\DataGrid;
use Illuminate\Support\Facades\DB;
class CustomerDataGrid extends DataGrid
{
@ -17,13 +17,15 @@ class CustomerDataGrid extends DataGrid
{
$queryBuilder = DB::table('customers')
->leftJoin('customer_groups', 'customers.customer_group_id', '=', 'customer_groups.id')
->addSelect('customers.id as customer_id', 'customers.email', 'customer_groups.name', 'customers.phone', 'customers.gender', 'status')
->addSelect('customers.id as customer_id', 'customers.email', 'customer_groups.name as group', 'customers.phone', 'customers.gender', 'status')
->addSelect(DB::raw('CONCAT(' . DB::getTablePrefix() . 'customers.first_name, " ", ' . DB::getTablePrefix() . 'customers.last_name) as full_name'));
$this->addFilter('customer_id', 'customers.id');
$this->addFilter('full_name', DB::raw('CONCAT(' . DB::getTablePrefix() . 'customers.first_name, " ", ' . DB::getTablePrefix() . 'customers.last_name)'));
$this->addFilter('group', 'customer_groups.name');
$this->addFilter('phone', 'customers.phone');
$this->addFilter('gender', 'customers.gender');
$this->addFilter('status', 'status');
$this->setQueryBuilder($queryBuilder);
}
@ -58,7 +60,7 @@ class CustomerDataGrid extends DataGrid
]);
$this->addColumn([
'index' => 'name',
'index' => 'group',
'label' => trans('admin::app.datagrid.group'),
'type' => 'string',
'searchable' => false,
@ -159,14 +161,14 @@ class CustomerDataGrid extends DataGrid
'type' => 'delete',
'label' => trans('admin::app.datagrid.delete'),
'action' => route('admin.customer.mass-delete'),
'method' => 'PUT',
'method' => 'POST',
]);
$this->addMassAction([
'type' => 'update',
'label' => trans('admin::app.datagrid.update-status'),
'action' => route('admin.customer.mass-update'),
'method' => 'PUT',
'method' => 'POST',
'options' => [
'Active' => 1,
'Inactive' => 0,

View File

@ -108,14 +108,14 @@ class CustomerReviewDataGrid extends DataGrid
'type' => 'delete',
'label' => trans('admin::app.datagrid.delete'),
'action' => route('admin.customer.review.massdelete'),
'method' => 'DELETE',
'method' => 'POST',
]);
$this->addMassAction([
'type' => 'update',
'label' => trans('admin::app.datagrid.update-status'),
'action' => route('admin.customer.review.massupdate'),
'method' => 'PUT',
'method' => 'POST',
'options' => [
trans('admin::app.customers.reviews.pending') => 0,
trans('admin::app.customers.reviews.approved') => 1,

View File

@ -15,6 +15,8 @@ class EmailTemplateDataGrid extends DataGrid
{
$queryBuilder = DB::table('marketing_templates')->addSelect('id', 'name', 'status');
$this->addFilter('status', 'status');
$this->setQueryBuilder($queryBuilder);
}

View File

@ -15,6 +15,8 @@ class InventorySourcesDataGrid extends DataGrid
{
$queryBuilder = DB::table('inventory_sources')->addSelect('id', 'code', 'name', 'priority', 'status');
$this->addFilter('status', 'status');
$this->setQueryBuilder($queryBuilder);
}

View File

@ -223,14 +223,14 @@ class ProductDataGrid extends DataGrid
'type' => 'delete',
'label' => trans('admin::app.datagrid.delete'),
'action' => route('admin.catalog.products.massdelete'),
'method' => 'DELETE',
'method' => 'POST',
]);
$this->addMassAction([
'type' => 'update',
'label' => trans('admin::app.datagrid.update-status'),
'action' => route('admin.catalog.products.massupdate'),
'method' => 'PUT',
'method' => 'POST',
'options' => [
'Active' => 1,
'Inactive' => 0,

View File

@ -30,10 +30,17 @@ class SliderDataGrid extends DataGrid
{
parent::__construct();
$this->locale = request()->get('locale') ?? 'all';
$this->channel = request()->get('channel')
? Channel::find(request()->get('channel'))->code
: 'all';
/* locale */
$this->locale = request()->get('locale') ?? app()->getLocale();
/* channel */
$this->channel = request()->get('channel') ?? (core()->getCurrentChannelCode() ?: core()->getDefaultChannelCode());
/* finding channel code */
if ($this->channel !== 'all') {
$this->channel = Channel::query()->find($this->channel);
$this->channel = $this->channel ? $this->channel->code : 'all';
}
}
public function prepareQueryBuilder()

View File

@ -105,7 +105,7 @@ class TaxRateDataGrid extends DataGrid
$this->addAction([
'title' => trans('admin::app.datagrid.edit'),
'method' => 'GET',
'route' => 'admin.tax-rates.store',
'route' => 'admin.tax-rates.edit',
'icon' => 'icon pencil-lg-icon',
]);

View File

@ -20,6 +20,7 @@ class UserDataGrid extends DataGrid
$this->addFilter('user_id', 'u.id');
$this->addFilter('user_name', 'u.name');
$this->addFilter('role_name', 'ro.name');
$this->addFilter('status', 'u.status');
$this->setQueryBuilder($queryBuilder);
}

View File

@ -2,10 +2,10 @@
namespace Webkul\Admin\Http\Controllers\Sales;
use PDF;
use Webkul\Admin\Http\Controllers\Controller;
use Webkul\Sales\Repositories\OrderRepository;
use Webkul\Sales\Repositories\InvoiceRepository;
use PDF;
class InvoiceController extends Controller
{
@ -141,8 +141,30 @@ class InvoiceController extends Controller
{
$invoice = $this->invoiceRepository->findOrFail($id);
$pdf = PDF::loadView('admin::sales.invoices.pdf', compact('invoice'))->setPaper('a4');
$html = view('admin::sales.invoices.pdf', compact('invoice'))->render();
return $pdf->download('invoice-' . $invoice->created_at->format('d-m-Y') . '.pdf');
return PDF::loadHTML($this->adjustArabicAndPersianContent($html))
->setPaper('a4')
->download('invoice-' . $invoice->created_at->format('d-m-Y') . '.pdf');
}
/**
* Adjust arabic and persian content.
*
* @param string $html
* @return string
*/
private function adjustArabicAndPersianContent($html)
{
$arabic = new \ArPHP\I18N\Arabic();
$p = $arabic->arIdentify($html);
for ($i = count($p)-1; $i >= 0; $i -= 2) {
$utf8ar = $arabic->utf8Glyphs(substr($html, $p[$i-1], $p[$i] - $p[$i-1]));
$html = substr_replace($html, $utf8ar, $p[$i-1], $p[$i] - $p[$i-1]);
}
return $html;
}
}

View File

@ -341,7 +341,7 @@ Route::group(['middleware' => ['web', 'admin_locale']], function () {
])->name('admin.catalog.categories.massdelete');
Route::post('/categories/product/count', 'Webkul\Category\Http\Controllers\CategoryController@categoryProductCount')->name('admin.catalog.categories.product.count');
// Catalog Attribute Routes
Route::get('/attributes', 'Webkul\Attribute\Http\Controllers\AttributeController@index')->defaults('_config', [
@ -620,11 +620,11 @@ Route::group(['middleware' => ['web', 'admin_locale']], function () {
// tax category routes
Route::get('/tax-categories/create', 'Webkul\Tax\Http\Controllers\TaxCategoryController@show')->defaults('_config', [
'view' => 'admin::tax.tax-categories.create',
])->name('admin.tax-categories.show');
])->name('admin.tax-categories.create');
Route::post('/tax-categories/create', 'Webkul\Tax\Http\Controllers\TaxCategoryController@create')->defaults('_config', [
'redirect' => 'admin.tax-categories.index',
])->name('admin.tax-categories.create');
])->name('admin.tax-categories.store');
Route::get('/tax-categories/edit/{id}', 'Webkul\Tax\Http\Controllers\TaxCategoryController@edit')->defaults('_config', [
'view' => 'admin::tax.tax-categories.edit',
@ -645,15 +645,15 @@ Route::group(['middleware' => ['web', 'admin_locale']], function () {
Route::get('tax-rates/create', 'Webkul\Tax\Http\Controllers\TaxRateController@show')->defaults('_config', [
'view' => 'admin::tax.tax-rates.create',
])->name('admin.tax-rates.show');
])->name('admin.tax-rates.create');
Route::post('tax-rates/create', 'Webkul\Tax\Http\Controllers\TaxRateController@create')->defaults('_config', [
'redirect' => 'admin.tax-rates.index',
])->name('admin.tax-rates.create');
])->name('admin.tax-rates.store');
Route::get('tax-rates/edit/{id}', 'Webkul\Tax\Http\Controllers\TaxRateController@edit')->defaults('_config', [
'view' => 'admin::tax.tax-rates.edit',
])->name('admin.tax-rates.store');
])->name('admin.tax-rates.edit');
Route::put('tax-rates/update/{id}', 'Webkul\Tax\Http\Controllers\TaxRateController@update')->defaults('_config', [
'redirect' => 'admin.tax-rates.index',

View File

@ -87,15 +87,20 @@ return [
'acl' => [
'dashboard' => 'لوحة التحكم',
'sales' => 'المبيعات',
'cancel' => 'Cancel',
'orders' => 'الطلبات',
'shipments' => 'الشحنات',
'invoices' => 'الفواتير',
'refunds' => 'Refunds',
'catalog' => 'فهرس',
'products' => 'المنتجات',
'copy' => 'Copy',
'categories' => 'الفئات',
'attributes' => 'الصفات',
'attribute-families' => 'وصف الأسر',
'customers' => 'زبائن',
'addresses' => 'Addresses',
'note' => 'Note',
'groups' => 'المجموعات',
'reviews' => 'باء-الاستعراضات',
'newsletter-subscriptions' => 'الاشتراك في الرسالة الإخبارية',
@ -112,9 +117,12 @@ return [
'taxes' => 'الضرائب',
'tax-categories' => 'فئات الضرائب',
'tax-rates' => 'المعدلات الضريبية',
'view' => 'View',
'edit' => 'تعديل',
'create' => 'أضف',
'delete' => 'حذف',
'mass-delete' => 'Mass Delete',
'mass-update' => 'Mass Update',
'marketing' => 'Marketing',
'promotions' => 'الترقيات',
'cart-rules' => 'قواعد سلة التسوق',
@ -1329,6 +1337,10 @@ return [
],
'system' => [
'catalog' => 'فهرس',
'homepage' => 'Homepage configuration',
'allow-no-of-new-product-homepage' => 'Allowed No of New Product in Homepage',
'allow-no-of-featured-product-homepage' => 'Allowed No of Featured Product in Homepage',
'allow-out-of-stock-items' => 'Allow out of stock items',
'products' => 'منتجات',
'guest-checkout' => 'ضيف المحاسبة',
'allow-guest-checkout' => 'السماح للضيف بالخروج',

View File

@ -86,15 +86,20 @@ return [
[
'dashboard' => 'Dashboard',
'sales' => 'Vertrieb',
'cancel' => 'Cancel',
'orders' => 'Bestellungen',
'shipments' => 'Sendungen',
'invoices' => 'Rechnungen',
'refunds' => 'Refunds',
'catalog' => 'Katalog',
'products' => 'Produkte',
'copy' => 'Copy',
'categories' => 'Kategorien',
'attributes' => 'Attribute',
'attribute-families' => 'Attributgruppen',
'customers' => 'Kunden',
'addresses' => 'Addresses',
'note' => 'Note',
'groups' => 'Gruppen',
'reviews' => 'Bewertungen',
'newsletter-subscriptions' => 'Newsletter-Abonnements',
@ -111,10 +116,13 @@ return [
'taxes' => 'Steuern',
'tax-categories' => 'Steuerkategorien',
'tax-rates' => 'Steuersätze',
'view' => 'View',
'edit' => 'Bearbeiten',
'create' => 'Hinzufügen',
'delete' => 'Löschen',
'marketing' => 'Marketing',
'mass-delete' => 'Mass Delete',
'mass-update' => 'Mass Update',
'marketing' => 'Marketing',
'promotions' => 'Promotions',
'cart-rules' => 'Warenkorbregeln',
'catalog-rules' => 'Katalogregeln',
@ -1197,7 +1205,7 @@ return [
'edit-error' => 'Can not edit this event.'
]
],
'error' =>
[
'go-to-home' => 'HOME ÖFFNEN',
@ -1337,6 +1345,10 @@ return [
'system' =>
[
'catalog' => 'Katalog',
'homepage' => 'Homepage configuration',
'allow-no-of-new-product-homepage' => 'Allowed No of New Product in Homepage',
'allow-no-of-featured-product-homepage' => 'Allowed No of Featured Product in Homepage',
'allow-out-of-stock-items' => 'Allow out of stock items',
'products' => 'Produkte',
'guest-checkout' => 'Gastbestellungen',
'allow-guest-checkout' => 'Gastbestellungen erlauben',

View File

@ -88,15 +88,20 @@ return [
'acl' => [
'dashboard' => 'Dashboard',
'sales' => 'Sales',
'cancel' => 'Cancel',
'orders' => 'Orders',
'shipments' => 'Shipments',
'invoices' => 'Invoices',
'refunds' => 'Refunds',
'catalog' => 'Catalog',
'products' => 'Products',
'copy' => 'Copy',
'categories' => 'Categories',
'attributes' => 'Attributes',
'attribute-families' => 'Attribute Families',
'customers' => 'Customers',
'addresses' => 'Addresses',
'note' => 'Note',
'groups' => 'Groups',
'reviews' => 'Reviews',
'newsletter-subscriptions' => 'Newsletter Subscriptions',
@ -113,9 +118,12 @@ return [
'taxes' => 'Taxes',
'tax-categories' => 'Tax Categories',
'tax-rates' => 'Tax Rates',
'view' => 'View',
'edit' => 'Edit',
'create' => 'Add',
'delete' => 'Delete',
'mass-delete' => 'Mass Delete',
'mass-update' => 'Mass Update',
'marketing' => 'Marketing',
'promotions' => 'Promotions',
'cart-rules' => 'Cart Rules',
@ -1340,6 +1348,7 @@ return [
'homepage' => 'Homepage configuration',
'allow-no-of-new-product-homepage' => 'Allowed No of New Product in Homepage',
'allow-no-of-featured-product-homepage' => 'Allowed No of Featured Product in Homepage',
'allow-out-of-stock-items' => 'Allow out of stock items',
'products' => 'Products',
'guest-checkout' => 'Guest Checkout',
'allow-guest-checkout' => 'Allow Guest Checkout',

View File

@ -85,15 +85,20 @@ return [
'acl' => [
'dashboard' => 'Tablero',
'sales' => 'Ventas',
'cancel' => 'Cancel',
'orders' => 'Pedidos',
'shipments' => 'Envíos',
'invoices' => 'Facturas',
'refunds' => 'Refunds',
'catalog' => 'Catálogo',
'products' => 'Productos',
'copy' => 'Copy',
'categories' => 'Categorías',
'attributes' => 'Atributos',
'attribute-families' => 'Familias de atributos',
'customers' => 'Clientes',
'addresses' => 'Addresses',
'note' => 'Note',
'groups' => 'Grupos',
'reviews' => 'Opiniones',
'newsletter-subscriptions' => 'Suscripciones a newsletter por correo',
@ -110,9 +115,12 @@ return [
'taxes' => 'Impuestos',
'tax-categories' => 'Categorías de impuestos',
'tax-rates' => 'Tasas de impuestos',
'view' => 'View',
'edit' => 'Editar',
'create' => 'Agregar',
'delete' => 'Borrar',
'mass-delete' => 'Mass Delete',
'mass-update' => 'Mass Update',
'marketing' => 'Marketing',
'promotions' => 'Promociones',
'cart-rules' => 'Reglas del carrito',
@ -1318,6 +1326,10 @@ return [
],
'system' => [
'catalog' => 'Catálogo',
'homepage' => 'Homepage configuration',
'allow-no-of-new-product-homepage' => 'Allowed No of New Product in Homepage',
'allow-no-of-featured-product-homepage' => 'Allowed No of Featured Product in Homepage',
'allow-out-of-stock-items' => 'Allow out of stock items',
'products' => 'Productos',
'guest-checkout' => 'Compras como invitado',
'allow-guest-checkout' => 'Permitir compras como invitado',

View File

@ -86,15 +86,20 @@ return [
'acl' => [
'dashboard' => 'داشبورد',
'sales' => 'فروش',
'cancel' => 'Cancel',
'orders' => 'سفارشات',
'shipments' => 'حمل و نقل',
'invoices' => 'صورت حساب',
'refunds' => 'Refunds',
'catalog' => 'کاتالوگ',
'products' => 'محصولات',
'copy' => 'Copy',
'categories' => 'دسته بندی ها',
'attributes' => 'ویژگی ها',
'attribute-families' => 'ویژگی خانواده',
'customers' => 'مشتریان',
'addresses' => 'Addresses',
'note' => 'Note',
'groups' => 'گروه ها',
'reviews' => 'بررسی ها',
'newsletter-subscriptions' => 'اشتراک های خبرنامه',
@ -111,9 +116,12 @@ return [
'taxes' => 'مالیات',
'tax-categories' => 'دسته بندی مالیات',
'tax-rates' => 'نرخ مالیات',
'view' => 'View',
'edit' => 'ویاریش',
'create' => 'افزودن',
'delete' => 'حذف',
'mass-delete' => 'Mass Delete',
'mass-update' => 'Mass Update',
'marketing' => 'Marketing',
'promotions' => 'تبلیغات',
'cart-rules' => 'قوانین سبد خرید',
@ -1326,6 +1334,10 @@ return [
],
'system' => [
'catalog' => 'کاتالوگ',
'homepage' => 'Homepage configuration',
'allow-no-of-new-product-homepage' => 'Allowed No of New Product in Homepage',
'allow-no-of-featured-product-homepage' => 'Allowed No of Featured Product in Homepage',
'allow-out-of-stock-items' => 'Allow out of stock items',
'products' => 'محصولات',
'guest-checkout' => 'وارسی میهمان',
'allow-guest-checkout' => 'مجاز به پرداخت مهمان',

View File

@ -86,15 +86,20 @@ return [
'acl' => [
'dashboard' => 'Dashboard',
'sales' => 'Vendite',
'cancel' => 'Cancel',
'orders' => 'Ordini',
'shipments' => 'Spedizioni',
'invoices' => 'Fatture',
'refunds' => 'Refunds',
'catalog' => 'Catalogo',
'products' => 'Prodotti',
'copy' => 'Copy',
'categories' => 'Categorie',
'attributes' => 'Attributi',
'attribute-families' => 'Famiglie Attributi',
'customers' => 'Clienti',
'addresses' => 'Addresses',
'note' => 'Note',
'groups' => 'Gruppi',
'reviews' => 'Recensioni',
'newsletter-subscriptions' => 'Iscrizioni Newsletter',
@ -111,9 +116,12 @@ return [
'taxes' => 'IVA',
'tax-categories' => 'Categorie IVA',
'tax-rates' => 'Aliquote IVA',
'view' => 'View',
'edit' => 'Modifica',
'create' => 'Aggiungi',
'delete' => 'Elimina',
'mass-delete' => 'Mass Delete',
'mass-update' => 'Mass Update',
'marketing' => 'Marketing',
'promotions' => 'Promozioni',
'cart-rules' => 'Regole Carrello',
@ -1329,6 +1337,10 @@ return [
],
'system' => [
'catalog' => 'Catalogo',
'homepage' => 'Homepage configuration',
'allow-no-of-new-product-homepage' => 'Allowed No of New Product in Homepage',
'allow-no-of-featured-product-homepage' => 'Allowed No of Featured Product in Homepage',
'allow-out-of-stock-items' => 'Allow out of stock items',
'products' => 'Prodotti',
'guest-checkout' => 'Checkout come Ospite',
'allow-guest-checkout' => 'Consenti Checkout come Ospite',

View File

@ -86,15 +86,20 @@ return [
'acl' => [
'dashboard' => 'Dashboard',
'sales' => 'Verkopen',
'cancel' => 'Cancel',
'orders' => 'Bestellingen',
'shipments' => 'Verzendingen',
'invoices' => 'Facturen',
'refunds' => 'Refunds',
'catalog' => 'Catalogus',
'products' => 'Producten',
'copy' => 'Copy',
'categories' => 'Categorieën',
'attributes' => 'Attributes',
'attribute-families' => 'Attribute Families',
'customers' => 'Klanten',
'addresses' => 'Addresses',
'note' => 'Note',
'groups' => 'Groepen',
'reviews' => 'Reviews',
'newsletter-subscriptions' => 'Newsletter Subscriptions',
@ -111,9 +116,12 @@ return [
'taxes' => 'Belastingen',
'tax-categories' => 'Belasting categorieën',
'tax-rates' => 'BTW-tarieven',
'view' => 'View',
'edit' => 'Edit',
'create' => 'Add',
'delete' => 'Verwijder',
'mass-delete' => 'Mass Delete',
'mass-update' => 'Mass Update',
'marketing' => 'Marketing',
'promotions' => 'Promoties',
'cart-rules' => 'Cart Rules',
@ -454,7 +462,7 @@ return [
'refunded' => 'Teruggestort',
'date' => 'Refund Date',
'customer-name' => 'klantnaam',
'status' => 'Toestand',
'status' => 'Status',
'action' => 'Actie',
'view-title' => 'Terugbetaling #:refund_id',
'invalid-refund-amount-error' => 'Het restitutiebedrag mag niet nul zijn.'
@ -695,7 +703,7 @@ return [
'save-btn-title' => 'Opslaan',
'description' => 'Description',
'active' => 'Actief',
'status' => 'Toestand'
'status' => 'Status'
]
]
],
@ -969,7 +977,7 @@ return [
'addresses' => 'Addresses',
'mass-destroy-success' => 'Klanten zijn succesvol verwijderd',
'mass-update-success' => 'Klanten succesvol bijgewerkt',
'status' => 'Toestand',
'status' => 'Status',
'active' => 'Actief',
'inactive' => 'Niet geactiveerd'
],
@ -978,7 +986,7 @@ return [
'title' => 'Recensies',
'edit-title' => 'Review bewerken',
'rating' => 'Beoordeling',
'status' => 'Toestand',
'status' => 'Status',
'comment' => 'Commentaar',
'pending' => 'In afwachting',
'approved' => 'Goedkeuren',
@ -1007,7 +1015,7 @@ return [
'rule-information' => 'Regelinformatie',
'name' => 'Naam',
'description' => 'Beschrijving',
'status' => 'Toestand',
'status' => 'Status',
'is-active' => 'Winkelwagenregel is actief',
'channels' => 'Kanalen',
'customer-groups' => 'Klantengroepen',
@ -1093,7 +1101,7 @@ return [
'rule-information' => 'Regelinformatie',
'name' => 'Naam',
'description' => 'Beschrijving',
'status' => 'Toestand',
'status' => 'Status',
'is-active' => 'Catalogusregel is actief',
'channels' => 'Kanalen',
'customer-groups' => 'Klantengroepen',
@ -1325,6 +1333,10 @@ return [
],
'system' => [
'catalog' => 'Catalogus',
'homepage' => 'Homepage configuration',
'allow-no-of-new-product-homepage' => 'Allowed No of New Product in Homepage',
'allow-no-of-featured-product-homepage' => 'Allowed No of Featured Product in Homepage',
'allow-out-of-stock-items' => 'Allow out of stock items',
'products' => 'Producten',
'guest-checkout' => 'Gast afrekenen',
'allow-guest-checkout' => 'Gast afrekenen toestaan',
@ -1352,8 +1364,8 @@ return [
'title' => 'Titel',
'description' => 'Omschrijving',
'rate' => 'Tarief',
'status' => 'Toestand',
'calculate-tax' => 'Beregn skat',
'status' => 'Status',
'calculate-tax' => 'BTW berekenen',
'type' => 'Type',
'payment-methods' => 'Betaalmethodes',
'cash-on-delivery' => 'Rembours',

View File

@ -85,15 +85,20 @@ return [
'acl' => [
'dashboard' => 'Kokpit',
'sales' => 'Sprzedaż',
'cancel' => 'Cancel',
'orders' => 'Zamówienia',
'shipments' => 'przesyłki',
'invoices' => 'Faktury',
'refunds' => 'Refunds',
'catalog' => 'Katalog',
'products' => 'Produkty',
'copy' => 'Copy',
'categories' => 'Kategorie',
'attributes' => 'Atrybuty',
'attribute-families' => 'Rodziny atrybutów',
'customers' => 'Klienci',
'addresses' => 'Addresses',
'note' => 'Note',
'groups' => 'Grupy',
'reviews' => 'Recenzje',
'newsletter-subscriptions' => 'Subskrypcje newslettera',
@ -110,9 +115,12 @@ return [
'taxes' => 'Podatki',
'tax-categories' => 'Kategorie podatkowe',
'tax-rates' => 'Stawki podatkowe',
'view' => 'View',
'edit' => 'Edytuj',
'create' => 'Dodaj',
'delete' => 'Usuń',
'mass-delete' => 'Mass Delete',
'mass-update' => 'Mass Update',
'marketing' => 'Marketing',
'promotions' => 'Promocje',
'cart-rules' => 'Zasady koszyka',
@ -1326,6 +1334,10 @@ return [
],
'system' => [
'catalog' => 'Katalog',
'homepage' => 'Homepage configuration',
'allow-no-of-new-product-homepage' => 'Allowed No of New Product in Homepage',
'allow-no-of-featured-product-homepage' => 'Allowed No of Featured Product in Homepage',
'allow-out-of-stock-items' => 'Allow out of stock items',
'products' => 'Produkty',
'guest-checkout' => 'Zamówienia gości',
'allow-guest-checkout' => 'Zezwalaj na zamówienia gości',

View File

@ -86,15 +86,20 @@ return [
'acl' => [
'dashboard' => 'Dashboard',
'sales' => 'Vendas',
'cancel' => 'Cancel',
'orders' => 'Pedidos',
'shipments' => 'Envios',
'invoices' => 'Faturas',
'refunds' => 'Refunds',
'catalog' => 'Catálogos',
'products' => 'Produtos',
'copy' => 'Copy',
'categories' => 'Categorias',
'attributes' => 'Atributos',
'attribute-families' => 'Famílias de Atributos',
'customers' => 'Clientes',
'addresses' => 'Addresses',
'note' => 'Note',
'groups' => 'Grupos',
'reviews' => 'Avaliações',
'newsletter-subscriptions' => 'Inscrições de Newsletter',
@ -111,9 +116,12 @@ return [
'taxes' => 'Impostos',
'tax-categories' => 'Categorias de Impostos',
'tax-rates' => 'Impostos de Impostos',
'view' => 'View',
'edit' => 'Edit',
'create' => 'Add',
'delete' => 'Delete',
'mass-delete' => 'Mass Delete',
'mass-update' => 'Mass Update',
'marketing' => 'Marketing',
'promotions' => 'Promoções',
'cart-rules' => 'Regras do Carrinho',
@ -1325,6 +1333,10 @@ return [
],
'system' => [
'catalog' => 'Catálogo',
'homepage' => 'Homepage configuration',
'allow-no-of-new-product-homepage' => 'Allowed No of New Product in Homepage',
'allow-no-of-featured-product-homepage' => 'Allowed No of Featured Product in Homepage',
'allow-out-of-stock-items' => 'Allow out of stock items',
'products' => 'Produtos',
'guest-checkout' => 'Compras sem cadastro?',
'allow-guest-checkout' => 'Permitir compra para clientes sem cadastros?',

View File

@ -84,15 +84,20 @@ return [
'acl' => [
'dashboard' => 'Panel',
'sales' => 'Satışlar',
'cancel' => 'Cancel',
'orders' => 'Siparişler',
'shipments' => 'Teslimatlar',
'invoices' => 'Faturalar',
'refunds' => 'Refunds',
'catalog' => 'Katalog',
'products' => 'Ürünler',
'copy' => 'Copy',
'categories' => 'Kategoriler',
'attributes' => 'Nitelikler',
'attribute-families' => 'Nitelik Grupları',
'customers' => 'Müşteriler',
'addresses' => 'Addresses',
'note' => 'Note',
'groups' => 'Gruplar',
'reviews' => 'İncelemeler',
'newsletter-subscriptions' => 'Bülten Üyelikleri',
@ -109,9 +114,12 @@ return [
'taxes' => 'Vergi',
'tax-categories' => 'Vergi Grupları',
'tax-rates' => 'Vergi Oranları',
'view' => 'View',
'edit' => 'Düzenle',
'create' => 'Oluştur',
'delete' => 'Sil',
'mass-delete' => 'Mass Delete',
'mass-update' => 'Mass Update',
'marketing' => 'Marketing',
'promotions' => 'Promosyonlar',
'cart-rules' => 'Alışveriş Sepeti Kuralları',
@ -1313,6 +1321,10 @@ return [
],
'system' => [
'catalog' => 'Katalog',
'homepage' => 'Homepage configuration',
'allow-no-of-new-product-homepage' => 'Allowed No of New Product in Homepage',
'allow-no-of-featured-product-homepage' => 'Allowed No of Featured Product in Homepage',
'allow-out-of-stock-items' => 'Allow out of stock items',
'products' => 'Ürünler',
'guest-checkout' => 'Ziyaretçi Satışı',
'allow-guest-checkout' => 'Ziyaretçi Alımına İzin Ver',

View File

@ -85,7 +85,7 @@
<div class="control-group">
<div class="control-group" :class="[errors.has(inputName + '[value]') ? 'has-error' : '']">
<input type="number" v-validate="{required: true, min_value: 0, ...(customerGroupPrice.value_type === 'discount' ? {max_value: 100} : {})}" :name="[inputName + '[value]']" v-model="customerGroupPrice.value" class="control" data-vv-as="&quot;{{ __('admin::app.datagrid.price') }}&quot;"/>
<input type="number" step=".01" v-validate="{required: true, min_value: 0, ...(customerGroupPrice.value_type === 'discount' ? {max_value: 100} : {})}" :name="[inputName + '[value]']" v-model="customerGroupPrice.value" class="control" data-vv-as="&quot;{{ __('admin::app.datagrid.price') }}&quot;"/>
<span class="control-error" v-if="errors.has(inputName + '[value]')">@{{ errors.first(inputName + '[value]') }}</span>
</div>
</div>

View File

@ -38,7 +38,7 @@
<div class="control-group">
<select class="control" id="locale-switcher" name="locale">
@foreach (core()->getAllLocales() as $localeModel)
@foreach (app('Webkul\Core\Repositories\ChannelRepository')->findOneByField('code', $channel)->locales as $localeModel)
<option
value="{{ $localeModel->code }}" {{ ($localeModel->code) == $locale ? 'selected' : '' }}>
@ -199,6 +199,13 @@
$(document).ready(function () {
$('#channel-switcher, #locale-switcher').on('change', function (e) {
$('#channel-switcher').val()
if (event.target.id == 'channel-switcher') {
let locale = "{{ app('Webkul\Core\Repositories\ChannelRepository')->findOneByField('code', $channel)->locales->first()->code }}";
$('#locale-switcher').val(locale);
}
var query = '?channel=' + $('#channel-switcher').val() + '&locale=' + $('#locale-switcher').val();
window.location.href = "{{ route('admin.catalog.products.edit', $product->id) }}" + query;

View File

@ -1,4 +1 @@
<input type="text" v-validate="'{{$validations}}'" class="control" id="{{ $attribute->code }}" name="{{ $attribute->code }}" value="{{ old($attribute->code) ?: $product[$attribute->code] }}" {{ in_array($attribute->code, ['sku', 'url_key']) ? 'v-slugify' : '' }} data-vv-as="&quot;{{ $attribute->admin_name }}&quot;" {{ $attribute->code == 'name' && ! $product[$attribute->code] ? 'v-slugify-target=\'url_key\'' : '' }} />
<input type="text" v-validate="'{{$validations}}'" class="control" id="{{ $attribute->code }}" name="{{ $attribute->code }}" value="{{ old($attribute->code) ?: $product[$attribute->code] }}" {{ in_array($attribute->code, ['sku', 'url_key']) ? 'v-slugify' : '' }} data-vv-as="&quot;{{ $attribute->admin_name }}&quot;" {{ $attribute->code == 'name' && ! $product[$attribute->code] ? 'v-slugify-target=\'url_key\'' : '' }} />

View File

@ -260,11 +260,11 @@
</div>
@endif
</td>
<td>{{ core()->formatBasePrice($item->base_price) }}</td>
<td>{!! core()->formatBasePrice($item->base_price, true) !!}</td>
<td class="text-center">{{ $item->qty }}</td>
<td class="text-center">{{ core()->formatBasePrice($item->base_total) }}</td>
<td class="text-center">{{ core()->formatBasePrice($item->base_tax_amount) }}</td>
<td class="text-center">{{ core()->formatBasePrice($item->base_total + $item->base_tax_amount) }}</td>
<td class="text-center">{!! core()->formatBasePrice($item->base_total, true) !!}</td>
<td class="text-center">{!! core()->formatBasePrice($item->base_tax_amount, true) !!}</td>
<td class="text-center">{!! core()->formatBasePrice($item->base_total + $item->base_tax_amount, true) !!}</td>
</tr>
@endforeach
@ -277,31 +277,31 @@
<tr>
<td>{{ __('admin::app.sales.orders.subtotal') }}</td>
<td>-</td>
<td>{{ core()->formatBasePrice($invoice->base_sub_total) }}</td>
<td>{!! core()->formatBasePrice($invoice->base_sub_total, true) !!}</td>
</tr>
<tr>
<td>{{ __('admin::app.sales.orders.shipping-handling') }}</td>
<td>-</td>
<td>{{ core()->formatBasePrice($invoice->base_shipping_amount) }}</td>
<td>{!! core()->formatBasePrice($invoice->base_shipping_amount, true) !!}</td>
</tr>
<tr>
<td>{{ __('admin::app.sales.orders.tax') }}</td>
<td>-</td>
<td>{{ core()->formatBasePrice($invoice->base_tax_amount) }}</td>
<td>{!! core()->formatBasePrice($invoice->base_tax_amount, true) !!}</td>
</tr>
<tr>
<td>{{ __('admin::app.sales.orders.discount') }}</td>
<td>-</td>
<td>{{ core()->formatBasePrice($invoice->base_discount_amount) }}</td>
<td>{!! core()->formatBasePrice($invoice->base_discount_amount, true) !!}</td>
</tr>
<tr>
<td><strong>{{ __('admin::app.sales.orders.grand-total') }}</strong></td>
<td><strong>-</strong></td>
<td><strong>{{ core()->formatBasePrice($invoice->base_grand_total) }}</strong></td>
<td><strong>{!! core()->formatBasePrice($invoice->base_grand_total, true) !!}</strong></td>
</tr>
</table>

View File

@ -25,7 +25,7 @@
<div class="page-action">
{!! view_render_event('sales.order.page_action.before', ['order' => $order]) !!}
@if ($order->canCancel())
@if ($order->canCancel() && bouncer()->hasPermission('sales.orders.cancel'))
<a href="{{ route('admin.sales.orders.cancel', $order->id) }}" class="btn btn-lg btn-primary" v-alert:message="'{{ __('admin::app.sales.orders.cancel-confirm-msg') }}'">
{{ __('admin::app.sales.orders.cancel-btn-title') }}
</a>

View File

@ -61,7 +61,7 @@
{{ __('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'] ?? '') }}"/>
<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'] ?? $channel->name) }}"/>
<span class="control-error" v-if="errors.has('{{$locale}}[name]')">@{{ errors.first('{!!$locale!!}[page_title]') }}</span>
</div>
@ -70,7 +70,7 @@
{{ __('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>
<textarea class="control" id="description" name="{{$locale}}[description]">{{ old($locale)['description'] ?? ($channel->translate($locale)['description'] ?? $channel->description) }}</textarea>
</div>
<div class="control-group" :class="[errors.has('inventory_sources[]') ? 'has-error' : '']">
@ -190,7 +190,7 @@
{{ __('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>
<textarea class="control" id="home_page_content" name="{{$locale}}[home_page_content]">{{ old($locale)['home_page_content'] ?? ($channel->translate($locale)['home_page_content'] ?? $channel->home_page_content) }}</textarea>
</div>
<div class="control-group">
@ -198,7 +198,7 @@
{{ __('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>
<textarea class="control" id="footer_content" name="{{$locale}}[footer_content]">{{ old($locale)['footer_content'] ?? ($channel->translate($locale)['footer_content'] ?? $channel->footer_content) }}</textarea>
</div>
<div class="control-group">
@ -217,7 +217,7 @@
</accordian>
@php
$home_seo = $channel->translate($locale)['home_seo'] ?? '{}';
$home_seo = $channel->translate($locale)['home_seo'] ?? $channel->home_seo;
$seo = json_decode($home_seo);
@endphp
@ -276,7 +276,7 @@
{{ __('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'] ?? '') }}"/>
<input class="control" id="maintenance-mode-text" name="{{$locale}}[maintenance_mode_text]" value="{{ old('maintenance_mode_text') ?? ($channel->translate($locale)['maintenance_mode_text'] ?? $channel->maintenance_mode_text) }}"/>
</div>
<div class="control-group">

View File

@ -6,7 +6,7 @@
@section('content')
<div class="content">
<form method="POST" action="{{ route('admin.tax-categories.create') }}" @submit.prevent="onSubmit">
<form method="POST" action="{{ route('admin.tax-categories.store') }}" @submit.prevent="onSubmit">
<div class="page-header">
<div class="page-title">
<h1>

View File

@ -12,7 +12,7 @@
</div>
<div class="page-action">
<a href="{{ route('admin.tax-categories.show') }}" class="btn btn-lg btn-primary">
<a href="{{ route('admin.tax-categories.create') }}" class="btn btn-lg btn-primary">
{{ __('admin::app.settings.tax-categories.add-title') }}
</a>
</div>

View File

@ -6,7 +6,7 @@
@section('content')
<div class="content">
<form method="POST" action="{{ route('admin.tax-rates.create') }}" @submit.prevent="onSubmit">
<form method="POST" action="{{ route('admin.tax-rates.store') }}" @submit.prevent="onSubmit">
<div class="page-header">
<div class="page-title">
<h1>

View File

@ -25,7 +25,7 @@
</span>
</div>
<a href="{{ route('admin.tax-rates.show') }}" class="btn btn-lg btn-primary">
<a href="{{ route('admin.tax-rates.create') }}" class="btn btn-lg btn-primary">
{{ __('admin::app.settings.tax-rates.add-title') }}
</a>
</div>

View File

@ -581,12 +581,12 @@ class CartRule
->where('cart_rule_channels.channel_id', $channelId)
->where(function ($query1) {
/** @var Builder $query1 */
$query1->where('cart_rules.starts_from', '<=', Carbon::now()->format('Y-m-d'))
$query1->where('cart_rules.starts_from', '<=', Carbon::now()->format('Y-m-d H:m:s'))
->orWhereNull('cart_rules.starts_from');
})
->where(function ($query2) {
/** @var Builder $query2 */
$query2->where('cart_rules.ends_till', '>=', Carbon::now()->format('Y-m-d'))
$query2->where('cart_rules.ends_till', '>=', Carbon::now()->format('Y-m-d H:m:s'))
->orWhereNull('cart_rules.ends_till');
})
->with([

View File

@ -180,7 +180,6 @@ class CartRuleController extends Controller
'customer_groups' => 'required|array|min:1',
'coupon_type' => 'required',
'use_auto_generation' => 'required_if:coupon_type,==,1',
'coupon_code' => 'required_if:use_auto_generation,==,0|unique:cart_rule_coupons,code,' . $id,
'starts_from' => 'nullable|date',
'ends_till' => 'nullable|date|after_or_equal:starts_from',
'action_type' => 'required',
@ -189,6 +188,18 @@ class CartRuleController extends Controller
$cartRule = $this->cartRuleRepository->findOrFail($id);
if ($cartRule->coupon_type) {
if ($cartRule->cart_rule_coupon) {
$this->validate(request(), [
'coupon_code' => 'required_if:use_auto_generation,==,0|unique:cart_rule_coupons,code,' . $cartRule->cart_rule_coupon->id,
]);
} else {
$this->validate(request(), [
'coupon_code' => 'required_if:use_auto_generation,==,0|unique:cart_rule_coupons,code',
]);
}
}
Event::dispatch('promotions.cart_rule.update.before', $cartRule);
$cartRule = $this->cartRuleRepository->update(request()->all(), $id);

View File

@ -2,6 +2,7 @@
namespace Webkul\Category\Http\Controllers;
use Webkul\Core\Models\Channel;
use Illuminate\Support\Facades\Event;
use Webkul\Category\Repositories\CategoryRepository;
use Webkul\Attribute\Repositories\AttributeRepository;
@ -9,7 +10,7 @@ use Webkul\Attribute\Repositories\AttributeRepository;
class CategoryController extends Controller
{
/**
* Contains route related configuration
* Contains route related configuration.
*
* @var array
*/
@ -147,15 +148,16 @@ class CategoryController extends Controller
{
$category = $this->categoryRepository->findOrFail($id);
if(strtolower($category->name) == "root") {
if ($this->isCategoryDeletable($category)) {
session()->flash('warning', trans('admin::app.response.delete-category-root', ['name' => 'Category']));
} else {
try {
Event::dispatch('catalog.category.delete.before', $id);
if($category->products->count() > 0) {
if ($category->products->count() > 0) {
$category->products()->delete();
}
$category->delete();
Event::dispatch('catalog.category.delete.after', $id);
@ -163,7 +165,7 @@ class CategoryController extends Controller
session()->flash('success', trans('admin::app.response.delete-success', ['name' => 'Category']));
return response()->json(['message' => true], 200);
} catch(\Exception $e) {
} catch (\Exception $e) {
session()->flash('error', trans('admin::app.response.delete-failed', ['name' => 'Category']));
}
}
@ -172,7 +174,7 @@ class CategoryController extends Controller
}
/**
* Remove the specified resources from database
* Remove the specified resources from database.
*
* @return \Illuminate\Http\Response
*/
@ -185,7 +187,7 @@ class CategoryController extends Controller
$category = $this->categoryRepository->find($categoryId);
if (isset($category)) {
if(strtolower($category->name) == "root") {
if ($this->isCategoryDeletable($category)) {
$suppressFlash = false;
session()->flash('warning', trans('admin::app.response.delete-category-root', ['name' => 'Category']));
} else {
@ -193,14 +195,14 @@ class CategoryController extends Controller
$suppressFlash = true;
Event::dispatch('catalog.category.delete.before', $categoryId);
if($category->products->count() > 0) {
if ($category->products->count() > 0) {
$category->products()->delete();
}
$category->delete();
Event::dispatch('catalog.category.delete.after', $categoryId);
} catch(\Exception $e) {
} catch (\Exception $e) {
session()->flash('error', trans('admin::app.response.delete-failed', ['name' => 'Category']));
}
}
@ -214,7 +216,11 @@ class CategoryController extends Controller
return redirect()->route($this->_config['redirect']);
}
/**
* Get category product count.
*
* @return \Illuminate\Http\Response
*/
public function categoryProductCount() {
$indexes = explode(",", request()->input('indexes'));
$product_count = 0;
@ -226,4 +232,24 @@ class CategoryController extends Controller
return response()->json(['product_count' => $product_count], 200);
}
/**
* Check whether the current category is deletable or not.
*
* This method will fetch all root category ids from the channel. If `id` is present,
* then it is not deletable.
*
* @param \Webkul\Category\Models\Category $category
* @return bool
*/
private function isCategoryDeletable($category)
{
static $rootIdInChannels;
if (! $rootIdInChannels) {
$rootIdInChannels = Channel::pluck('root_category_id');
}
return $category->id === 1 || $rootIdInChannels->contains($category->id);
}
}

View File

@ -20,7 +20,6 @@ use Webkul\Customer\Repositories\CustomerAddressRepository;
class Cart
{
/**
* CartRepository instance
*
@ -558,6 +557,14 @@ 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;
@ -1282,6 +1289,25 @@ class Cart
}
}
/**
* Check whether cart has product.
*
* @param \Webkul\Product\Models\Product $product
* @return bool
*/
public function hasProduct($product): bool
{
$cart = \Cart::getCart();
if (! $cart) {
return false;
}
$count = $cart->all_items()->where('product_id', $product->id)->count();
return $count > 0 ? true : false;
}
/**
* Check minimum order.
*

View File

@ -554,13 +554,15 @@ class Core
}
/**
* Format price with base currency symbol
* Format price with base currency symbol. This method also give ability to encode
* the base currency symbol and its optional.
*
* @param float $price
* @param float $price
* @param bool $isEncoded
*
* @return string
*/
public function formatBasePrice($price)
public function formatBasePrice($price, $isEncoded = false)
{
if (is_null($price)) {
$price = 0;
@ -570,15 +572,17 @@ class Core
if ($symbol = $this->getBaseCurrency()->symbol) {
if ($this->currencySymbol($this->getBaseCurrencyCode()) == $symbol) {
return $formater->formatCurrency($price, $this->getBaseCurrencyCode());
$content = $formater->formatCurrency($price, $this->getBaseCurrencyCode());
} else {
$formater->setSymbol(\NumberFormatter::CURRENCY_SYMBOL, $symbol);
return $formater->format($this->convertPrice($price));
$content = $formater->format($this->convertPrice($price));
}
} else {
return $formater->formatCurrency($price, $this->getBaseCurrencyCode());
$content = $formater->formatCurrency($price, $this->getBaseCurrencyCode());
}
return ! $isEncoded ? $content : htmlentities($content);
}
/**

View File

@ -67,7 +67,7 @@ class ExchangeRates extends ExchangeRate
$result = json_decode($result->getBody()->getContents(), true);
if (isset($result['success']) && ! $result['success']) {
throw new E\xception(
throw new \Exception(
isset($result['error']['info'])
? $result['error']['info']
: $result['error']['type'], 1);

View File

@ -70,6 +70,12 @@ class SubscriptionController extends Controller
$subscriber = $this->subscribersListRepository->findOrFail($id);
$customer = $subscriber->customer;
$customer->subscribed_to_news_letter = $data['is_subscribed'];
$customer->save();
$result = $subscriber->update($data);
if ($result) {
@ -99,7 +105,7 @@ class SubscriptionController extends Controller
return response()->json(['message' => true], 200);
} catch (\Exception $e) {
report($e);
session()->flash('error', trans('admin::app.response.delete-failed', ['name' => 'Subscriber']));
}

View File

@ -3,6 +3,7 @@
namespace Webkul\Core\Models;
use Illuminate\Database\Eloquent\Model;
use Webkul\Customer\Models\CustomerProxy;
use Webkul\Core\Contracts\SubscribersList as SubscribersListContract;
class SubscribersList extends Model implements SubscribersListContract
@ -24,4 +25,12 @@ class SubscribersList extends Model implements SubscribersListContract
];
protected $hidden = ['token'];
/**
* Get the customer associated with the subscription.
*/
public function customer()
{
return $this->belongsTo(CustomerProxy::modelClass());
}
}

View File

@ -49,7 +49,7 @@ class RegistrationController extends Controller
* @param \Webkul\Customer\Repositories\CustomerRepository $customer
* @param \Webkul\Customer\Repositories\CustomerGroupRepository $customerGroupRepository
* @param \Webkul\Core\Repositories\SubscribersListRepository $subscriptionRepository
*
*
* @return void
*/
public function __construct(
@ -97,6 +97,7 @@ class RegistrationController extends Controller
'is_verified' => core()->getConfigData('customer.settings.email.verification') ? 0 : 1,
'customer_group_id' => $this->customerGroupRepository->findOneWhere(['code' => 'general'])->id,
'token' => md5(uniqid(rand(), true)),
'subscribed_to_news_letter' => isset(request()->input()['is_subscribed']) ? 1 : 0,
]);
Event::dispatch('customer.registration.before');
@ -220,7 +221,7 @@ class RegistrationController extends Controller
return redirect()->back();
}
session()->flash('success', trans('shop::app.customer.signup-form.verification-sent'));
return redirect()->back();

View File

@ -59,6 +59,10 @@ class WishlistController extends Controller
{
$wishlistItems = $this->wishlistRepository->getCustomerWhishlist();
if (! core()->getConfigData('general.content.shop.wishlist_option')) {
abort(404);
}
return view($this->_config['view'])->with('items', $wishlistItems);
}

View File

@ -7,6 +7,7 @@ use Illuminate\Foundation\Auth\User as Authenticatable;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Webkul\Checkout\Models\CartProxy;
use Webkul\Sales\Models\OrderProxy;
use Webkul\Core\Models\SubscribersListProxy;
use Webkul\Product\Models\ProductReviewProxy;
use Webkul\Customer\Notifications\CustomerResetPassword;
use Webkul\Customer\Contracts\Customer as CustomerContract;
@ -160,4 +161,12 @@ class Customer extends Authenticatable implements CustomerContract, JWTSubject
{
return [];
}
/**
* Get the customer's subscription.
*/
public function subscription()
{
return $this->hasOne(SubscribersListProxy::modelClass(), 'customer_id');
}
}

View File

@ -90,18 +90,9 @@ class Campaign
*/
public function getEmailAddresses($campaign)
{
$newsletterEmails = app('\Webkul\Core\Repositories\SubscribersListRepository')->getModel()
->where('is_subscribed', 1)
->where('channel_id', $campaign->channel_id)
->get('email');
$customerGroupEmails = $campaign->customer_group->customers()->where('subscribed_to_news_letter', 1)->get('email');
$emails = [];
foreach ($newsletterEmails as $row) {
$emails[] = $row->email;
}
$customerGroupEmails = $campaign->customer_group->customers()->where('subscribed_to_news_letter', 1)->get('email');
foreach ($customerGroupEmails as $row) {
$emails[] = $row->email;

View File

@ -3,8 +3,8 @@
namespace Webkul\Marketing\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Event;
use Webkul\Marketing\Console\Commands\EmailsCommand;
use Illuminate\Console\Scheduling\Schedule;
class MarketingServiceProvider extends ServiceProvider
{
@ -19,9 +19,9 @@ class MarketingServiceProvider extends ServiceProvider
$this->loadRoutesFrom(__DIR__ . '/../Http/routes.php');
$this->loadTranslationsFrom(__DIR__ . '/../Resources/lang', 'marketing');
$this->loadViewsFrom(__DIR__ . '/../Resources/views', 'marketing');
$this->callAfterResolving(Schedule::class, function (Schedule $schedule) {
$schedule->command('campaign:process')->daily();
});
}
/**
@ -31,7 +31,6 @@ class MarketingServiceProvider extends ServiceProvider
*/
public function register()
{
if ($this->app->runningInConsole()) {
$this->commands([EmailsCommand::class]);
}

View File

@ -44,8 +44,8 @@ class ConfigurableOption extends AbstractProduct
'attributes' => $this->getAttributesData($product, $options),
'index' => isset($options['index']) ? $options['index'] : [],
'regular_price' => [
'formated_price' => core()->currency($product->getTypeInstance()->getMinimalPrice()),
'price' => $product->getTypeInstance()->getMinimalPrice(),
'formated_price' => $product->getTypeInstance()->haveOffer() ? core()->currency($product->getTypeInstance()->getOfferPrice()) : core()->currency($product->getTypeInstance()->getMinimalPrice()),
'price' => $product->getTypeInstance()->haveOffer() ? $product->getTypeInstance()->getOfferPrice() : $product->getTypeInstance()->getMinimalPrice(),
],
'variant_prices' => $this->getVariantPrices($product),
'variant_images' => $this->getVariantImages($product),

View File

@ -46,7 +46,7 @@ class Toolbar extends AbstractProduct
{
$keys = explode('-', $key);
return request()->fullUrlWithQuery([
return $this->fullUrlWithQuery([
'sort' => current($keys),
'order' => end($keys),
]);
@ -60,7 +60,7 @@ class Toolbar extends AbstractProduct
*/
public function getLimitUrl($limit)
{
return request()->fullUrlWithQuery([
return $this->fullUrlWithQuery([
'limit' => $limit,
]);
}
@ -73,7 +73,7 @@ class Toolbar extends AbstractProduct
*/
public function getModeUrl($mode)
{
return request()->fullUrlWithQuery([
return $this->fullUrlWithQuery([
'mode' => $mode,
]);
}
@ -185,4 +185,22 @@ class Toolbar extends AbstractProduct
/* if still default config is not set from the admin then in last needed hardcoded value */
return $viewOption ?? 'grid';
}
/**
* Returns the query string. As request built in method does not able to handle the
* multiple question marks, this method will check the query string and append the query string.
*
* @param array $additionalQuery
* @return string
*/
public function fullUrlWithQuery($additionalQuery)
{
$queryString = request()->getQueryString();
$additionalQueryString = http_build_query($additionalQuery);
return $queryString
? url()->current() . '?' . $queryString . '&' . $additionalQueryString
: url()->current() . '?' . $additionalQueryString;
}
}

View File

@ -912,4 +912,72 @@ abstract class AbstractType
return false;
}
/**
* Get more offers for customer group pricing.
*
* @return array
*/
public function getCustomerGroupPricingOffers() {
$offerLines = [];
$haveOffers = true;
$customerGroupId = null;
if (Cart::getCurrentCustomer()->check()) {
$customerGroupId = Cart::getCurrentCustomer()->user()->customer_group_id;
} else {
$customerGroupRepository = app('Webkul\Customer\Repositories\CustomerGroupRepository');
if ($customerGuestGroup = $customerGroupRepository->findOneByField('code', 'guest')) {
$customerGroupId = $customerGuestGroup->id;
}
}
$customerGroupPrices = $this->product->customer_group_prices()->where(function ($query) use ($customerGroupId) {
$query->where('customer_group_id', $customerGroupId)
->orWhereNull('customer_group_id');
}
)->groupBy('qty')->get()->sortBy('qty')->values()->all();
if ($this->haveSpecialPrice()) {
$rulePrice = app('Webkul\CatalogRule\Helpers\CatalogRuleProductPrice')->getRulePrice($this->product);
if ($rulePrice && $rulePrice->price < $this->product->special_price) {
$haveOffers = false;
}
if ($haveOffers) {
foreach ($customerGroupPrices as $key => $customerGroupPrice) {
if ($customerGroupPrice && $customerGroupPrice->qty > 1) {
array_push($offerLines, $this->getOfferLines($customerGroupPrice));
}
}
}
} else {
if (count($customerGroupPrices) > 0) {
foreach ($customerGroupPrices as $key => $customerGroupPrice) {
array_push($offerLines, $this->getOfferLines($customerGroupPrice));
}
}
}
return $offerLines;
}
/**
* Get offers lines.
*
* @param array $customerGroupPrice
*
* @return array
*/
public function getOfferLines($customerGroupPrice) {
$price = $this->getCustomerGroupPrice($this->product, $customerGroupPrice->qty);
$discount = number_format((($this->product->price - $price) * 100) / ($this->product->price), 2);
$offerLines = trans('shop::app.products.offers', ['qty' => $customerGroupPrice->qty,
'price' => core()->currency($price), 'discount' => $discount]);
return $offerLines;
}
}

View File

@ -128,8 +128,9 @@ class Bundle extends AbstractType
public function update(array $data, $id, $attribute = "id")
{
$product = parent::update($data, $id, $attribute);
$route = request()->route() ? request()->route()->getName() : '';
if (request()->route()->getName() != 'admin.catalog.products.massupdate') {
if ($route != 'admin.catalog.products.massupdate') {
$this->productBundleOptionRepository->saveBundleOptons($data, $product);
}
@ -761,4 +762,4 @@ class Bundle extends AbstractType
return true;
}
}
}

View File

@ -95,8 +95,9 @@ class Configurable extends AbstractType
public function update(array $data, $id, $attribute = "id")
{
$product = parent::update($data, $id, $attribute);
$route = request()->route() ? request()->route()->getName() : '';
if (request()->route()->getName() != 'admin.catalog.products.massupdate') {
if ($route != 'admin.catalog.products.massupdate') {
$previousVariantIds = $product->variants->pluck('id');
if (isset($data['variants'])) {
@ -379,6 +380,49 @@ class Configurable extends AbstractType
return min($minPrices);
}
/**
* Get product offer price
*
* @return float
*/
public function getOfferPrice() {
$rulePrices = $customerGroupPrices = [];
foreach ($this->product->variants as $variant) {
$rulePrice = app('Webkul\CatalogRule\Helpers\CatalogRuleProductPrice')->getRulePrice($variant);
if ($rulePrice) {
$rulePrices[] = $rulePrice->price;
}
$customerGroupPrices[] = $this->getCustomerGroupPrice($variant, 1);
}
if ($rulePrices || $customerGroupPrices) {
return min(array_merge($rulePrices, $customerGroupPrices));
}
return [];
}
/**
* Check for offer
*
* @return bool
*/
public function haveOffer() {
$haveOffer = false;
$offerPrice = $this->getOfferPrice();
$minPrice = $this->getMinimalPrice();
if ($offerPrice < $minPrice) {
$haveOffer = true;
}
return $haveOffer;
}
/**
* Get product maximam price
*
@ -404,9 +448,16 @@ class Configurable extends AbstractType
*/
public function getPriceHtml()
{
return '<span class="price-label">' . trans('shop::app.products.price-label') . '</span>'
if ($this->haveOffer()) {
return '<div class="sticker sale">' . trans('shop::app.products.sale') . '</div>'
. '<span class="price-label">' . trans('shop::app.products.price-label') . '</span>'
. '<span class="regular-price">' . core()->currency($this->getMinimalPrice()) . '</span>'
. '<span class="final-price">' . core()->currency($this->getOfferPrice()) . '</span>';
} else {
return '<span class="price-label">' . trans('shop::app.products.price-label') . '</span>'
. ' '
. '<span class="final-price">' . core()->currency($this->getMinimalPrice()) . '</span>';
}
}
/**
@ -539,7 +590,7 @@ class Configurable extends AbstractType
$product = $item->child->product;
} else {
$product = $item->product;
}
}
}
}
@ -660,4 +711,4 @@ class Configurable extends AbstractType
return $total;
}
}
}

View File

@ -118,8 +118,9 @@ class Downloadable extends AbstractType
public function update(array $data, $id, $attribute = "id")
{
$product = parent::update($data, $id, $attribute);
$route = request()->route() ? request()->route()->getName() : '';
if (request()->route()->getName() != 'admin.catalog.products.massupdate') {
if ($route != 'admin.catalog.products.massupdate') {
$this->productDownloadableLinkRepository->saveLinks($data, $product);
$this->productDownloadableSampleRepository->saveSamples($data, $product);
@ -287,4 +288,4 @@ class Downloadable extends AbstractType
return $result;
}
}
}

View File

@ -92,8 +92,9 @@ class Grouped extends AbstractType
public function update(array $data, $id, $attribute = "id")
{
$product = parent::update($data, $id, $attribute);
$route = request()->route() ? request()->route()->getName() : '';
if (request()->route()->getName() != 'admin.catalog.products.massupdate') {
if ($route != 'admin.catalog.products.massupdate') {
$this->productGroupedProductRepository->saveGroupedProducts($data, $product);
}
@ -231,4 +232,4 @@ class Grouped extends AbstractType
return $products;
}
}
}

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,4 +1,4 @@
{
"/js/shop.js": "/js/shop.js?id=fd3e9e2c897df46dd84c",
"/css/shop.css": "/css/shop.css?id=5f874d3390a80dcc95dd"
"/js/shop.js": "/js/shop.js?id=83c93b077da401f7b709",
"/css/shop.css": "/css/shop.css?id=6f4a4f8fad1b25e05e33"
}

View File

@ -53,7 +53,10 @@ class ProductsCategoriesProxyController extends Controller
{
$slugOrPath = trim($request->getPathInfo(), '/');
if (preg_match('/^([a-z0-9-]+\/?)+$/', $slugOrPath)) {
$slugOrPath = urldecode($slugOrPath);
// support url for chinese, japanese, arbic and english with numbers.
if (preg_match('/^([\x{0621}-\x{064A}\x{4e00}-\x{9fa5}\x{3402}-\x{FA6D}\x{3041}-\x{30A0}\x{30A0}-\x{31FF}_a-z0-9-]+\/?)+$/u', $slugOrPath)) {
if ($category = $this->categoryRepository->findByPath($slugOrPath)) {
@ -71,7 +74,7 @@ class ProductsCategoriesProxyController extends Controller
}
$sliderRepository = app('Webkul\Core\Repositories\SliderRepository');
$sliderData = $sliderRepository
->where('channel_id', core()->getCurrentChannel()->id)
->where('locale', core()->getCurrentLocale()->code)

View File

@ -31,6 +31,9 @@ class ShopServiceProvider extends ServiceProvider
], 'public');
$this->loadViewsFrom(__DIR__ . '/../Resources/views', 'shop');
$this->publishes([
__DIR__ . '/../Resources/views' => resource_path('themes/shop/views'),
]);
$router->aliasMiddleware('locale', Locale::class);
$router->aliasMiddleware('theme', Theme::class);

View File

@ -1,7 +1,6 @@
<template>
<transition name="slide">
<div class="slider-content" v-if="images.length > 0">
<ul class="slider-images">
<li v-for="(image, index) in images" :key="index" v-bind:class="{'show': index==currentIndex}">
<a :href="image.slider_path">
@ -19,10 +18,29 @@
</transition>
</template>
<style lang="scss">
.slider-control {
direction: ltr;
}
.slide-enter-active {
transition: all 0.2s cubic-bezier(0.55, 0.085, 0.68, 0.53);
}
.slide-leave-active {
transition: all 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.slide-enter, .slide-leave-to {
-webkit-transform: scaleY(0) translateZ(0);
transform: scaleY(0) translateZ(0);
opacity: 0;
}
</style>
<script>
export default {
props:{
props: {
slides: {
type: Array,
required: true,
@ -36,16 +54,11 @@ export default {
},
data() {
return {
images: [],
currentIndex: -1,
content: [],
current: false,
images_loaded: false,
};
},
@ -55,7 +68,6 @@ export default {
},
methods: {
getProps() {
this.setProps();
},
@ -85,34 +97,18 @@ export default {
changeIndexLeft: function() {
if (this.currentIndex > 0) {
this.currentIndex--;
} else if(this.currentIndex == 0) {
} else if (this.currentIndex == 0) {
this.currentIndex = this.images.length-1;
}
},
changeIndexRight: function() {
if(this.currentIndex < this.images.length-1) {
if (this.currentIndex < this.images.length-1) {
this.currentIndex++;
} else if(this.currentIndex == this.images.length-1) {
} else if (this.currentIndex == this.images.length-1) {
this.currentIndex = 0;
}
}
}
};
</script>
<style>
.slide-enter-active {
transition: all 0.2s cubic-bezier(0.55, 0.085, 0.68, 0.53);
}
.slide-leave-active {
transition: all 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.slide-enter, .slide-leave-to {
-webkit-transform: scaleY(0) translateZ(0);
transform: scaleY(0) translateZ(0);
opacity: 0;
}
</style>
</script>

View File

@ -683,7 +683,6 @@ section.slider-block {
div.slider-content {
position: relative;
height: 500px;
margin-left: auto;
margin-right: auto;
@ -731,7 +730,7 @@ section.slider-block {
}
li img {
max-height: 500px;
height: 500px;
width: 100%;
}
}
@ -764,15 +763,36 @@ section.slider-block {
}
//responsive css for slider
@media only screen and (max-width: 770px) {
@media only screen and (max-width: 720px) {
section.slider-block {
div.slider-content {
div.slider-control {
display: flex;
justify-content:space-between;
bottom: 46%;
justify-content: space-between;
width: 100%;
bottom: 40%;
right: 0%;
}
}
}
}
@media only screen and (max-width: 420px) {
section.slider-block {
div.slider-content {
ul.slider-images {
li img {
width: 100%;
height: 250px;
}
}
div.slider-control {
display: flex;
justify-content:space-between;
width: 100%;
bottom: 40%;
right: 0%;
width:100%;
}
}
}
@ -1861,6 +1881,7 @@ section.product-detail {
font-size: 24px;
color: $font-dark;
margin-bottom: 15px;
line-height: normal;
}
.product-price {

View File

@ -442,7 +442,8 @@ return [
'available-for-order' => 'متوفر لطلب الشراء',
'settings' => 'Settings',
'compare_options' => 'قارن الخيارات',
'wishlist-options' => 'Wishlist Options'
'wishlist-options' => 'Wishlist Options',
'offers' => 'Buy :qty for :price each and save :discount%',
],
// 'reviews' => [

View File

@ -439,7 +439,8 @@ return [
'available' => 'Verfügbar',
'settings' => 'Settings',
'compare_options' => 'Compare Options',
'wishlist-options' => 'Wishlist Options'
'wishlist-options' => 'Wishlist Options',
'offers' => 'Buy :qty for :price each and save :discount%',
],
// 'reviews' => [

View File

@ -443,7 +443,8 @@ return [
'available-for-order' => 'Available for Order',
'settings' => 'Settings',
'compare_options' => 'Compare Options',
'wishlist-options' => 'Wishlist Options'
'wishlist-options' => 'Wishlist Options',
'offers' => 'Buy :qty for :price each and save :discount%',
],
// 'reviews' => [

View File

@ -412,7 +412,8 @@ return [
'available-for-order' => 'Disponible para ordenar',
'settings' => 'Settings',
'compare_options' => 'Compare Options',
'wishlist-options' => 'Wishlist Options'
'wishlist-options' => 'Wishlist Options',
'offers' => 'Buy :qty for :price each and save :discount%',
],
// 'reviews' => [

View File

@ -441,7 +441,8 @@ return [
'available-for-order' => 'Available for Order',
'settings' => 'Settings',
'compare_options' => 'Compare Options',
'wishlist-options' => 'Wishlist Options'
'wishlist-options' => 'Wishlist Options',
'offers' => 'Buy :qty for :price each and save :discount%',
],
// 'reviews' => [

View File

@ -439,7 +439,8 @@ return [
'available-for-order' => 'Disponibile per lordine',
'settings' => 'Settings',
'compare_options' => 'Compare Options',
'wishlist-options' => 'Wishlist Options'
'wishlist-options' => 'Wishlist Options',
'offers' => 'Buy :qty for :price each and save :discount%',
],
// 'reviews' => [

View File

@ -408,7 +408,8 @@ return [
'available-for-order' => '注文可能',
'settings' => 'Settings',
'compare_options' => 'Compare Options',
'wishlist-options' => 'Wishlist Options'
'wishlist-options' => 'Wishlist Options',
'offers' => 'Buy :qty for :price each and save :discount%',
],
'buynow' => [

View File

@ -446,7 +446,8 @@ return [
'available-for-order' => 'Beschikbaar voor bestelling',
'settings' => 'Settings',
'compare_options' => 'Compare Options',
'wishlist-options' => 'Wishlist Options'
'wishlist-options' => 'Wishlist Options',
'offers' => 'Buy :qty for :price each and save :discount%',
],
// 'reviews' => [

View File

@ -439,7 +439,8 @@ return [
'available-for-order' => 'Dostępne na zamówienie',
'settings' => 'Settings',
'compare_options' => 'Compare Options',
'wishlist-options' => 'Wishlist Options'
'wishlist-options' => 'Wishlist Options',
'offers' => 'Buy :qty for :price each and save :discount%',
],
// 'reviews' => [

View File

@ -429,7 +429,8 @@ return [
'available-for-order' => 'Disponível para encomenda',
'settings' => 'Settings',
'compare_options' => 'Compare Options',
'wishlist-options' => 'Wishlist Options'
'wishlist-options' => 'Wishlist Options',
'offers' => 'Buy :qty for :price each and save :discount%',
],
// 'reviews' => [

View File

@ -439,7 +439,8 @@ return [
'available-for-order' => 'Sipariş İçin Uygun',
'settings' => 'Settings',
'compare_options' => 'Compare Options',
'wishlist-options' => 'Wishlist Options'
'wishlist-options' => 'Wishlist Options',
'offers' => 'Buy :qty for :price each and save :discount%',
],
// 'reviews' => [

View File

@ -219,10 +219,10 @@
return false;
},
validateForm: function(scope) {
validateForm: async function(scope) {
var this_this = this;
this.$validator.validateAll(scope).then(function (result) {
await this.$validator.validateAll(scope).then(function (result) {
if (result) {
if (scope == 'address-form') {
this_this.saveAddress();
@ -286,7 +286,7 @@
.catch(function (error) {})
},
saveAddress: function() {
saveAddress: async function() {
var this_this = this;
this.disable_button = true;
@ -327,7 +327,7 @@
})
},
saveShipping: function() {
saveShipping: async function() {
var this_this = this;
this.disable_button = true;
@ -351,7 +351,7 @@
})
},
savePayment: function() {
savePayment: async function() {
var this_this = this;
this.disable_button = true;
@ -373,7 +373,7 @@
});
},
placeOrder: function() {
placeOrder: async function() {
var this_this = this;
this.disable_button = true;
@ -610,4 +610,4 @@
})
</script>
@endpush
@endpush

View File

@ -76,6 +76,14 @@
{!! view_render_event('bagisto.shop.customers.account.profile.edit.email.after') !!}
<div class="control-group" :class="[errors.has('phone') ? 'has-error' : '']">
<label for="phone">{{ __('shop::app.customer.account.profile.phone') }}</label>
<input type="text" class="control" name="phone" value="{{ old('phone') ?? $customer->phone }}" data-vv-as="&quot;{{ __('shop::app.customer.account.profile.phone') }}&quot;">
<span class="control-error" v-if="errors.has('phone')">@{{ errors.first('phone') }}</span>
</div>
{!! view_render_event('bagisto.shop.customers.account.profile.edit.phone.after') !!}
<div class="control-group" :class="[errors.has('oldpassword') ? 'has-error' : '']">
<label for="password">{{ __('shop::app.customer.account.profile.opassword') }}</label>
<input type="password" class="control" name="oldpassword" data-vv-as="&quot;{{ __('shop::app.customer.account.profile.opassword') }}&quot;" v-validate="'min:6'">
@ -101,7 +109,7 @@
</div>
<div class="control-group">
<input type="checkbox" id="checkbox2" name="subscribed_to_news_letter" value="{{ $customer->subscribed_to_news_letter }}" {{ $customer->subscribed_to_news_letter ? 'checked' : ''}}>
<input type="checkbox" id="checkbox2" name="subscribed_to_news_letter"@if (isset($customer->subscription)) value="{{ $customer->subscription->is_subscribed }}" {{ $customer->subscription->is_subscribed ? 'checked' : ''}} @endif>
<span>{{ __('shop::app.customer.signup-form.subscribe-to-newsletter') }}</span>
</div>

View File

@ -11,7 +11,13 @@
@foreach (app('Webkul\Product\Repositories\ProductRepository')->getFeaturedProducts() as $productFlat)
@include ('shop::products.list.card', ['product' => $productFlat])
@if (core()->getConfigData('catalog.products.homepage.out_of_stock_items'))
@include ('shop::products.list.card', ['product' => $productFlat])
@else
@if ($productFlat->isSaleable())
@include ('shop::products.list.card', ['product' => $productFlat])
@endif
@endif
@endforeach

View File

@ -40,7 +40,13 @@
@section('content-wrapper')
{!! view_render_event('bagisto.shop.home.content.before') !!}
{!! DbView::make($channel)->field('home_page_content')->with(['sliderData' => $sliderData])->render() !!}
@if (! is_null($channel->home_page_content))
{!! DbView::make($channel)->field('home_page_content')->with(['sliderData' => $sliderData])->render() !!}
@else
@include('shop::home.slider', ['sliderData' => $sliderData])
@include('shop::home.featured-products')
@include('shop::home.new-products')
@endif
{{ view_render_event('bagisto.shop.home.content.after') }}

View File

@ -11,7 +11,13 @@
@foreach (app('Webkul\Product\Repositories\ProductRepository')->getNewProducts() as $productFlat)
@include ('shop::products.list.card', ['product' => $productFlat])
@if (core()->getConfigData('catalog.products.homepage.out_of_stock_items'))
@include ('shop::products.list.card', ['product' => $productFlat])
@else
@if ($productFlat->isSaleable())
@include ('shop::products.list.card', ['product' => $productFlat])
@endif
@endif
@endforeach

View File

@ -1,5 +1,5 @@
@if (count($sliderData))
<section class="slider-block" style="height: 500px">
<section class="slider-block">
<image-slider :slides='@json($sliderData)' public_path="{{ url()->to('/') }}"></image-slider>
</section>
@endif

View File

@ -63,6 +63,14 @@
@include ('shop::products.price', ['product' => $product])
@if (count($product->getTypeInstance()->getCustomerGroupPricingOffers()) > 0)
<div class="regular-price">
@foreach ($product->getTypeInstance()->getCustomerGroupPricingOffers() as $offers)
<p> {{ $offers }} </p>
@endforeach
</div>
@endif
@include ('shop::products.view.stock', ['product' => $product])
{!! view_render_event('bagisto.shop.products.view.short_description.before', ['product' => $product]) !!}

View File

@ -275,12 +275,15 @@
var priceLabelElement = document.querySelector('.price-label');
var priceElement = document.querySelector('.final-price');
var regularPriceElement = document.querySelector('.regular-price');
if (this.childAttributes.length == selectedOptionCount) {
priceLabelElement.style.display = 'none';
priceElement.innerHTML = this.config.variant_prices[this.simpleProduct].final_price.formated_price;
regularPriceElement.innerHTML = this.config.variant_prices[this.simpleProduct].regular_price.formated_price;
eventBus.$emit('configurable-variant-selected-event', this.simpleProduct)
} else {
priceLabelElement.style.display = 'inline-block';

View File

@ -21,15 +21,13 @@
<span>{{ __('shop::app.search.no-results') }}</span>
</div>
@else
@if ($results->total() == 1)
<div class="search-result-status mb-20">
<span><b>{{ $results->total() }} </b>{{ __('shop::app.search.found-result') }}</span>
</div>
@else
<div class="search-result-status mb-20">
<span><b>{{ $results->total() }} </b>{{ __('shop::app.search.found-results') }}</span>
</div>
@endif
<div class="search-result-status mb-20">
<span>
<b>{{ $results->total() }} </b>
{{ ($results->total() == 1) ? __('shop::app.search.found-result') : __('shop::app.search.found-results') }}
</span>
</div>
<div class="product-grid-4">
@foreach ($results as $productFlat)

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,18 +1,18 @@
/* flatpickr v4.6.6, @license MIT */
/* flatpickr v4.6.3, @license MIT */
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
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.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/**

View File

@ -1,4 +1,4 @@
{
"/js/ui.js": "/js/ui.js?id=2cf17b86ea451828fd09",
"/css/ui.css": "/css/ui.css?id=5673703005b2ac3d0889"
"/js/ui.js": "/js/ui.js?id=9480d375da1da8eb3366",
"/css/ui.css": "/css/ui.css?id=6555a7029beea2bc5c1e"
}

View File

@ -7,14 +7,14 @@ use Illuminate\Support\Facades\Event;
abstract class DataGrid
{
/**
* set index columns, ex: id.
* Set index columns, ex: id.
*
* @var int
*/
protected $index;
/**
* Default sort order of datagrid
* Default sort order of datagrid.
*
* @var string
*/
@ -29,14 +29,14 @@ abstract class DataGrid
protected $enableFilterMap = false;
/**
* This is array where aliases and custom column's name are passed
* This is array where aliases and custom column's name are passed.
*
* @var array
*/
protected $filterMap = [];
/**
* array to hold all the columns which will be displayed on frontend.
* Array to hold all the columns which will be displayed on frontend.
*
* @var array
*/
@ -44,13 +44,15 @@ abstract class DataGrid
/**
* Complete column details.
*
* @var array
*/
protected $completeColumnDetails = [];
/**
* Hold query builder instance of the query prepared by executing datagrid
* class method setQueryBuilder
* class method `setQueryBuilder`.
*
* @var array
*/
@ -80,7 +82,7 @@ abstract class DataGrid
protected $massActions = [];
/**
* Parsed value of the url parameters
* Parsed value of the url parameters.
*
* @var array
*/
@ -99,7 +101,7 @@ abstract class DataGrid
protected $enableAction = false;
/**
* paginate the collection or not
* Paginate the collection or not.
*
* @var bool
*/
@ -113,70 +115,91 @@ abstract class DataGrid
protected $itemsPerPage = 10;
/**
* Operators mapping.
*
* @var array
*/
protected $operators = [
'eq' => "=",
'lt' => "<",
'gt' => ">",
'lte' => "<=",
'gte' => ">=",
'neqs' => "<>",
'neqn' => "!=",
'eqo' => "<=>",
'like' => "like",
'blike' => "like binary",
'nlike' => "not like",
'ilike' => "ilike",
'and' => "&",
'bor' => "|",
'regex' => "regexp",
'notregex' => "not regexp",
'eq' => '=',
'lt' => '<',
'gt' => '>',
'lte' => '<=',
'gte' => '>=',
'neqs' => '<>',
'neqn' => '!=',
'eqo' => '<=>',
'like' => 'like',
'blike' => 'like binary',
'nlike' => 'not like',
'ilike' => 'ilike',
'and' => '&',
'bor' => '|',
'regex' => 'regexp',
'notregex' => 'not regexp',
];
/**
* Bindings.
*
* @var array
*/
protected $bindings = [
0 => "select",
1 => "from",
2 => "join",
3 => "where",
4 => "having",
5 => "order",
6 => "union",
0 => 'select',
1 => 'from',
2 => 'join',
3 => 'where',
4 => 'having',
5 => 'order',
6 => 'union',
];
/**
* Select components.
*
* @var array
*/
protected $selectcomponents = [
0 => "aggregate",
1 => "columns",
2 => "from",
3 => "joins",
4 => "wheres",
5 => "groups",
6 => "havings",
7 => "orders",
8 => "limit",
9 => "offset",
10 => "lock",
0 => 'aggregate',
1 => 'columns',
2 => 'from',
3 => 'joins',
4 => 'wheres',
5 => 'groups',
6 => 'havings',
7 => 'orders',
8 => 'limit',
9 => 'offset',
10 => 'lock',
];
/** @var string[] contains the keys for which extra filters to show */
/**
* Contains the keys for which extra filters to show.
*
* @var string[]
*/
protected $extraFilters = [];
/**
* The current admin user.
*
* @var object
*/
protected $currentUser;
abstract public function prepareQueryBuilder();
abstract public function addColumns();
/**
* Create datagrid instance.
*
* @return void
*/
public function __construct()
{
$this->invoker = $this;
$this->currentUser = auth()->guard('admin')->user();
}
/**
@ -189,7 +212,7 @@ abstract class DataGrid
$parsedUrl = [];
$unparsed = url()->full();
$route = request()->route() ? request()->route()->getName() : "";
$route = request()->route() ? request()->route()->getName() : '';
if ($route == 'admin.datagrid.export') {
$unparsed = url()->previous();
@ -218,7 +241,7 @@ abstract class DataGrid
}
/**
* Add the index as alias of the column and use the column to make things happen
* Add the index as alias of the column and use the column to make things happen.
*
* @param string $alias
* @param string $column
@ -233,6 +256,8 @@ abstract class DataGrid
}
/**
* Add column.
*
* @param string $column
*
* @return void
@ -249,6 +274,8 @@ abstract class DataGrid
}
/**
* Set complete column details.
*
* @param string $column
*
* @return void
@ -259,6 +286,8 @@ abstract class DataGrid
}
/**
* Set query builder.
*
* @param \Illuminate\Database\Query\Builder $queryBuilder
*
* @return void
@ -269,12 +298,16 @@ abstract class DataGrid
}
/**
* Add action.
*
* @param array $action
*
* @return void
*/
public function addAction($action)
{
$currentRouteACL = $this->fetchCurrentRouteACL($action);
if (isset($action['title'])) {
$eventName = strtolower($action['title']);
$eventName = explode(' ', $eventName);
@ -283,22 +316,29 @@ abstract class DataGrid
$eventName = null;
}
$this->fireEvent('action.before.' . $eventName);
if (bouncer()->hasPermission($currentRouteACL['key'] ?? null)) {
$this->fireEvent('action.before.' . $eventName);
array_push($this->actions, $action);
array_push($this->actions, $action);
$this->enableAction = true;
$this->enableAction = true;
$this->fireEvent('action.after.' . $eventName);
$this->fireEvent('action.after.' . $eventName);
}
}
/**
* Add mass action.
*
* @param array $massAction
*
* @return void
*/
public function addMassAction($massAction)
{
$massAction['route'] = $this->getRouteNameFromUrl($massAction['action'], $massAction['method']);
$currentRouteACL = $this->fetchCurrentRouteACL($massAction);
if (isset($massAction['label'])) {
$eventName = strtolower($massAction['label']);
$eventName = explode(' ', $eventName);
@ -307,16 +347,19 @@ abstract class DataGrid
$eventName = null;
}
$this->fireEvent('mass.action.before.' . $eventName);
if (bouncer()->hasPermission($currentRouteACL['key'] ?? null)) {
$this->fireEvent('mass.action.before.' . $eventName);
$this->massActions[] = $massAction;
$this->massActions[] = $massAction;
$this->enableMassAction = true;
$this->enableMassAction = true;
$this->fireEvent('mass.action.after.' . $eventName);
$this->fireEvent('mass.action.after.' . $eventName);
}
}
/**
* Get collections.
*
* @return \Illuminate\Support\Collection
*/
public function getCollection()
@ -376,6 +419,8 @@ abstract class DataGrid
}
/**
* Sort or filter collection.
*
* @param \Illuminate\Support\Collection $collection
* @param array $parseInfo
*
@ -387,7 +432,7 @@ abstract class DataGrid
$columnType = $this->findColumnType($key)[0] ?? null;
$columnName = $this->findColumnType($key)[1] ?? null;
if ($key === "sort") {
if ($key === 'sort') {
$count_keys = count(array_keys($info));
if ($count_keys > 1) {
@ -400,7 +445,7 @@ abstract class DataGrid
$columnName[1],
array_values($info)[0]
);
} elseif ($key === "search") {
} elseif ($key === 'search') {
$count_keys = count(array_keys($info));
if ($count_keys > 1) {
@ -430,7 +475,7 @@ abstract class DataGrid
}
}
if (array_keys($info)[0] === "like" || array_keys($info)[0] === "nlike") {
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(
@ -526,7 +571,7 @@ abstract class DataGrid
);
});
}
} elseif ($this->enableFilterMap && ! isset($this->filterMap[$columnName])) {
} elseif ($this->enableFilterMap && ! isset($this->filterMap[$columnName])) {
if ($this->operators[$condition] == '=') {
if ($filter_value == 1) {
$collection->Where(function($query) use($columnName, $condition, $filter_value) {
@ -649,6 +694,8 @@ abstract class DataGrid
}
/**
* Trigger event.
*
* @param string $name
*
* @return void
@ -658,7 +705,7 @@ abstract class DataGrid
if (isset($name)) {
$className = get_class($this->invoker);
$className = last(explode("\\", $className));
$className = last(explode('\\', $className));
$className = strtolower($className);
@ -669,6 +716,8 @@ abstract class DataGrid
}
/**
* Preprare mass actions.
*
* @return void
*/
public function prepareMassActions()
@ -676,6 +725,8 @@ abstract class DataGrid
}
/**
* Prepare actions.
*
* @return void
*/
public function prepareActions()
@ -683,6 +734,8 @@ abstract class DataGrid
}
/**
* Render view.
*
* @return \Illuminate\View\View
*/
public function render()
@ -722,6 +775,8 @@ abstract class DataGrid
}
/**
* Export.
*
* @return \Illuminate\Support\Collection
*/
public function export()
@ -738,4 +793,32 @@ abstract class DataGrid
return $this->getCollection();
}
/**
* 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

@ -7,10 +7,10 @@
target.value = e.target.value.toString()
.toLowerCase()
.normalize('NFKD') // Normalize Unicode
.replace(/[^\w- ]+/g, '')
.replace(/[^\w\u0621-\u064A\u4e00-\u9fa5\u3402-\uFA6D\u3041-\u30A0\u30A0-\u31FF- ]+/g, '')
// replace whitespaces with dashes
.replace(/ +/g, '-')

View File

@ -6,7 +6,7 @@
e.target.value = e.target.value
.toString()
.toLowerCase()
.replace(/[^\w- ]+/g, '')
.replace(/[^\w\u0621-\u064A\u4e00-\u9fa5\u3402-\uFA6D\u3041-\u30A0\u30A0-\u31FF- ]+/g, '')
// replace whitespaces with dashes
.replace(/ +/g, '-')

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