conflict resolve

This commit is contained in:
rahul shukla 2020-01-21 13:24:19 +05:30
commit e3db0b164c
311 changed files with 16969 additions and 8954 deletions

View File

@ -4,8 +4,9 @@ APP_VERSION=0.1.8
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
APP_TIMEZONE='Asia/Kolkata'
LOG_CHANNEL=stack
APP_CURRENCY=USD
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
@ -34,6 +35,7 @@ MAIL_ENCRYPTION=tls
SHOP_MAIL_FROM=
ADMIN_MAIL_TO=
MAIL_FROM_NAME=
fixer_api_key=

1
.gitignore vendored
View File

@ -15,7 +15,6 @@ npm-debug.log
yarn-error.log
.env
/ignorables/*
composer.lock
yarn.lock
package-lock.json
yarn.lock

View File

@ -2,6 +2,70 @@
#### This changelog consists the bug & security fixes and new features being included in the releases listed below.
## **v0.1.9 (20th of December, 2019)** - *Release*
* #1875 [fixed] - Discount gets applied on cart if condition is "Visible Individually" is set to yes and product added in cart is not visible individually.
* #1868 [fixed] - Getting exception on checkout if action Buy X Get Y free is selected in cart rule.
* #1838 [fixed] - Cart rule not working for condition sku(children only) and sku(parent only).
* #1835 [fixed] - Getting exception if condition value remains blank.
* #1831 [fixed] - Negative sign is not required in discount amount.
* #1830 [fixed] - If Coupon type is selected as "No Coupon" then coupon code should not generate for that particular cart rule.
* #1904 [fixed] - Existing tax should display as list on creating catalog rule if in condition "Tax Category" is selected.
* #1903 [fixed] - UI issue in condition field
* #1895 [fixed] - Translation issue Action Type field while creating catalog rule.
* #1883 [fixed] - Free shipping not applied on cart, if from action "Free Shipping" is selected and discount amount is given as zero.
* #1882 [fixed] - If from Action "Apply on shipping " is selected as yes then the discounted amount is applying on both product and shipping charge.
* #1861 [fixed] - Getting exception on checkout if applying invalid coupon code and proceed for checkout.
* #1857 [fixed] - Getting exception when creating cart rule with condition URL KEY(children only).
* #1856 [fixed] - Getting exception on creating cart rule with condition Name(children only).
* #1847 [fixed] - If cart rule condition does not match the cart then on applying coupon it should display message "Coupon cannot be applied".
* #1839 [fixed] - Getting exception on filtering cart rule through id.
* #1836 [fixed] - Back button on Edit cart rule page doesn't work.
* #1834 [fixed] - On editing any cart rule, its priority updates to 1.
* #1833 [fixed] - Discount not applied if "Payment Method", "Shipping Method", "Shipping State" or "Shipping Country" is selected in condition.
* #1832 [fixed] - Able to use coupon irrespective of the number given in "Uses per coupon" field.
* #1828 [fixed] - Updated changes are not saved on editing cart rule.
* #1825 [fixed] - Not able to generate coupon code while creating cart rule.
* #1823 [fixed] - Getting exception after clicking on developement.
* #1929 [fixed] - Actual product amount and discounted amount both should display on product page for configurable product
* #1928 [fixed] - Catalog rule should not apply if any of the condition doesn't match, if condition type"All Condition are true"
* #1931 [fixed] - Catalog rule not applying if in condition type"Any Condition is true" is selected, and some of the condition doesn't match the product.
* #1935 [fixed] - Categories are not displaying if in condition Categories(children only) or Categories(Parent Only) is selected.
* #1938 [fixed] - multiple cart rules are getting applied by using only single coupon.
* #1939 [fixed] - Invalid coupon gets applied, if clicking on apply coupon multiple time, although there is no discount amount but its displaying message that coupon code applied successfully.
* #1942 [fixed] - When editing the cart rule, selected category is not checked.
## **v0.1.8 (4th of October, 2019)** - *Release*
* [feature] - Refund is added for orders.

17
CHANGELOG for v0.2.x.md Normal file
View File

@ -0,0 +1,17 @@
# CHANGELOG for v0.2.x
#### This changelog consists the bug & security fixes and new features being included in the releases listed below.
## **v0.2.0 (23th of December, 2019)** - *Release*
* #1955 [fixed] - Message need to be changed on mouse hover on cross symbol next to applied coupon.
* #1959 [fixed] - if admin has set the same condition twice, then catalog rule is not getting apply
* #1958 [fixed] - getting exception on front end, if action type is Buy x get y free in non couponable cart rule.
* #1957 [fixed] - if action type is Fixed Amount to Whole Cart, then apply to shipping option should get hide.
* #1954 [fixed] - If any different tax category has been assigned to variants in configurable product, then while using tax category condition in cart rule, rule is not working properly.
* #1950 [fixed] - multiple catalog rule should not get get applied, if 1st one has been created as End Other Rules = yes

View File

@ -21,20 +21,20 @@
### Introduction
[Bagisto](https://www.bagisto.com) is a hand tailored E-Commerce framework designed on some of the hottest opensource technologies
such as [Laravel](https://laravel.com) a [PHP](https://secure.php.net/) framework, [Vue.js](https://vuejs.org)
[Bagisto](https://www.bagisto.com) is a hand tailored E-Commerce framework built on some of the hottest opensource technologies
such as [Laravel](https://laravel.com) (a [PHP](https://secure.php.net/) framework) and [Vue.js](https://vuejs.org)
a progressive Javascript framework.
**Bagisto is viable attempt to cut down your time, cost and workforce for building online stores or migrating from physical stores
to the ever demanding online world. Your business whether small or huge it suits all and very simple to set it up.**
**Bagisto can help you to cut down your time, cost, and workforce for building online stores or migrating from physical stores
to the ever demanding online world. Your business -- whether small or huge -- can benefit. And it's very simple to set it up.**
**Read our documentation: [Bagisto Docs](https://devdocs.bagisto.com/)**
**We are also having a forum for any type of your concern, feature request discussions. Please visit: [Bagisto Forums](https://forums.bagisto.com/)**
**We also have a forum for any type of concerns, feature requests, or discussions. Please visit: [Bagisto Forums](https://forums.bagisto.com/)**
# Visit our live [Demo](https://demo.bagisto.com)
It packs in lots of demanding features that allows your business to scale in no time:
It packs in lots of features that will allow your E-Commerce business to scale in no time:
* Multiple Channels, Locale, Currencies.
* Built-in Access Control Layer.
@ -50,11 +50,10 @@ It packs in lots of demanding features that allows your business to scale in no
* Simple and Configurable Products.
* Price rules (Discount) inbuilt.
* CMS Pages.
* Check out [click here](https://bagisto.com/features/).
* Check out [these features and more](https://bagisto.com/features/).
**For Developers**:
Dev guys can take advantage of two of the hottest frameworks used in this project Laravel and Vue.js, both of these frameworks have been used in Bagisto.
Bagisto is using power of both of these frameworks and making best out of it out of the box.
Take advantage of two of the hottest frameworks used in this project -- Laravel and Vue.js -- both of which have been used in Bagisto.
### Documentation
@ -80,7 +79,7 @@ Bagisto is using power of both of these frameworks and making best out of it out
[Download](https://github.com/bagisto/bagisto/archive/v0.1.6.zip)
##### b. Extract the contents of zip and execute the project in browser:
##### b. Extract the contents of zip and execute the project in your browser:
~~~
http(s)://localhost/bagisto/public
@ -94,15 +93,15 @@ http(s)://example.com/public
**2. Try our old fashioned way to install Bagisto:**
##### Execute these commands below as in their order
##### Execute these commands below, in order
~~~
1. composer create-project bagisto/bagisto
~~~
**Now configure your database:**
**Now, configure your database:**
If the above command was completed successfully, then you'll find directory **bagisto** and all of the code will be inside it.
If the above command was completed successfully, then you'll find directory **bagisto** with all of the code inside it.
Find file **.env** inside **bagisto** directory and set the environment variables listed below:
@ -114,7 +113,7 @@ Find file **.env** inside **bagisto** directory and set the environment variable
* **DB_USERNAME**
* **DB_PASSWORD**
Although, mailer environment variables are also required to be set up as **Bagisto** requires emails to send to customers and admins for various functionalities that are built in.
Mailer environment variables are also required to be set up. This is because **Bagisto** needs to send emails to customers and admins depending on what events require notification.
~~~
2. php artisan migrate
@ -142,13 +141,13 @@ Although, mailer environment variables are also required to be set up as **Bagis
##### On server:
Warning: Before going full on production mode we recommend you to uninstall developer dependencies.
Warning: Before going into production mode we recommend you uninstall developer dependencies.
In order to do that, run the command below:
> composer install --no-dev
~~~
Open the specified entry point in your hosts file in browser or make entry in hosts file if not done.
Open the specified entry point in your hosts file in your browser or make an entry in hosts file if not done.
~~~
##### On local:
@ -178,13 +177,13 @@ password:admin123
Bagisto is a truly opensource E-Commerce framework which will always be free under the [MIT License](https://github.com/bagisto/bagisto/blob/master/LICENSE).
### Security Vulnerabilities
Please don't disclose security vulnerabilities publicly. If you find any security vulnerability in Bagisto then please write us mail: mailto:support@bagisto.com.
Please don't disclose security vulnerabilities publicly. If you find any security vulnerability in Bagisto then please email us: mailto:support@bagisto.com.
### Miscellaneous
#### Contributors
This project is on [Open Collective](https://opencollective.com/bagisto) and it exists thanks to this people who contribute.
This project is on [Open Collective](https://opencollective.com/bagisto) and it exists thanks to the people who contribute.
<a href="https://github.com/bagisto/bagisto/graphs/contributors"><img src="https://opencollective.com/bagisto/contributors.svg?width=890&button=false"/></a>

View File

@ -0,0 +1,119 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Artisan;
class install extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'bagisto:install';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Run migrate and seed command, publish assets and config, link storage';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Install and configure bagisto
*/
public function handle()
{
$this->checkForEnvFile();
// running `php artisan migrate`
$this->warn('Step: Migrating all tables into database...');
$migrate = shell_exec('php artisan migrate:fresh');
$this->info($migrate);
// running `php artisan db:seed`
$this->warn('Step: seeding basic data for bagisto kickstart...');
$result = shell_exec('php artisan db:seed');
$this->info($result);
// running `php artisan vendor:publish --all`
$this->warn('Step: Publishing Assets and Configurations...');
$result = shell_exec('php artisan vendor:publish --all');
$this->info($result);
// running `php artisan storage:link`
$this->warn('Step: Linking Storage directory...');
$result = shell_exec('php artisan storage:link');
$this->info($result);
// running `composer dump-autoload`
$this->warn('Step: Composer Autoload...');
$result = shell_exec('composer dump-autoload');
$this->info($result);
$this->info('-----------------------------');
$this->info('Now, run `php artisan serve` to start using Bagisto');
$this->info('Cheers!');
}
/**
* Checking .env file and if not found then create .env file.
* Then ask for database name, password & username to set
* On .env file so that we can easily migrate to our db
*/
public function checkForEnvFile()
{
$envExists = File::exists(base_path() . '/.env');
if (!$envExists) {
$this->info('Creating .env file');
$this->createEnvFile();
} else {
$this->info('Great! .env file aready exists');
}
}
public function createEnvFile()
{
try {
File::copy('.env.example', '.env');
Artisan::call('key:generate');
$this->envUpdate('APP_URL=http://localhost', ':8000');
$this->addDatabaseDetails();
} catch (\Exception $e) {
$this->error('Error in creating .env file, please create manually and then run `php artisan migrate` again');
}
}
public function addDatabaseDetails()
{
$dbName = $this->ask('What is your database name to be used by bagisto');
$dbUser = $this->anticipate('What is your database username', ['root']);
$dbPass = $this->secret('What is your database password');
$this->envUpdate('DB_DATABASE=', $dbName);
$this->envUpdate('DB_USERNAME=', $dbUser);
$this->envUpdate('DB_PASSWORD=', $dbPass);
}
public static function envUpdate($key, $value)
{
$path = base_path() . '/.env';
file_put_contents($path, str_replace(
$key,
$key . $value,
file_get_contents($path)
));
}
}

View File

@ -70,33 +70,35 @@
},
"autoload": {
"classmap": [
"database/seeds",
"database/factories"
],
"psr-4": {
"App\\": "app/",
"Webkul\\User\\": "packages/Webkul/User/src",
"Webkul\\Admin\\": "packages/Webkul/Admin/src",
"Webkul\\Ui\\": "packages/Webkul/Ui/src",
"Webkul\\Category\\": "packages/Webkul/Category/src",
"Webkul\\Checkout\\": "packages/Webkul/Checkout/src",
"Webkul\\Attribute\\": "packages/Webkul/Attribute/src",
"Webkul\\Shop\\": "packages/Webkul/Shop/src",
"Webkul\\Core\\": "packages/Webkul/Core/src",
"Webkul\\Customer\\": "packages/Webkul/Customer/src",
"Webkul\\Inventory\\": "packages/Webkul/Inventory/src",
"Webkul\\Product\\": "packages/Webkul/Product/src",
"Webkul\\Theme\\": "packages/Webkul/Theme/src",
"Webkul\\Shipping\\": "packages/Webkul/Shipping/src",
"Webkul\\Payment\\": "packages/Webkul/Payment/src",
"Webkul\\Paypal\\": "packages/Webkul/Paypal/src",
"Webkul\\Sales\\": "packages/Webkul/Sales/src",
"Webkul\\Tax\\": "packages/Webkul/Tax/src",
"Webkul\\API\\": "packages/Webkul/API",
"Webkul\\Discount\\": "packages/Webkul/Discount/src",
"Webkul\\CMS\\": "packages/Webkul/CMS/src"
}
"classmap": [
"database/seeds",
"database/factories"
],
"psr-4": {
"App\\": "app/",
"Webkul\\User\\": "packages/Webkul/User/src",
"Webkul\\Admin\\": "packages/Webkul/Admin/src",
"Webkul\\Ui\\": "packages/Webkul/Ui/src",
"Webkul\\Category\\": "packages/Webkul/Category/src",
"Webkul\\Checkout\\": "packages/Webkul/Checkout/src",
"Webkul\\Attribute\\": "packages/Webkul/Attribute/src",
"Webkul\\Shop\\": "packages/Webkul/Shop/src",
"Webkul\\Core\\": "packages/Webkul/Core/src",
"Webkul\\Customer\\": "packages/Webkul/Customer/src",
"Webkul\\Inventory\\": "packages/Webkul/Inventory/src",
"Webkul\\Product\\": "packages/Webkul/Product/src",
"Webkul\\Theme\\": "packages/Webkul/Theme/src",
"Webkul\\Shipping\\": "packages/Webkul/Shipping/src",
"Webkul\\Payment\\": "packages/Webkul/Payment/src",
"Webkul\\Paypal\\": "packages/Webkul/Paypal/src",
"Webkul\\Sales\\": "packages/Webkul/Sales/src",
"Webkul\\Tax\\": "packages/Webkul/Tax/src",
"Webkul\\API\\": "packages/Webkul/API",
"Webkul\\CatalogRule\\": "packages/Webkul/CatalogRule/src",
"Webkul\\CartRule\\": "packages/Webkul/CartRule/src",
"Webkul\\Rule\\": "packages/Webkul/Rule/src",
"Webkul\\CMS\\": "packages/Webkul/CMS/src"
}
},
"autoload-dev": {
@ -132,7 +134,8 @@
"set -e",
"@php artisan migrate:fresh --env=testing",
"vendor/bin/codecept run unit",
"vendor/bin/codecept run functional"
"vendor/bin/codecept run functional",
"vendor/bin/codecept run trigger"
]
},
"config": {

7885
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -65,7 +65,7 @@ return [
|
*/
'timezone' => 'Asia/Kolkata',
'timezone' => env('APP_TIMEZONE','Asia/Kolkata'),
/*
|--------------------------------------------------------------------------
@ -102,7 +102,7 @@ return [
|
*/
'currency' => 'USD',
'currency' => env('APP_CURRENCY','USD'),
/*
|--------------------------------------------------------------------------
@ -219,6 +219,8 @@ return [
//Laravel Maatwebsite
Maatwebsite\Excel\ExcelServiceProvider::class,
Barryvdh\Debugbar\ServiceProvider::class,
//Repository
Prettus\Repository\Providers\RepositoryServiceProvider::class,
Konekt\Concord\ConcordServiceProvider::class,
@ -245,7 +247,9 @@ return [
Webkul\Sales\Providers\SalesServiceProvider::class,
Webkul\Tax\Providers\TaxServiceProvider::class,
Webkul\API\Providers\APIServiceProvider::class,
Webkul\Discount\Providers\DiscountServiceProvider::class,
Webkul\CatalogRule\Providers\CatalogRuleServiceProvider::class,
Webkul\CartRule\Providers\CartRuleServiceProvider::class,
Webkul\Rule\Providers\RuleServiceProvider::class,
Webkul\CMS\Providers\CMSServiceProvider::class
],

View File

@ -19,7 +19,8 @@ return [
\Webkul\Sales\Providers\ModuleServiceProvider::class,
\Webkul\Tax\Providers\ModuleServiceProvider::class,
\Webkul\User\Providers\ModuleServiceProvider::class,
\Webkul\Discount\Providers\ModuleServiceProvider::class,
\Webkul\CatalogRule\Providers\ModuleServiceProvider::class,
\Webkul\CartRule\Providers\ModuleServiceProvider::class,
\Webkul\CMS\Providers\ModuleServiceProvider::class
]
];

0
config/modules.php Executable file → Normal file
View File

View File

@ -10,14 +10,17 @@
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"axios": "^0.18",
"cross-env": "^5.1.4",
"laravel-mix": "^2.1",
"laravel-mix-merge-manifest": "^0.1.1",
"jquery": "^3.2",
"vue": "^2.1.10"
"axios": "^0.19.0",
"cross-env": "^6.0.3",
"jquery": "^3.4.1",
"laravel-mix": "^5.0.0",
"laravel-mix-merge-manifest": "^0.1.2",
"sass": "^1.24.4",
"sass-loader": "^8.0.2",
"vue": "^2.6.10",
"vue-template-compiler": "^2.6.11"
},
"dependencies": {
"vee-validate": "2.0.0-rc.26"
"vee-validate": "^2.2.15"
}
}

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/admin.js": "/js/admin.js?id=1a04ed2a8f0437dbe740",
"/css/admin.css": "/css/admin.css?id=c845e7c275d4df7fa03f"
"/js/admin.js": "/js/admin.js?id=7da533d2597c7e84df97",
"/css/admin.css": "/css/admin.css?id=9a8c6ebe5e08965b7ae6"
}

View File

@ -394,27 +394,27 @@ return [
], [
'key' => 'promotions',
'name' => 'admin::app.acl.promotions',
'route' => 'admin.cart-rule.index',
'route' => 'admin.cart-rules.index',
'sort' => 7
], [
'key' => 'promotions.cart-rule',
'key' => 'promotions.cart-rules',
'name' => 'admin::app.acl.cart-rules',
'route' => 'admin.cart-rule.index',
'route' => 'admin.cart-rules.index',
'sort' => 1
], [
'key' => 'promotions.cart-rule.create',
'key' => 'promotions.cart-rules.create',
'name' => 'admin::app.acl.create',
'route' => 'admin.cart-rule.create',
'route' => 'admin.cart-rules.create',
'sort' => 1
], [
'key' => 'promotions.cart-rule.edit',
'key' => 'promotions.cart-rules.edit',
'name' => 'admin::app.acl.edit',
'route' => 'admin.cart-rule.edit',
'route' => 'admin.cart-rules.edit',
'sort' => 2
], [
'key' => 'promotions.cart-rule.delete',
'key' => 'promotions.cart-rules.delete',
'name' => 'admin::app.acl.delete',
'route' => 'admin.cart-rule.delete',
'route' => 'admin.cart-rules.delete',
'sort' => 3
],
];

View File

@ -182,29 +182,23 @@ return [
'sort' => 2,
'icon-class' => ''
], [
'key' => 'settings.development',
'name' => 'admin::app.settings.development.title',
'route' => 'admin.development.index',
'sort' => 8,
'icon-class' => ''
],[
'key' => 'promotions',
'name' => 'admin::app.layouts.promotion',
'route' => 'admin.cart-rule.index',
'name' => 'admin::app.layouts.promotions',
'route' => 'admin.catalog-rules.index',
'sort' => 5,
'icon-class' => 'promotion-icon'
], [
'key' => 'promotions.cart-rule',
'name' => 'admin::app.promotion.cart-rule',
'route' => 'admin.cart-rule.index',
'key' => 'promotions.catalog-rules',
'name' => 'admin::app.promotions.catalog-rules.title',
'route' => 'admin.catalog-rules.index',
'sort' => 1,
'icon-class' => ''
], [
'key' => 'promotions.catalog-rule',
'name' => 'admin::app.promotion.catalog-rule',
'route' => 'admin.catalog-rule.index',
'sort' => 1,
'icon-class' => '',
'key' => 'promotions.cart-rules',
'name' => 'admin::app.promotions.cart-rules.title',
'route' => 'admin.cart-rules.index',
'sort' => 2,
'icon-class' => ''
], [
'key' => 'cms',
'name' => 'admin::app.layouts.cms',

View File

@ -76,6 +76,7 @@ return [
'title' => 'admin::app.admin.system.logo-image',
'type' => 'image',
'channel_based' => true,
'validation' => 'mimes:jpeg,bmp,png,jpg'
]
]
], [
@ -156,5 +157,5 @@ return [
'type' => 'boolean'
]
],
],
],
];

View File

@ -52,7 +52,7 @@ class AddressDataGrid extends DataGrid
$queryBuilder = DB::table('customer_addresses as ca')
->leftJoin('countries', 'ca.country', '=', 'countries.code')
->leftJoin('customers as c', 'ca.customer_id', '=', 'c.id')
->addSelect('ca.id as address_id', 'ca.address1', 'ca.country', DB::raw(''.DB::getTablePrefix().'countries.name as country_name'), 'ca.state', 'ca.city', 'ca.postcode', 'ca.phone', 'ca.default_address')
->addSelect('ca.id as address_id', 'ca.address1', 'ca.country', DB::raw('' . DB::getTablePrefix() . 'countries.name as country_name'), 'ca.state', 'ca.city', 'ca.postcode', 'ca.phone', 'ca.default_address')
->where('c.id', $customer->id);
$queryBuilder = $queryBuilder->leftJoin('country_states', function($qb) {
@ -62,13 +62,13 @@ class AddressDataGrid extends DataGrid
$queryBuilder
->groupBy('ca.id')
->addSelect(DB::raw(''.DB::getTablePrefix().'country_states.default_name as state_name'));
->addSelect(DB::raw(DB::getTablePrefix() . 'country_states.default_name as state_name'));
$this->addFilter('address_id', 'ca.id');
$this->addFilter('address1', 'ca.address1');
$this->addFilter('city', 'ca.city');
$this->addFilter('state_name', DB::raw(''.DB::getTablePrefix().'country_states.default_name'));
$this->addFilter('country_name', DB::raw(''.DB::getTablePrefix().'countries.name'));
$this->addFilter('state_name', DB::raw(DB::getTablePrefix() . 'country_states.default_name'));
$this->addFilter('country_name', DB::raw(DB::getTablePrefix() . 'countries.name'));
$this->addFilter('postcode', 'ca.postcode');
$this->addFilter('default_address', 'ca.default_address');

View File

@ -13,23 +13,26 @@ use DB;
*/
class CMSPageDataGrid extends DataGrid
{
protected $index = 'id'; //the column that needs to be treated as index column
protected $index = 'id';
protected $sortOrder = 'desc'; //asc or desc
protected $sortOrder = 'desc';
public function prepareQueryBuilder()
{
$queryBuilder = DB::table('cms_pages')->select('id', 'url_key', 'page_title', 'channel_id', 'locale_id');
$queryBuilder = DB::table('cms_pages')
->select('cms_pages.id', 'cms_page_translations.page_title', 'cms_page_translations.url_key')
->leftJoin('cms_page_translations', function($leftJoin) {
$leftJoin->on('cms_pages.id', '=', 'cms_page_translations.cms_page_id')
->where('cms_page_translations.locale', app()->getLocale());
});
$this->addFilter('id', 'cms_pages.id');
$this->setQueryBuilder($queryBuilder);
}
public function addColumns()
{
$channels = app('Webkul\Core\Repositories\ChannelRepository');
$locales = app('Webkul\Core\Repositories\LocaleRepository');
$this->addColumn([
'index' => 'id',
'label' => trans('admin::app.datagrid.id'),
@ -39,15 +42,6 @@ class CMSPageDataGrid extends DataGrid
'filterable' => true
]);
$this->addColumn([
'index' => 'url_key',
'label' => trans('admin::app.datagrid.url-key'),
'type' => 'string',
'searchable' => true,
'sortable' => true,
'filterable' => true
]);
$this->addColumn([
'index' => 'page_title',
'label' => trans('admin::app.cms.pages.page-title'),
@ -58,45 +52,26 @@ class CMSPageDataGrid extends DataGrid
]);
$this->addColumn([
'index' => 'locale_id',
'label' => trans('admin::app.cms.pages.locale'),
'type' => 'number',
'searchable' => false,
'index' => 'url_key',
'label' => trans('admin::app.datagrid.url-key'),
'type' => 'string',
'searchable' => true,
'sortable' => true,
'filterable' => true,
'wrapper' => function($row) use($locales) {
$localeCode = $locales->find($row->locale_id)->code;
return $row->locale_id.' ('. $localeCode. ')';
}
]);
$this->addColumn([
'index' => 'channel_id',
'label' => trans('admin::app.cms.pages.channel'),
'type' => 'number',
'searchable' => false,
'sortable' => true,
'filterable' => true,
'wrapper' => function($row) use($channels) {
$channelCode = $channels->find($row->channel_id)->name;
return $row->channel_id.' ('. $channelCode. ')';
}
'filterable' => true
]);
}
public function prepareActions() {
$this->addAction([
'title' => 'Edit CMSPage',
'method' => 'GET', // use GET request only for redirect purposes
'method' => 'GET',
'route' => 'admin.cms.edit',
'icon' => 'icon pencil-lg-icon'
]);
$this->addAction([
'title' => 'Delete CMSPage',
'method' => 'POST', // use GET request only for redirect purposes
'method' => 'POST',
'route' => 'admin.cms.delete',
'icon' => 'icon trash-icon'
]);

View File

@ -0,0 +1,86 @@
<?php
namespace Webkul\Admin\DataGrids;
use Webkul\Ui\DataGrid\DataGrid;
use DB;
/**
* CartRuleCouponDataGrid class
*
* @author Jitendra Singh <jitendra@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class CartRuleCouponDataGrid extends DataGrid
{
protected $index = 'id';
protected $sortOrder = 'desc';
public function prepareQueryBuilder()
{
$queryBuilder = DB::table('cart_rule_coupons')
->addSelect('id', 'code', 'created_at', 'expired_at', 'times_used')
->where('cart_rule_coupons.cart_rule_id', collect(request()->segments())->last());
$this->setQueryBuilder($queryBuilder);
}
public function addColumns()
{
$this->addColumn([
'index' => 'id',
'label' => trans('admin::app.datagrid.id'),
'type' => 'number',
'searchable' => false,
'sortable' => true,
'filterable' => true
]);
$this->addColumn([
'index' => 'code',
'label' => trans('admin::app.datagrid.coupon-code'),
'type' => 'string',
'searchable' => true,
'sortable' => true,
'filterable' => true
]);
$this->addColumn([
'index' => 'created_at',
'label' => trans('admin::app.datagrid.created-date'),
'type' => 'datetime',
'sortable' => true,
'searchable' => false,
'filterable' => true
]);
$this->addColumn([
'index' => 'expired_at',
'label' => trans('admin::app.datagrid.expiration-date'),
'type' => 'datetime',
'sortable' => true,
'searchable' => false,
'filterable' => true
]);
$this->addColumn([
'index' => 'times_used',
'label' => trans('admin::app.datagrid.times-used'),
'type' => 'number',
'searchable' => true,
'sortable' => true,
'filterable' => true
]);
}
public function prepareMassActions()
{
$this->addMassAction([
'type' => 'delete',
'action' => route('admin.cart-rule-coupons.mass-delete'),
'label' => trans('admin::app.datagrid.delete'),
'method' => 'DELETE'
]);
}
}

View File

@ -8,20 +8,27 @@ use DB;
/**
* Cart Rule DataGrid class
*
* @author Prashant Singh <prashant.singh852@webkul.com> @prashant-webkul
* @author Jitendra Singh <jitendra@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class CartRuleDataGrid extends DataGrid
{
protected $index = 'id'; //the column that needs to be treated as index column
protected $index = 'id';
protected $sortOrder = 'desc'; //asc or desc
protected $sortOrder = 'desc';
public function prepareQueryBuilder()
{
$queryBuilder = DB::table('cart_rules')
->select('id')
->addSelect('id', 'name', 'status', 'end_other_rules', 'action_type', 'disc_amount', 'use_coupon');
->leftJoin('cart_rule_coupons', function($leftJoin) {
$leftJoin->on('cart_rule_coupons.cart_rule_id', '=', 'cart_rules.id')
->where('cart_rule_coupons.is_primary', 1);
})
->addSelect('cart_rules.id', 'name', 'cart_rule_coupons.code as coupon_code', 'status', 'starts_from', 'ends_till', 'sort_order');
$this->addFilter('id', 'cart_rules.id');
$this->addFilter('coupon_code', 'cart_rule_coupons.code');
$this->setQueryBuilder($queryBuilder);
}
@ -30,7 +37,7 @@ class CartRuleDataGrid extends DataGrid
{
$this->addColumn([
'index' => 'id',
'label' => trans('admin::app.id'),
'label' => trans('admin::app.datagrid.id'),
'type' => 'number',
'searchable' => false,
'sortable' => true,
@ -39,13 +46,40 @@ class CartRuleDataGrid extends DataGrid
$this->addColumn([
'index' => 'name',
'label' => trans('admin::app.name'),
'label' => trans('admin::app.datagrid.name'),
'type' => 'string',
'searchable' => true,
'sortable' => true,
'filterable' => true
]);
$this->addColumn([
'index' => 'coupon_code',
'label' => trans('admin::app.datagrid.coupon-code'),
'type' => 'string',
'searchable' => true,
'sortable' => true,
'filterable' => true
]);
$this->addColumn([
'index' => 'starts_from',
'label' => trans('admin::app.datagrid.start'),
'type' => 'datetime',
'sortable' => true,
'searchable' => false,
'filterable' => true
]);
$this->addColumn([
'index' => 'ends_till',
'label' => trans('admin::app.datagrid.end'),
'type' => 'datetime',
'sortable' => true,
'searchable' => false,
'filterable' => true
]);
$this->addColumn([
'index' => 'status',
'label' => trans('admin::app.status'),
@ -55,89 +89,36 @@ class CartRuleDataGrid extends DataGrid
'filterable' => true,
'wrapper' => function($value) {
if ($value->status == 1)
return 'Active';
return trans('admin::app.datagrid.active');
else
return 'In Active';
return trans('admin::app.datagrid.inactive');
}
]);
$this->addColumn([
'index' => 'end_other_rules',
'label' => 'End Other Rules',
'type' => 'boolean',
'searchable' => false,
'sortable' => true,
'filterable' => true,
'wrapper' => function($value) {
if ($value->end_other_rules == 1)
return 'True';
else
return 'False';
}
]);
$this->addColumn([
'index' => 'action_type',
'label' => 'Action Type',
'type' => 'string',
'searchable' => true,
'sortable' => true,
'filterable' => true,
'wrapper' => function($value) {
return config('pricerules.cart.actions')[$value->action_type];
}
]);
$this->addColumn([
'index' => 'disc_amount',
'label' => 'Discount Amount',
'index' => 'sort_order',
'label' => trans('admin::app.datagrid.priority'),
'type' => 'number',
'searchable' => false,
'searchable' => true,
'sortable' => true,
'filterable' => true
]);
$this->addColumn([
'index' => 'use_coupon',
'label' => 'Use Coupon',
'type' => 'boolean',
'searchable' => true,
'sortable' => true,
'filterable' => true,
'wrapper' => function($value) {
if ($value->use_coupon == 1) {
return 'True';
} else {
return 'False';
}
}
]);
}
public function prepareActions()
{
$this->addAction([
'title' => 'Edit CartRule',
'method' => 'GET', //use post only for redirects only
'route' => 'admin.cart-rule.edit',
'title' => 'Edit Cart Rule',
'method' => 'GET',
'route' => 'admin.cart-rules.edit',
'icon' => 'icon pencil-lg-icon'
]);
$this->addAction([
'title' => 'Delete CartRule',
'method' => 'POST', //use post only for requests other than redirects
'route' => 'admin.cart-rule.delete',
'title' => 'Delete Cart Rule',
'method' => 'POST',
'route' => 'admin.cart-rules.delete',
'icon' => 'icon trash-icon'
]);
}
public function prepareMassActions()
{
// $this->addMassAction([
// 'type' => 'delete',
// 'action' => route('admin.catalog.attributes.massdelete'),
// 'label' => 'Delete',
// 'method' => 'DELETE'
// ]);
}
}

View File

@ -8,20 +8,19 @@ use DB;
/**
* Catalog Rule DataGrid class
*
* @author Prashant Singh <prashant.singh852@webkul.com> @prashant-webkul
* @author Jitendra Singh <jitendra@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class CatalogRuleDataGrid extends DataGrid
{
protected $index = 'id'; //the column that needs to be treated as index column
protected $index = 'id';
protected $sortOrder = 'desc'; //asc or desc
protected $sortOrder = 'desc';
public function prepareQueryBuilder()
{
$queryBuilder = DB::table('catalog_rules')
->select('id')
->addSelect('id', 'name', 'starts_from', 'ends_till', 'status', 'end_other_rules', 'action_code');
->addSelect('catalog_rules.id', 'name', 'status', 'starts_from', 'ends_till', 'sort_order');
$this->setQueryBuilder($queryBuilder);
}
@ -48,56 +47,41 @@ class CatalogRuleDataGrid extends DataGrid
$this->addColumn([
'index' => 'starts_from',
'label' => trans('admin::app.datagrid.starts-from'),
'label' => trans('admin::app.datagrid.start'),
'type' => 'datetime',
'searchable' => false,
'sortable' => true,
'searchable' => false,
'filterable' => true
]);
$this->addColumn([
'index' => 'ends_till',
'label' => trans('admin::app.datagrid.ends-till'),
'label' => trans('admin::app.datagrid.end'),
'type' => 'datetime',
'searchable' => false,
'sortable' => true,
'searchable' => false,
'filterable' => true
]);
$this->addColumn([
'index' => 'status',
'label' => trans('admin::app.datagrid.status'),
'label' => trans('admin::app.status'),
'type' => 'boolean',
'searchable' => false,
'searchable' => true,
'sortable' => true,
'filterable' => true,
'wrapper' => function ($value) {
'wrapper' => function($value) {
if ($value->status == 1)
return 'True';
return trans('admin::app.datagrid.active');
else
return 'False';
return trans('admin::app.datagrid.inactive');
}
]);
$this->addColumn([
'index' => 'end_other_rules',
'label' => 'End Other Rules',
'type' => 'boolean',
'searchable' => false,
'sortable' => true,
'filterable' => true,
'wrapper' => function ($value) {
if ($value->end_other_rules == 1)
return 'True';
else
return 'False';
}
]);
$this->addColumn([
'index' => 'action_code',
'label' => 'Action Type',
'type' => 'string',
'index' => 'sort_order',
'label' => trans('admin::app.datagrid.priority'),
'type' => 'number',
'searchable' => true,
'sortable' => true,
'filterable' => true
@ -107,27 +91,17 @@ class CatalogRuleDataGrid extends DataGrid
public function prepareActions()
{
$this->addAction([
'title' => 'Edit CatalogRule',
'method' => 'GET', //use post only for redirects only
'route' => 'admin.catalog-rule.edit',
'title' => 'Edit Catalog Rule',
'method' => 'GET',
'route' => 'admin.catalog-rules.edit',
'icon' => 'icon pencil-lg-icon'
]);
$this->addAction([
'title' => 'Delete CatalogRule',
'method' => 'POST', //use post only for requests other than redirects
'route' => 'admin.catalog-rule.delete',
'title' => 'Delete Catalog Rule',
'method' => 'POST',
'route' => 'admin.catalog-rules.delete',
'icon' => 'icon trash-icon'
]);
}
public function prepareMassActions()
{
// $this->addMassAction([
// 'type' => 'delete',
// 'action' => route('admin.catalog.attributes.massdelete'),
// 'label' => 'Delete',
// 'method' => 'DELETE'
// ]);
}
}

View File

@ -21,7 +21,7 @@ class CategoryDataGrid extends DataGrid
{
$queryBuilder = DB::table('categories as cat')
->select('cat.id as category_id', 'ct.name', 'cat.position', 'cat.status', 'ct.locale',
DB::raw('COUNT(DISTINCT '.DB::getTablePrefix().'pc.product_id) as count'))
DB::raw('COUNT(DISTINCT ' . DB::getTablePrefix() . 'pc.product_id) as count'))
->leftJoin('category_translations as ct', function($leftJoin) {
$leftJoin->on('cat.id', '=', 'ct.category_id')
->where('ct.locale', app()->getLocale());

View File

@ -25,10 +25,10 @@ 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(DB::raw('CONCAT('.DB::getTablePrefix().'customers.first_name, " ", '.DB::getTablePrefix().'customers.last_name) as full_name'));
->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('full_name', DB::raw('CONCAT(' . DB::getTablePrefix() . 'customers.first_name, " ", ' . DB::getTablePrefix() . 'customers.last_name)'));
$this->addFilter('phone', 'customers.phone');
$this->addFilter('gender', 'customers.gender');

View File

@ -29,11 +29,11 @@ class OrderDataGrid extends DataGrid
->where('order_address_billing.address_type', 'billing');
})
->addSelect('orders.id','orders.increment_id', 'orders.base_sub_total', 'orders.base_grand_total', 'orders.created_at', 'channel_name', 'status')
->addSelect(DB::raw('CONCAT('.DB::getTablePrefix().'order_address_billing.first_name, " ", '.DB::getTablePrefix().'order_address_billing.last_name) as billed_to'))
->addSelect(DB::raw('CONCAT('.DB::getTablePrefix().'order_address_shipping.first_name, " ", '.DB::getTablePrefix().'order_address_shipping.last_name) as shipped_to'));
->addSelect(DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_billing.first_name, " ", ' . DB::getTablePrefix() . 'order_address_billing.last_name) as billed_to'))
->addSelect(DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_shipping.first_name, " ", ' . DB::getTablePrefix() . 'order_address_shipping.last_name) as shipped_to'));
$this->addFilter('billed_to', DB::raw('CONCAT('.DB::getTablePrefix().'order_address_billing.first_name, " ", '.DB::getTablePrefix().'order_address_billing.last_name)'));
$this->addFilter('shipped_to', DB::raw('CONCAT('.DB::getTablePrefix().'order_address_shipping.first_name, " ", '.DB::getTablePrefix().'order_address_shipping.last_name)'));
$this->addFilter('billed_to', DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_billing.first_name, " ", ' . DB::getTablePrefix() . 'order_address_billing.last_name)'));
$this->addFilter('shipped_to', DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_shipping.first_name, " ", ' . DB::getTablePrefix() . 'order_address_shipping.last_name)'));
$this->addFilter('increment_id', 'orders.increment_id');
$this->addFilter('created_at', 'orders.created_at');

View File

@ -26,9 +26,9 @@ class OrderRefundDataGrid extends DataGrid
$leftJoin->on('order_address_billing.order_id', '=', 'orders.id')
->where('order_address_billing.address_type', 'billing');
})
->addSelect(DB::raw('CONCAT('.DB::getTablePrefix().'order_address_billing.first_name, " ", '.DB::getTablePrefix().'order_address_billing.last_name) as billed_to'));
->addSelect(DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_billing.first_name, " ", ' . DB::getTablePrefix() . 'order_address_billing.last_name) as billed_to'));
$this->addFilter('billed_to', DB::raw('CONCAT('.DB::getTablePrefix().'order_address_billing.first_name, " ", '.DB::getTablePrefix().'order_address_billing.last_name)'));
$this->addFilter('billed_to', DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_billing.first_name, " ", ' . DB::getTablePrefix() . 'order_address_billing.last_name)'));
$this->addFilter('id', 'refunds.id');
$this->addFilter('increment_id', 'orders.increment_id');
$this->addFilter('state', 'refunds.state');

View File

@ -26,16 +26,17 @@ class OrderShipmentsDataGrid extends DataGrid
})
->leftJoin('orders as ors', 'shipments.order_id', '=', 'ors.id')
->leftJoin('inventory_sources as is', 'shipments.inventory_source_id', '=', 'is.id')
->select('shipments.id as shipment_id', 'ors.increment_id as shipment_order_id', 'shipments.total_qty as shipment_total_qty', 'is.name as inventory_source_name', 'ors.created_at as order_date', 'shipments.created_at as shipment_created_at')
->addSelect(DB::raw('CONCAT('.DB::getTablePrefix().'order_address_shipping.first_name, " ", '.DB::getTablePrefix().'order_address_shipping.last_name) as shipped_to'));
->select('shipments.id as shipment_id', 'ors.increment_id as shipment_order_id', 'shipments.total_qty as shipment_total_qty', 'ors.created_at as order_date', 'shipments.created_at as shipment_created_at')
->addSelect(DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_shipping.first_name, " ", ' . DB::getTablePrefix() . 'order_address_shipping.last_name) as shipped_to'))
->selectRaw('IF(' . DB::getTablePrefix() . 'shipments.inventory_source_id IS NOT NULL,' . DB::getTablePrefix() . 'is.name, ' . DB::getTablePrefix() . 'shipments.inventory_source_name) as inventory_source_name');
$this->addFilter('shipment_id', 'shipments.id');
$this->addFilter('shipment_order_id', 'ors.increment_id');
$this->addFilter('shipment_total_qty', 'shipments.total_qty');
$this->addFilter('inventory_source_name', 'is.name');
$this->addFilter('inventory_source_name', DB::raw('IF(' . DB::getTablePrefix() . 'shipments.inventory_source_id IS NOT NULL,' . DB::getTablePrefix() . 'is.name, ' . DB::getTablePrefix() . 'shipments.inventory_source_name)'));
$this->addFilter('order_date', 'ors.created_at');
$this->addFilter('shipment_created_at', 'shipments.created_at');
$this->addFilter('shipped_to', DB::raw(''.DB::getTablePrefix().'CONCAT(order_address_shipping.first_name, " ", '.DB::getTablePrefix().'order_address_shipping.last_name)'));
$this->addFilter('shipped_to', DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_shipping.first_name, " ", ' . DB::getTablePrefix() . 'order_address_shipping.last_name)'));
$this->setQueryBuilder($queryBuilder);
}

View File

@ -25,7 +25,7 @@ class ProductDataGrid extends DataGrid
->leftJoin('products', 'product_flat.product_id', '=', 'products.id')
->leftJoin('attribute_families', 'products.attribute_family_id', '=', 'attribute_families.id')
->leftJoin('product_inventories', 'product_flat.product_id', '=', 'product_inventories.product_id')
->select('product_flat.product_id as product_id', 'product_flat.sku as product_sku', 'product_flat.name as product_name', 'products.type as product_type', 'product_flat.status', 'product_flat.price', 'attribute_families.name as attribute_family', DB::raw('SUM('.DB::getTablePrefix().'product_inventories.qty) as quantity'))
->select('product_flat.product_id as product_id', 'product_flat.sku as product_sku', 'product_flat.name as product_name', 'products.type as product_type', 'product_flat.status', 'product_flat.price', 'attribute_families.name as attribute_family', DB::raw('SUM(' . DB::getTablePrefix() . 'product_inventories.qty) as quantity'))
->where('channel', core()->getCurrentChannelCode())
->where('locale', app()->getLocale())
->groupBy('product_flat.product_id');

View File

@ -50,7 +50,13 @@ class TaxRateDataGrid extends DataGrid
'type' => 'string',
'searchable' => true,
'sortable' => true,
'filterable' => true
'filterable' => true,
'wrapper' => function($value) {
if (empty($value->state))
return '*';
else
return $value->state;
}
]);
$this->addColumn([

View File

@ -120,9 +120,11 @@ class ConfigurationController extends Controller
{
Event::dispatch('core.configuration.save.before');
$this->validate(request(), [
'general.design.admin_logo.logo_image' => 'mimes:jpeg,bmp,png,jpg'
]);
if (request()->has('general.design.admin_logo.logo_image') && ! request()->input('general.design.admin_logo.logo_image.delete')) {
$this->validate(request(), [
'general.design.admin_logo.logo_image' => 'required|mimes:jpeg,bmp,png,jpg'
]);
}
$this->coreConfigRepository->create(request()->all());

View File

@ -186,7 +186,7 @@ class DashboardController extends Controller
->where('order_items.created_at', '>=', $this->startDate)
->where('order_items.created_at', '<=', $this->endDate)
->addSelect(DB::raw('SUM(qty_invoiced - qty_refunded) as total_qty_invoiced'))
->addSelect(DB::raw('COUNT('.DB::getTablePrefix().'products.id) as total_products'))
->addSelect(DB::raw('COUNT(' . DB::getTablePrefix() . 'products.id) as total_products'))
->addSelect('order_items.id', 'categories.id as category_id', 'category_translations.name')
->groupBy('categories.id')
->havingRaw('SUM(qty_invoiced - qty_refunded) > 0')

View File

@ -669,60 +669,56 @@ Route::group(['middleware' => ['web']], function () {
//DataGrid Export
Route::post('admin/export', 'Webkul\Admin\Http\Controllers\ExportController@export')->name('admin.datagrid.export');
Route::prefix('promotion')->group(function () {
Route::get('/catalog-rules', 'Webkul\Discount\Http\Controllers\CatalogRuleController@index')->defaults('_config', [
'view' => 'admin::promotions.catalog-rule.index'
])->name('admin.catalog-rule.index');
Route::prefix('promotions')->group(function () {
Route::get('cart-rules', 'Webkul\CartRule\Http\Controllers\CartRuleController@index')->defaults('_config', [
'view' => 'admin::promotions.cart-rules.index'
])->name('admin.cart-rules.index');
Route::get('/catalog-rules/create', 'Webkul\Discount\Http\Controllers\CatalogRuleController@create')->defaults('_config', [
'view' => 'admin::promotions.catalog-rule.create'
])->name('admin.catalog-rule.create');
Route::get('cart-rules/create', 'Webkul\CartRule\Http\Controllers\CartRuleController@create')->defaults('_config', [
'view' => 'admin::promotions.cart-rules.create'
])->name('admin.cart-rules.create');
Route::post('/catalog-rules/create', 'Webkul\Discount\Http\Controllers\CatalogRuleController@store')->defaults('_config', [
'redirect' => 'admin.catalog-rule.index'
])->name('admin.catalog-rule.store');
Route::post('cart-rules/create', 'Webkul\CartRule\Http\Controllers\CartRuleController@store')->defaults('_config', [
'redirect' => 'admin.cart-rules.index'
])->name('admin.cart-rules.store');
Route::get('/catalog-rules/edit/{id}', 'Webkul\Discount\Http\Controllers\CatalogRuleController@edit')->defaults('_config', [
'view' => 'admin::promotions.catalog-rule.edit'
])->name('admin.catalog-rule.edit');
Route::get('cart-rules/edit/{id}', 'Webkul\CartRule\Http\Controllers\CartRuleController@edit')->defaults('_config', [
'view' => 'admin::promotions.cart-rules.edit'
])->name('admin.cart-rules.edit');
Route::post('/catalog-rules/edit/{id}', 'Webkul\Discount\Http\Controllers\CatalogRuleController@update')->defaults('_config', [
'redirect' => 'admin.catalog-rule.index'
])->name('admin.catalog-rule.update');
Route::post('cart-rules/edit/{id}', 'Webkul\CartRule\Http\Controllers\CartRuleController@update')->defaults('_config', [
'redirect' => 'admin.cart-rules.index'
])->name('admin.cart-rules.update');
Route::get('/catalog-rules/apply', 'Webkul\Discount\Http\Controllers\CatalogRuleController@applyRules')->defaults('_config', [
'view' => 'admin::promotions.catalog-rule.index'
])->name('admin.catalog-rule.apply');
Route::post('cart-rules/delete/{id}', 'Webkul\CartRule\Http\Controllers\CartRuleController@destroy')->name('admin.cart-rules.delete');
Route::post('/catalog-rules/delete/{id}', 'Webkul\Discount\Http\Controllers\CatalogRuleController@destroy')->name('admin.catalog-rule.delete');
Route::post('cart-rules/generate-coupons/{id?}', 'Webkul\CartRule\Http\Controllers\CartRuleController@generateCoupons')->name('admin.cart-rules.generate-coupons');
Route::get('/catalog-rules/declutter', 'Webkul\Discount\Http\Controllers\CatalogRuleController@deClutter')->defaults('_config', [
'redirect' => 'admin.catalog-rule.index'
])->name('admin.catalog-rule.declut');
Route::post('/massdelete', 'Webkul\CartRule\Http\Controllers\CartRuleCouponController@massDelete')->name('admin.cart-rule-coupons.mass-delete');
Route::post('fetch/options', 'Webkul\Discount\Http\Controllers\CatalogRuleController@fetchAttributeOptions')->name('admin.catalog-rule.options');
Route::get('cart-rules', 'Webkul\Discount\Http\Controllers\CartRuleController@index')->defaults('_config', [
'view' => 'admin::promotions.cart-rule.index'
])->name('admin.cart-rule.index');
//Catalog rules
Route::get('catalog-rules', 'Webkul\CatalogRule\Http\Controllers\CatalogRuleController@index')->defaults('_config', [
'view' => 'admin::promotions.catalog-rules.index'
])->name('admin.catalog-rules.index');
Route::get('cart-rules/create', 'Webkul\Discount\Http\Controllers\CartRuleController@create')->defaults('_config', [
'view' => 'admin::promotions.cart-rule.create'
])->name('admin.cart-rule.create');
Route::get('catalog-rules/create', 'Webkul\CatalogRule\Http\Controllers\CatalogRuleController@create')->defaults('_config', [
'view' => 'admin::promotions.catalog-rules.create'
])->name('admin.catalog-rules.create');
Route::post('cart-rules/store', 'Webkul\Discount\Http\Controllers\CartRuleController@store')->defaults('_config', [
'redirect' => 'admin.cart-rule.index'
])->name('admin.cart-rule.store');
Route::post('catalog-rules/create', 'Webkul\CatalogRule\Http\Controllers\CatalogRuleController@store')->defaults('_config', [
'redirect' => 'admin.catalog-rules.index'
])->name('admin.catalog-rules.store');
Route::get('cart-rules/edit/{id}', 'Webkul\Discount\Http\Controllers\CartRuleController@edit')->defaults('_config', [
'view' => 'admin::promotions.cart-rule.edit'
])->name('admin.cart-rule.edit');
Route::get('catalog-rules/edit/{id}', 'Webkul\CatalogRule\Http\Controllers\CatalogRuleController@edit')->defaults('_config', [
'view' => 'admin::promotions.catalog-rules.edit'
])->name('admin.catalog-rules.edit');
Route::post('cart-rules/update/{id}', 'Webkul\Discount\Http\Controllers\CartRuleController@update')->defaults('_config', [
'redirect' => 'admin.cart-rule.index'
])->name('admin.cart-rule.update');
Route::post('catalog-rules/edit/{id}', 'Webkul\CatalogRule\Http\Controllers\CatalogRuleController@update')->defaults('_config', [
'redirect' => 'admin.catalog-rules.index'
])->name('admin.catalog-rules.update');
Route::post('cart-rules/delete/{id}', 'Webkul\Discount\Http\Controllers\CartRuleController@destroy')->name('admin.cart-rule.delete');
Route::post('catalog-rules/delete/{id}', 'Webkul\CatalogRule\Http\Controllers\CatalogRuleController@destroy')->name('admin.catalog-rules.delete');
});
Route::prefix('cms')->group(function () {
@ -730,7 +726,6 @@ Route::group(['middleware' => ['web']], function () {
'view' => 'admin::cms.index'
])->name('admin.cms.index');
Route::get('preview/{url_key}', 'Webkul\CMS\Http\Controllers\Admin\PageController@preview')->name('admin.cms.preview');
Route::get('create', 'Webkul\CMS\Http\Controllers\Admin\PageController@create')->defaults('_config', [
'view' => 'admin::cms.create'
@ -740,11 +735,11 @@ Route::group(['middleware' => ['web']], function () {
'redirect' => 'admin.cms.index'
])->name('admin.cms.store');
Route::get('update/{id}', 'Webkul\CMS\Http\Controllers\Admin\PageController@edit')->defaults('_config', [
Route::get('edit/{id}', 'Webkul\CMS\Http\Controllers\Admin\PageController@edit')->defaults('_config', [
'view' => 'admin::cms.edit'
])->name('admin.cms.edit');
Route::post('update/{id}', 'Webkul\CMS\Http\Controllers\Admin\PageController@update')->defaults('_config', [
Route::post('edit/{id}', 'Webkul\CMS\Http\Controllers\Admin\PageController@update')->defaults('_config', [
'redirect' => 'admin.cms.index'
])->name('admin.cms.update');
@ -760,12 +755,6 @@ Route::group(['middleware' => ['web']], function () {
// 'redirect' => 'admin.cms.index'
// ])->name('admin.cms.delete');
});
// Development settings
Route::prefix('development')->group(function () {
Route::get('/', 'Webkul\Admin\Http\Controllers\Development\DashboardController@index')
->name('admin.development.index');
});
});
});
});

View File

@ -45,7 +45,6 @@ class NewInvoiceNotification extends Mailable
$order = $this->invoice->order;
return $this->to($order->customer_email, $order->customer_full_name)
->from(config('mail.from'))
->subject(trans('shop::app.mail.invoice.subject', ['order_id' => $order->increment_id]))
->view('shop::emails.sales.new-invoice');
}

View File

@ -42,7 +42,6 @@ class NewOrderNotification extends Mailable
public function build()
{
return $this->to($this->order->customer_email, $this->order->customer_full_name)
->from(config('mail.from'))
->subject(trans('shop::app.mail.order.subject'))
->view('shop::emails.sales.new-order');
}

View File

@ -45,7 +45,6 @@ class NewRefundNotification extends Mailable
$order = $this->refund->order;
return $this->to($order->customer_email, $order->customer_full_name)
->from(config('mail.from'))
->subject(trans('shop::app.mail.refund.subject', ['order_id' => $order->increment_id]))
->view('shop::emails.sales.new-refund');
}

View File

@ -45,7 +45,6 @@ class NewShipmentNotification extends Mailable
$order = $this->shipment->order;
return $this->to($order->customer_email, $order->customer_full_name)
->from(config('mail.from'))
->subject(trans('shop::app.mail.shipment.subject', ['order_id' => $order->increment_id]))
->view('shop::emails.sales.new-shipment');
}

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50 (54983) - http://www.bohemiancoding.com/sketch -->
<title>Angle-Right</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Angle-Right" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<polyline id="Path-3" stroke="#A2A2A2" stroke-width="3" points="7 3 14 10.058476 7.11598308 17"></polyline>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 618 B

View File

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 50 (54983) - http://www.bohemiancoding.com/sketch -->
<title>Icon-Graph-Green</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Icon-Graph-Green" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
<g transform="translate(8.000000, 5.000000)" stroke="#00C357" stroke-width="2">
<path d="M4,0 L4,14" id="Path-2"></path>
<path d="M4,0 L0,4" id="Path-3"></path>
<path d="M7.92330631,0 L3.92330631,4" id="Path-3-Copy" transform="translate(5.961653, 2.000000) scale(-1, 1) translate(-5.961653, -2.000000) "></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 881 B

View File

@ -1,9 +1,14 @@
require("./bootstrap");
import Vue from 'vue';
import VeeValidate from 'vee-validate';
window.Vue = require("vue");
window.VeeValidate = require("vee-validate");
import './bootstrap';
Vue.use(VeeValidate);
window.Vue = Vue;
window.VeeValidate = VeeValidate;
Vue.use(VeeValidate, {
events: 'input|change|blur',
});
Vue.prototype.$http = axios
window.eventBus = new Vue();
@ -82,6 +87,10 @@ $(document).ready(function () {
},
addFlashMessages() {
if (typeof flashMessages == 'undefined') {
return;
};
const flashes = this.$refs.flashes;
flashMessages.forEach(function(flash) {

View File

@ -48,4 +48,29 @@
border-bottom: 1px solid #e8e8e8;
cursor: pointer;
}
}
.cart-rule-conditions,
.catalog-rule-conditions {
table {
td {
&.attribute {
width: 250px;
padding-left: 0;
}
&.operator,
&.value {
width: 260px;
}
&.actions {
width: 44px;
.icon {
margin-top: 6px;
}
}
}
}
}

View File

@ -852,7 +852,7 @@ return [
],
'footer' => [
'copy-right' => '© Copyright 2018 Webkul Software, All rights reserved.'
'copy-right' => ' مدعوم من <a href="https://bagisto.com/" target="_blank"> Bagisto </a> ، مشروع مجتمع بواسطة <a href="https://webkul.com/" target="_blank">Webkul</a>'
],
'admin' => [

View File

@ -73,7 +73,7 @@ return [
'taxes' => 'Taxes',
'tax-categories' => 'Tax Categories',
'tax-rates' => 'Tax Rates',
'promotion' => 'Promotions',
'promotions' => 'Promotions',
'discount' => 'Discount',
'cms' => 'CMS'
],
@ -110,7 +110,8 @@ return [
'create' => 'Add',
'delete' => 'Delete',
'promotions' => 'Promotions',
'cart-rules' => 'Cart Rules'
'cart-rules' => 'Cart Rules',
'catalog-rules' => 'Catalog Rules',
],
'dashboard' => [
@ -203,7 +204,16 @@ return [
'for-guest' => 'For Guest',
'order_number' => 'Order Number',
'refund-date' => 'Refund Date',
'refunded' => 'Refunded'
'refunded' => 'Refunded',
'start' => 'Start',
'end' => 'End',
'active' => 'Active',
'inactive' => 'Inactive',
'coupon-code' => 'Coupon Code',
'times-used' => 'Times Used',
'created-date' => 'Created Date',
'expiration-date' => 'Expiration Date',
'delete' => 'Delete'
],
'account' => [
@ -944,125 +954,138 @@ return [
]
],
'promotion' => [
'information' => 'Information',
'conditions' => 'Conditions',
'actions' => 'Actions',
'coupons' => 'Coupons',
'zero-unlimited' => 'Zero denotes unlimited usage here',
'catalog-rule' => 'Catalog Rules',
'cart-rule' => 'Cart Rules',
'add-catalog-rule' => 'Add Rule',
'add-cart-rule' => 'Add Cart Rule',
'edit-cart-rule' => 'Edit Cart Rule',
'edit-catalog-rule' => 'Edit Catalog Rule',
'create-catalog-rule' => 'Create Catalog Rule',
'create-cart-rule' => 'Create Cart Rule',
'save-btn-title' => 'Create',
'edit-btn-title' => 'Save',
'save' => 'Save',
'select-cart-attr' => 'Select Cart Attribute',
'select-products' => 'How to choose products ?',
'select-category' => 'Select by Categories',
'select-attribute' => 'Select by Attributes',
'cannot-activate-catalog-rule' => 'Cannot activate catalog rule',
'catalog-rule-already-activated' => 'Catalog rule is already activated',
'catalog-rule-activated' => 'Catalog rule is activated',
'select-attribute' => 'Select :attribute',
'enter-attribute' => 'Enter :attribute',
'add-condition' => 'Add Condition',
'cart-properties' => 'Cart Properties',
'yes' => 'Yes',
'no' => 'No',
'note' => 'Note',
'apply' => 'Apply',
'rule-name' => 'Enter Rule Name',
'rule-desc' => 'Enter Rule Description',
'convert-x-note' => 'If this section is left empty, then rule will get applied to all the products in the cart.',
'declut' => 'Declutter',
'processing-done' => 'Rules processing done',
'declut-success' => 'Catalog rules decluttering successful',
'declut-failure' => 'Catalog rules decluttering failed',
'add-attr-condition' => 'Add Attribute Condition',
'general-info' => [
'sku-like' => 'SKU Like',
'on-shipping' => 'If applied on shipping',
'discount' => 'Discount',
'shipping-apply-info' => 'It signifies how rule behaves when it is used for shipping',
'general-info' => 'General Info',
'options' => 'Options',
'name' => 'Rule Name',
'description' => 'Description',
'starts-from' => 'Start',
'ends-till' => 'End',
'channels' => 'Channels',
'channels-req' => 'Channels',
'cust-groups' => 'Customer Groups',
'priority' => 'Priority',
'add-condition' => 'Add Conditions',
'disc_amt' => 'Discount Amount',
'disc_percent' => 'Discount Percentage',
'is-coupon' => 'Use Coupon',
'is-coupon-yes' => 'Yes',
'is-coupon-no' => 'No',
'uses-per-cust' => 'Uses per customer',
'all' => 'All',
'any' => 'Any',
'end-other-rules' => 'End other rules',
'status' => 'Is Active',
'all-conditions-true' => 'Assuming all conditions are true',
'assuming' => 'Assuming',
'any' => 'Any',
'all' => 'All',
'conditions' => 'Conditions',
'apply' => 'Apply',
'are' => 'are',
'true' => 'true',
'false' => 'false',
'limit' => 'Usage Limit',
'specific-coupon' => 'Specific Coupon(Check) / Auto Generated(Unheck)',
'free-shipping' => 'Free Shipping',
'is-guest' => 'For Guests',
'disc_qty' => 'Max. Quantity Allowed To Be Discounted',
'test-mode' => 'Choose how to test conditions',
'labels' => 'Labels',
'prefix' => 'Prefix',
'suffix' => 'Suffix',
'code' => 'Code',
'global-label' => 'Global Label',
'label' => 'Label'
],
'status' => [
'success' => 'Success! rule created',
'success-coupon' => 'Success! rule created along with coupon',
'failed' => 'Error! failed to create rule',
'update-success' => 'Success! rule updated',
'update-coupon-success' => 'Success! rule updated along with coupon',
'update-failed' => 'Error! cannot update',
'delete-success' => 'Success! rule deleted',
'delete-failed' => 'Error! cannot delete',
'coupon-applied' => 'Coupon used',
'coupon-failed' => 'Coupon failed to apply',
'no-coupon' => '* Coupon not applicable',
'coupon-removed' => 'Coupon removed successfully',
'coupon-remove-failed' => 'Coupon removal failed',
'duplicate-coupon' => 'Coupon already exists, please try again with a different coupon'
],
'catalog' => [
'promotions' => [
'cart-rules' => [
'title' => 'Cart Rules',
'add-title' => 'Add Cart Rule',
'edit-title' => 'Edit Cart Rule',
'save-btn-title' => 'Save Cart Rule',
'rule-information' => 'Rule Information',
'name' => 'Name',
'description' => 'Description',
'apply-percent' => 'Apply as percentage',
'apply-fixed' => 'Apply as fixed amount',
'adjust-to-percent' => 'Adjust to percentage',
'adjust-to-value' => 'Adjust to discount value',
'condition-missing' => 'Please check conditons, some values might be missing'
'status' => 'Status',
'is-active' => 'Cart Rule is Active',
'channels' => 'Channels',
'customer-groups' => 'Customer Groups',
'coupon-type' => 'Coupon Type',
'no-coupon' => 'No Coupon',
'specific-coupon' => 'Specific Coupon',
'auto-generate-coupon' => 'Auto Generate Coupon',
'no' => 'No',
'yes' => 'Yes',
'coupon-code' => 'Coupon Code',
'uses-per-coupon' => 'Uses Per Coupon',
'uses-per-customer' => 'Uses Per Customer',
'uses-per-customer-control-info' => 'Will be used for logged in customers only.',
'from' => 'From',
'to' => 'To',
'priority' => 'Priority',
'conditions' => 'Conditions',
'condition-type' => 'Condition Type',
'all-conditions-true' => 'All Conditions are True',
'any-condition-true' => 'Any Condition is True',
'add-condition' => 'Add Condition',
'choose-condition-to-add' => 'Choose a condition to add',
'cart-attribute' => 'Cart Attribute',
'subtotal' => 'Subtotal',
'total-items-qty' => 'Total Items Qty',
'total-weight' => 'Total Weight',
'payment-method' => 'Payment Method',
'shipping-method' => 'Shipping Method',
'shipping-postcode' => 'Shipping Zip/Postcode',
'shipping-state' => 'Shipping State',
'shipping-country' => 'Shipping Country',
'cart-item-attribute' => 'Cart Item Attribute',
'price-in-cart' => 'Price in Cart',
'qty-in-cart' => 'Qty in Cart',
'product-attribute' => 'Product Attribute',
'attribute-name-children-only' => ':attribute_name (Children Only)',
'attribute-name-parent-only' => ':attribute_name (Parent Only)',
'is-equal-to' => 'Is equal to',
'is-not-equal-to' => 'Is not equal to',
'equals-or-greater-than' => 'Equals or greater than',
'equals-or-less-than' => 'Equals or less than',
'greater-than' => 'Greater than',
'less-than' => 'Less than',
'contain' => 'Contain',
'contains' => 'Contains',
'does-not-contain' => 'Does not contain',
'actions' => 'Actions',
'action-type' => 'Action Type',
'percentage-product-price' => 'Percentage of Product Price',
'fixed-amount' => 'Fixed Amount',
'fixed-amount-whole-cart' => 'Fixed Amount to Whole Cart',
'buy-x-get-y-free' => 'Buy X Get Y Free',
'discount-amount' => 'Discount Amount',
'discount-quantity' => 'Maximum Quantity Allowed to be Discounted',
'discount-step' => 'Buy X Quantity',
'free-shipping' => 'Free Shipping',
'apply-to-shipping' => 'Apply to Shipping',
'coupon-codes' => 'Coupon Codes',
'coupon-qty' => 'Coupon Qty',
'code-length' => 'Code Length',
'code-format' => 'Code Format',
'alphanumeric' => 'Alphanumeric',
'alphabetical' => 'Alphabetical',
'numeric' => 'Numeric',
'code-prefix' => 'Code Prefix',
'code-suffix' => 'Code Suffix',
'generate' => 'Generate',
'cart-rule-not-defind-error' => 'Cart rule is not defined',
'mass-delete-success' => 'All the selected index of coupons have been deleted successfully.',
'end-other-rules' => 'End Other Rules',
'children-categories' => 'Categories (Children Only)',
'parent-categories' => 'Categories (Parent Only)',
'categories' => 'Categories',
'attribute_family' => 'Attribute Family'
],
'cart' => [
'buy-atleast' => 'Buy Atleast',
'apply-to-shipping' => 'Apply to shipping'
'catalog-rules' => [
'title' => 'Catalog Rules',
'add-title' => 'Add Catalog Rule',
'edit-title' => 'Edit Catalog Rule',
'save-btn-title' => 'Save Catalog Rule',
'rule-information' => 'Rule Information',
'name' => 'Name',
'description' => 'Description',
'status' => 'Status',
'is-active' => 'Catalog Rule is Active',
'channels' => 'Channels',
'customer-groups' => 'Customer Groups',
'no' => 'No',
'yes' => 'Yes',
'from' => 'From',
'to' => 'To',
'priority' => 'Priority',
'conditions' => 'Conditions',
'condition-type' => 'Condition Type',
'all-conditions-true' => 'All Conditions are True',
'any-condition-true' => 'Any Condition is True',
'add-condition' => 'Add Condition',
'choose-condition-to-add' => 'Choose a condition to add',
'product-attribute' => 'Product Attribute',
'attribute-name-children-only' => ':attribute_name (Children Only)',
'attribute-name-parent-only' => ':attribute_name (Parent Only)',
'is-equal-to' => 'Is equal to',
'is-not-equal-to' => 'Is not equal to',
'equals-or-greater-than' => 'Equals or greater than',
'equals-or-less-than' => 'Equals or less than',
'greater-than' => 'Greater than',
'less-than' => 'Less than',
'contain' => 'Contain',
'contains' => 'Contains',
'does-not-contain' => 'Does not contain',
'actions' => 'Actions',
'action-type' => 'Action Type',
'percentage-product-price' => 'Percentage of Product Price',
'fixed-amount' => 'Fixed Amount',
'fixed-amount-whole-cart' => 'Fixed Amount to Whole Catalog',
'buy-x-get-y-free' => 'Buy X Get Y Free',
'discount-amount' => 'Discount Amount',
'mass-delete-success' => 'All the selected index of coupons have been deleted successfully.',
'end-other-rules' => 'End Other Rules',
'categories' => 'Categories',
'attribute_family' => 'Attribute Family'
]
],
@ -1119,13 +1142,13 @@ return [
'pages' => [
'general' => 'General',
'seo' => 'SEO',
'pages' => 'Page',
'title' => 'pages',
'pages' => 'Pages',
'title' => 'Pages',
'add-title' => 'Add Page',
'content' => 'Content',
'url-key' => 'URL Key',
'channel' => 'Channel',
'locale' => 'Locale',
'channel' => 'Channels',
'locale' => 'Locales',
'create-btn-title' => 'Save Page',
'edit-title' => 'Edit Page',
'edit-btn-title' => 'Save Page',
@ -1172,7 +1195,7 @@ return [
],
'footer' => [
'copy-right' => '© Copyright 2018 Webkul Software, All rights reserved.'
'copy-right' => 'Powered by <a href="https://bagisto.com/" target="_blank">Bagisto</a>, A Community Project by <a href="https://webkul.com/" target="_blank">Webkul</a>',
],
'admin' => [

View File

@ -998,7 +998,7 @@ return [
],
'footer' => [
'copy-right' => '© کپی رایت 2019 کلیه حقوق محفوظ است.'
'copy-right' => 'طراحی شده توسط <a href="https://bagisto.com/" target="_blank">Bagisto</a> ، یک پروژه عمومی توسط <a href="https://webkul.com/" target="_blank">Webkul</a>'
],
'admin' => [

View File

@ -976,7 +976,7 @@ return [
],
'footer' => [
'copy-right' => '© Copyright '.date('Y').' Webkul Software, Todos os direitos reservados.'
'copy-right' => 'Desenvolvido por <a href="https://bagisto.com/" target="_blank">Bagisto</a>, um projeto comunitário da <a href="https://webkul.com/" target="_blank">Webkul</a>'
],
'admin' => [

View File

@ -83,7 +83,7 @@
<div class="control-group">
<label for="locale-{{ $locale->code }}">{{ $locale->name . ' (' . $locale->code . ')' }}</label>
<input type="text" class="control" id="locale-{{ $locale->code }}" name="<?php echo $locale->code; ?>[name]" value="{{ old($locale->code)['name'] }}"/>
<input type="text" class="control" id="locale-{{ $locale->code }}" name="<?php echo $locale->code; ?>[name]" value="{{ old($locale->code)['name'] ?? '' }}"/>
</div>
@endforeach

View File

@ -108,7 +108,7 @@
<div class="control-group">
<label for="locale-{{ $locale->code }}">{{ $locale->name . ' (' . $locale->code . ')' }}</label>
<input type="text" class="control" id="locale-{{ $locale->code }}" name="<?php echo $locale->code; ?>[name]" value="{{ old($locale->code)['name'] ?: $attribute->translate($locale->code)['name'] }}"/>
<input type="text" class="control" id="locale-{{ $locale->code }}" name="<?php echo $locale->code; ?>[name]" value="{{ old($locale->code)['name'] ?? $attribute->translate($locale->code)['name'] }}"/>
</div>
@endforeach

View File

@ -52,7 +52,7 @@
<div class="control-group" :class="[errors.has('{{$locale}}[name]') ? 'has-error' : '']">
<label for="name" class="required">{{ __('admin::app.catalog.categories.name') }}</label>
<input type="text" v-validate="'required'" class="control" id="name" name="{{$locale}}[name]" value="{{ old($locale)['name'] ?: $category->translate($locale)['name'] }}" data-vv-as="&quot;{{ __('admin::app.catalog.categories.name') }}&quot;"/>
<input type="text" v-validate="'required'" class="control" id="name" name="{{$locale}}[name]" value="{{ old($locale)['name'] ?? $category->translate($locale)['name'] }}" data-vv-as="&quot;{{ __('admin::app.catalog.categories.name') }}&quot;"/>
<span class="control-error" v-if="errors.has('{{$locale}}[name]')">@{{ errors.first('{!!$locale!!}[name]') }}</span>
</div>
@ -180,23 +180,23 @@
<div class="control-group">
<label for="meta_title">{{ __('admin::app.catalog.categories.meta_title') }}</label>
<input type="text" class="control" id="meta_title" name="{{$locale}}[meta_title]" value="{{ old($locale)['meta_title'] ?: $category->translate($locale)['meta_title'] }}"/>
<input type="text" class="control" id="meta_title" name="{{$locale}}[meta_title]" value="{{ old($locale)['meta_title'] ?? $category->translate($locale)['meta_title'] }}"/>
</div>
<div class="control-group" :class="[errors.has('{{$locale}}[slug]') ? 'has-error' : '']">
<label for="slug" class="required">{{ __('admin::app.catalog.categories.slug') }}</label>
<input type="text" v-validate="'required'" class="control" id="slug" name="{{$locale}}[slug]" value="{{ old($locale)['slug'] ?: $category->translate($locale)['slug'] }}" data-vv-as="&quot;{{ __('admin::app.catalog.categories.slug') }}&quot;" v-slugify/>
<input type="text" v-validate="'required'" class="control" id="slug" name="{{$locale}}[slug]" value="{{ old($locale)['slug'] ?? $category->translate($locale)['slug'] }}" data-vv-as="&quot;{{ __('admin::app.catalog.categories.slug') }}&quot;" v-slugify/>
<span class="control-error" v-if="errors.has('{{$locale}}[slug]')">@{{ errors.first('{!!$locale!!}[slug]') }}</span>
</div>
<div class="control-group">
<label for="meta_description">{{ __('admin::app.catalog.categories.meta_description') }}</label>
<textarea class="control" id="meta_description" name="{{$locale}}[meta_description]">{{ old($locale)['meta_description'] ?: $category->translate($locale)['meta_description'] }}</textarea>
<textarea class="control" id="meta_description" name="{{$locale}}[meta_description]">{{ old($locale)['meta_description'] ?? $category->translate($locale)['meta_description'] }}</textarea>
</div>
<div class="control-group">
<label for="meta_keywords">{{ __('admin::app.catalog.categories.meta_keywords') }}</label>
<textarea class="control" id="meta_keywords" name="{{$locale}}[meta_keywords]">{{ old($locale)['meta_keywords'] ?: $category->translate($locale)['meta_keywords'] }}</textarea>
<textarea class="control" id="meta_keywords" name="{{$locale}}[meta_keywords]">{{ old($locale)['meta_keywords'] ?? $category->translate($locale)['meta_keywords'] }}</textarea>
</div>
{!! view_render_event('bagisto.admin.catalog.category.edit_form_accordian.seo.controls.after', ['category' => $category]) !!}
@ -220,7 +220,7 @@
<div class="control-group" :class="[errors.has('{{$locale}}[description]') ? 'has-error' : '']">
<label for="description" :class="isRequired ? 'required' : ''">{{ __('admin::app.catalog.categories.description') }}</label>
<textarea v-validate="isRequired ? 'required' : ''" class="control" id="description" name="{{$locale}}[description]" data-vv-as="&quot;{{ __('admin::app.catalog.categories.description') }}&quot;">{{ old($locale)['description'] ?: $category->translate($locale)['description'] }}</textarea>
<textarea v-validate="isRequired ? 'required' : ''" class="control" id="description" name="{{$locale}}[description]" data-vv-as="&quot;{{ __('admin::app.catalog.categories.description') }}&quot;">{{ old($locale)['description'] ?? $category->translate($locale)['description'] }}</textarea>
<span class="control-error" v-if="errors.has('{{$locale}}[description]')">@{{ errors.first('{!!$locale!!}[description]') }}</span>
</div>

View File

@ -11,9 +11,9 @@
<div class="page-header">
<div class="page-title">
<h1>
<i class="icon angle-left-icon back-link" onclick="history.length > 1 ? history.go(-1) : window.location = '{{ url('/admin/dashboard') }}';"></i>
<i class="icon angle-left-icon back-link" @click="redirectBack('{{ url('/admin/dashboard') }}')"></i>
{{ __('admin::app.cms.pages.pages') }}
{{ __('admin::app.cms.pages.add-title') }}
</h1>
</div>
@ -28,6 +28,9 @@
<div class="form-container">
@csrf()
{!! view_render_event('bagisto.admin.cms.pages.create_form_accordian.general.before') !!}
<accordian :title="'{{ __('admin::app.cms.pages.general') }}'" :active="true">
<div slot="body">
<div class="control-group" :class="[errors.has('page_title') ? 'has-error' : '']">
@ -38,16 +41,7 @@
<span class="control-error" v-if="errors.has('page_title')">@{{ errors.first('page_title') }}</span>
</div>
<div class="control-group" :class="[errors.has('url_key') ? 'has-error' : '']">
<label for="url-key" class="required">{{ __('admin::app.cms.pages.url-key') }}</label>
<input type="text" class="control" name="url_key" v-validate="'required'" value="{{ old('url-key') }}" data-vv-as="&quot;{{ __('admin::app.cms.pages.url-key') }}&quot;" v-slugify>
<span class="control-error" v-if="errors.has('url_key')">@{{ errors.first('url_key') }}</span>
</div>
@inject('channels', 'Webkul\Core\Repositories\ChannelRepository')
@inject('locales', 'Webkul\Core\Repositories\LocaleRepository')
<div class="control-group" :class="[errors.has('channels[]') ? 'has-error' : '']">
<label for="url-key" class="required">{{ __('admin::app.cms.pages.channel') }}</label>
@ -61,77 +55,56 @@
<span class="control-error" v-if="errors.has('channels[]')">@{{ errors.first('channels[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('locales[]') ? 'has-error' : '']">
<label for="url-key" class="required">{{ __('admin::app.cms.pages.locale') }}</label>
<select type="text" class="control" name="locales[]" v-validate="'required'" value="{{ old('locale[]') }}" data-vv-as="&quot;{{ __('admin::app.cms.pages.locale') }}&quot;" multiple="multiple">
@foreach($locales->all() as $locale)
<option value="{{ $locale->id }}">{{ $locale->name }}</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('locales[]')">@{{ errors.first('locales[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('html_content') ? 'has-error' : '']">
<label for="html_content" class="required">{{ __('admin::app.cms.pages.content') }}</label>
<textarea type="text" class="control" id="content" name="html_content" v-validate="'required'" value="{{ old('html_content') }}" data-vv-as="&quot;{{ __('admin::app.cms.pages.content') }}&quot;"></textarea>
{!! __('admin::app.cms.pages.one-col') !!}
{!! __('admin::app.cms.pages.two-col') !!}
{!! __('admin::app.cms.pages.three-col') !!}
<div class="mt-10 mb-10">
<a target="_blank" href="{{ route('ui.helper.classes') }}" class="btn btn-sm btn-primary">
{{ __('admin::app.cms.pages.helper-classes') }}
</a>
</div>
<textarea type="text" class="control" id="content" name="html_content" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.cms.pages.content') }}&quot;">{{ old('html_content') }}</textarea>
<span class="control-error" v-if="errors.has('html_content')">@{{ errors.first('html_content') }}</span>
</div>
</div>
</accordian>
{!! view_render_event('bagisto.admin.cms.pages.create_form_accordian.general.after') !!}
{!! view_render_event('bagisto.admin.cms.pages.create_form_accordian.seo.before') !!}
<accordian :title="'{{ __('admin::app.cms.pages.seo') }}'" :active="true">
<div slot="body">
<div class="control-group" :class="[errors.has('meta_title') ? 'has-error' : '']">
<label for="meta_title" class="required">{{ __('admin::app.cms.pages.meta_title') }}</label>
<div class="control-group">
<label for="meta_title">{{ __('admin::app.cms.pages.meta_title') }}</label>
<input type="text" class="control" name="meta_title" v-validate="'required'" value="{{ old('meta_title') }}" data-vv-as="&quot;{{ __('admin::app.cms.pages.meta_title') }}&quot;">
<span class="control-error" v-if="errors.has('meta_title')">@{{ errors.first('meta_title') }}</span>
<input type="text" class="control" name="meta_title" value="{{ old('meta_title') }}">
</div>
<div class="control-group" :class="[errors.has('meta_keywords') ? 'has-error' : '']">
<label for="meta_keywords" class="required">{{ __('admin::app.cms.pages.meta_keywords') }}</label>
<div class="control-group" :class="[errors.has('url_key') ? 'has-error' : '']">
<label for="url-key" class="required">{{ __('admin::app.cms.pages.url-key') }}</label>
<textarea type="text" class="control" name="meta_keywords" v-validate="'required'" value="{{ old('meta_keywords') }}" data-vv-as="&quot;{{ __('admin::app.cms.pages.meta_keywords') }}&quot;"></textarea>
<input type="text" class="control" name="url_key" v-validate="'required'" value="{{ old('url_key') }}" data-vv-as="&quot;{{ __('admin::app.cms.pages.url-key') }}&quot;" v-slugify>
<span class="control-error" v-if="errors.has('meta_keywords')">@{{ errors.first('meta_keywords') }}</span>
<span class="control-error" v-if="errors.has('url_key')">@{{ errors.first('url_key') }}</span>
</div>
<div class="control-group" :class="[errors.has('meta_description') ? 'has-error' : '']">
<div class="control-group">
<label for="meta_keywords">{{ __('admin::app.cms.pages.meta_keywords') }}</label>
<textarea type="text" class="control" name="meta_keywords">{{ old('meta_keywords') }}</textarea>
</div>
<div class="control-group">
<label for="meta_description">{{ __('admin::app.cms.pages.meta_description') }}</label>
<textarea type="text" class="control" name="meta_description" value="{{ old('meta_description') }}" data-vv-as="&quot;{{ __('admin::app.cms.pages.meta_description') }}&quot;"></textarea>
<span class="control-error" v-if="errors.has('meta_description')">@{{ errors.first('meta_description') }}</span>
<textarea type="text" class="control" name="meta_description">{{ old('meta_description') }}</textarea>
</div>
</div>
</accordian>
{!! view_render_event('bagisto.admin.cms.pages.create_form_accordian.seo.after') !!}
</div>
</div>
</form>
</div>
{{-- <modal id="showHelpers" :is-open="modalIds.showHelpers">
<h3 slot="header">{{ __('admin::app.cms.pages.helper-classes') }}</h3>
<div slot="body">
@include('ui::partials.helper-classes')
</div>
</modal> --}}
@stop
@push('scripts')
@ -142,7 +115,7 @@
tinymce.init({
selector: 'textarea#content',
height: 200,
width: "70%",
width: "100%",
plugins: 'image imagetools media wordcount save fullscreen code',
toolbar1: 'formatselect | bold italic strikethrough forecolor backcolor | link | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat | code',
image_advtab: true,

View File

@ -6,21 +6,37 @@
@section('content')
<div class="content">
<form method="POST" id="page-form" action="{{ route('admin.cms.edit', $page->id) }}" @submit.prevent="onSubmit">
<?php $locale = request()->get('locale') ?: app()->getLocale(); ?>
<form method="POST" id="page-form" action="" @submit.prevent="onSubmit">
<div class="page-header">
<div class="page-title">
<h1>
<i class="icon angle-left-icon back-link" onclick="history.length > 1 ? history.go(-1) : window.location = '{{ url('/admin/dashboard') }}';"></i>
<i class="icon angle-left-icon back-link" @click="redirectBack('{{ url('/admin/dashboard') }}')"></i>
{{ __('admin::app.cms.pages.pages') }}
{{ __('admin::app.cms.pages.edit-title') }}
</h1>
<div class="control-group">
<select class="control" id="locale-switcher" onChange="window.location.href = this.value">
@foreach (core()->getAllLocales() as $localeModel)
<option value="{{ route('admin.cms.edit', $page->id) . '?locale=' . $localeModel->code }}" {{ ($localeModel->code) == $locale ? 'selected' : '' }}>
{{ $localeModel->name }}
</option>
@endforeach
</select>
</div>
</div>
<div class="page-action">
<button id="preview" class="btn btn-lg btn-primary">
{{ __('admin::app.cms.pages.preview') }}
</button>
@if ($page->translate($locale))
<a href="{{ route('shop.cms.page', $page->translate($locale)['url_key']) }}" class="btn btn-lg btn-primary" target="_blank">
{{ __('admin::app.cms.pages.preview') }}
</a>
@endif
<button type="submit" class="btn btn-lg btn-primary">
{{ __('admin::app.cms.pages.edit-btn-title') }}
@ -34,66 +50,66 @@
@csrf()
<accordian :title="'{{ __('admin::app.cms.pages.general') }}'" :active="true">
<div slot="body">
<div class="control-group" :class="[errors.has('page_title') ? 'has-error' : '']">
<div class="control-group" :class="[errors.has('{{$locale}}[page_title]') ? 'has-error' : '']">
<label for="page_title" class="required">{{ __('admin::app.cms.pages.page-title') }}</label>
<input type="text" class="control" name="page_title" v-validate="'required'" value="{{ $page->page_title ?? old('page_title') }}" data-vv-as="&quot;{{ __('admin::app.cms.pages.page-title') }}&quot;">
<input type="text" class="control" name="{{$locale}}[page_title]" v-validate="'required'" value="{{ old($locale)['page_title'] ?? ($page->translate($locale)['page_title'] ?? '') }}" data-vv-as="&quot;{{ __('admin::app.cms.pages.page-title') }}&quot;">
<span class="control-error" v-if="errors.has('page_title')">@{{ errors.first('page_title') }}</span>
<span class="control-error" v-if="errors.has('{{$locale}}[page_title]')">@{{ errors.first('{!!$locale!!}[page_title]') }}</span>
</div>
<div class="control-group" :class="[errors.has('url_key') ? 'has-error' : '']">
<label for="url-key" class="required">{{ __('admin::app.cms.pages.url-key') }}</label>
<div class="control-group" :class="[errors.has('channels[]') ? 'has-error' : '']">
<label for="url-key" class="required">{{ __('admin::app.cms.pages.channel') }}</label>
<input type="text" class="control" name="url_key" v-validate="'required'" value="{{ $page->url_key ?? old('url_key') }}" data-vv-as="&quot;{{ __('admin::app.cms.pages.url-key') }}&quot;" disabled>
<?php $selectedOptionIds = old('inventory_sources') ?: $page->channels->pluck('id')->toArray() ?>
<span class="control-error" v-if="errors.has('url_key')">@{{ errors.first('url_key') }}</span>
<select type="text" class="control" name="channels[]" v-validate="'required'" value="{{ old('channel[]') }}" data-vv-as="&quot;{{ __('admin::app.cms.pages.channel') }}&quot;" multiple="multiple">
@foreach(app('Webkul\Core\Repositories\ChannelRepository')->all() as $channel)
<option value="{{ $channel->id }}" {{ in_array($channel->id, $selectedOptionIds) ? 'selected' : '' }}>
{{ $channel->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('channels[]')">@{{ errors.first('channels[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('html_content') ? 'has-error' : '']">
<div class="control-group" :class="[errors.has('{{$locale}}[html_content]') ? 'has-error' : '']">
<label for="html_content" class="required">{{ __('admin::app.cms.pages.content') }}</label>
<textarea type="text" class="control" id="content" name="html_content" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.cms.pages.content') }}&quot;">{{ $page->html_content ?? old('html_content') }}</textarea>
<textarea type="text" class="control" id="content" name="{{$locale}}[html_content]" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.cms.pages.content') }}&quot;">{{ old($locale)['html_content'] ?? ($page->translate($locale)['html_content'] ?? '') }}</textarea>
{!! __('admin::app.cms.pages.one-col') !!}
{!! __('admin::app.cms.pages.two-col') !!}
{!! __('admin::app.cms.pages.three-col') !!}
<div class="mt-10 mb-10">
<a target="_blank" href="{{ route('ui.helper.classes') }}" class="btn btn-sm btn-primary">
{{ __('admin::app.cms.pages.helper-classes') }}
</a>
</div>
<span class="control-error" v-if="errors.has('html_content')">@{{ errors.first('html_content') }}</span>
<span class="control-error" v-if="errors.has('{{$locale}}[html_content]')">@{{ errors.first('{!!$locale!!}[html_content]') }}</span>
</div>
</div>
</accordian>
<accordian :title="'{{ __('admin::app.cms.pages.seo') }}'" :active="true">
<div slot="body">
<div class="control-group" :class="[errors.has('meta_title') ? 'has-error' : '']">
<label for="meta_title" class="required">{{ __('admin::app.cms.pages.meta_title') }}</label>
<div class="control-group">
<label for="meta_title">{{ __('admin::app.cms.pages.meta_title') }}</label>
<input type="text" class="control" name="meta_title" v-validate="'required'" value="{{ $page->meta_title ?? old('meta_title') }}" data-vv-as="&quot;{{ __('admin::app.cms.pages.meta_title') }}&quot;">
<span class="control-error" v-if="errors.has('meta_title')">@{{ errors.first('meta_title') }}</span>
<input type="text" class="control" name="{{$locale}}[meta_title]" value="{{ old($locale)['meta_title'] ?? ($page->translate($locale)['meta_title'] ?? '') }}">
</div>
<div class="control-group" :class="[errors.has('meta_keywords') ? 'has-error' : '']">
<label for="meta_keywords" class="required">{{ __('admin::app.cms.pages.meta_keywords') }}</label>
<div class="control-group" :class="[errors.has('{{$locale}}[url_key]') ? 'has-error' : '']">
<label for="url-key" class="required">{{ __('admin::app.cms.pages.url-key') }}</label>
<textarea type="text" class="control" name="meta_keywords" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.cms.pages.meta_keywords') }}&quot;">{{ $page->meta_keywords ?? old('meta_keywords') }}</textarea>
<input type="text" class="control" name="{{$locale}}[url_key]" v-validate="'required'" value="{{ old($locale)['url_key'] ?? ($page->translate($locale)['url_key'] ?? '') }}" data-vv-as="&quot;{{ __('admin::app.cms.pages.url-key') }}&quot;">
<span class="control-error" v-if="errors.has('meta_keywords')">@{{ errors.first('meta_keywords') }}</span>
<span class="control-error" v-if="errors.has('{{$locale}}[url_key]')">@{{ errors.first('{!!$locale!!}[url_key]') }}</span>
</div>
<div class="control-group" :class="[errors.has('meta_description') ? 'has-error' : '']">
<div class="control-group">
<label for="meta_keywords">{{ __('admin::app.cms.pages.meta_keywords') }}</label>
<textarea type="text" class="control" name="{{$locale}}[meta_keywords]">{{ old($locale)['meta_keywords'] ?? ($page->translate($locale)['meta_keywords'] ?? '') }}</textarea>
</div>
<div class="control-group">
<label for="meta_description">{{ __('admin::app.cms.pages.meta_description') }}</label>
<textarea type="text" class="control" name="meta_description" data-vv-as="&quot;{{ __('admin::app.cms.pages.meta_description') }}&quot;">{{ $page->meta_description ?? old('meta_description') }}</textarea>
<span class="control-error" v-if="errors.has('meta_description')">@{{ errors.first('meta_description') }}</span>
<textarea type="text" class="control" name="{{$locale}}[meta_description]">{{ old($locale)['meta_description'] ?? ($page->translate($locale)['meta_description'] ?? '') }}</textarea>
</div>
</div>
</accordian>
@ -108,27 +124,10 @@
<script>
$(document).ready(function () {
$('#preview').on('click', function(e) {
var form = $('#page-form').serialize();
// var url = '{{ route('admin.cms.preview', $page->id) }}' + '?' + form;
var url = '{{ route('admin.cms.preview', $page->id) }}';
window.open(url, '_blank').focus();
return false;
});
$('#channel-switcher, #locale-switcher').on('change', function (e) {
$('#channel-switcher').val()
var query = '?channel=' + $('#channel-switcher').val() + '&locale=' + $('#locale-switcher').val();
window.location.href = "{{ route('admin.cms.edit', $page->id) }}" + query;
});
tinymce.init({
selector: 'textarea#content',
height: 200,
width: "70%",
width: "100%",
plugins: 'image imagetools media wordcount save fullscreen code',
toolbar1: 'formatselect | bold italic strikethrough forecolor backcolor | link | alignleft aligncenter alignright alignjustify | numlist bullist outdent indent | removeformat | code',
image_advtab: true,

View File

@ -96,7 +96,7 @@
@if (core()->getConfigData('general.content.footer.footer_content'))
{{ core()->getConfigData('general.content.footer.footer_content') }}
@else
{{ trans('admin::app.footer.copy-right') }}
{!! trans('admin::app.footer.copy-right') !!}
@endif
</p>
</div>

View File

@ -1,630 +0,0 @@
@extends('admin::layouts.content')
@section('page_title')
{{ __('admin::app.promotion.add-cart-rule') }}
@stop
@section('content')
<div class="content">
<cart-rule></cart-rule>
</div>
@push('scripts')
<script type="text/x-template" id="cart-rule-form-template">
<form method="POST" action="{{ route('admin.cart-rule.store') }}" @submit.prevent="onSubmit" autocomplete="off">
@csrf
<div class="page-header">
<div class="page-title">
<h1>
<i class="icon angle-left-icon back-link" onclick="history.length > 1 ? history.go(-1) : window.location = '{{ url('/admin/dashboard') }}';"></i>
{{ __('admin::app.promotion.add-cart-rule') }}
</h1>
</div>
<div class="page-action">
<button type="submit" class="btn btn-lg btn-primary">
{{ __('admin::app.promotion.save-btn-title') }}
</button>
</div>
</div>
<div class="page-content">
<div class="form-container">
<div>
@csrf()
<accordian :active="true" title="{{ __('admin::app.promotion.information') }}">
<div slot="body">
<div class="control-group" :class="[errors.has('name') ? 'has-error' : '']">
<label for="name" class="required">{{ __('admin::app.promotion.general-info.name') }}</label>
<input type="text" class="control" name="name" v-model="name" v-validate="'required'" value="{{ old('name') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.name') }}&quot;">
<span class="control-error" v-if="errors.has('name')">@{{ errors.first('name') }}</span>
</div>
<div class="control-group" :class="[errors.has('description') ? 'has-error' : '']">
<label for="description">{{ __('admin::app.promotion.general-info.description') }}</label>
<textarea class="control" name="description" v-model="description" value="{{ old('description') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.description') }}&quot;"></textarea>
<span class="control-error" v-if="errors.has('description')">@{{ errors.first('description') }}</span>
</div>
<datetime :name="starts_from">
<div class="control-group" :class="[errors.has('starts_from') ? 'has-error' : '']">
<label for="starts_from">{{ __('admin::app.promotion.general-info.starts-from') }}</label>
<input type="text" class="control" v-model="starts_from" name="starts_from" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.starts-from') }}&quot;">
<span class="control-error" v-if="errors.has('starts_from')">@{{ errors.first('starts_from') }}</span>
</div>
</datetime>
<datetime :name="starts_from">
<div class="control-group" :class="[errors.has('ends_till') ? 'has-error' : '']">
<label for="ends_till">{{ __('admin::app.promotion.general-info.ends-till') }}</label>
<input type="text" class="control" v-model="ends_till" name="ends_till" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.ends-till') }}&quot;">
<span class="control-error" v-if="errors.has('ends_till')">@{{ errors.first('ends_till') }}</span>
</div>
</datetime>
<div class="control-group" :class="[errors.has('customer_groups[]') ? 'has-error' : '']">
<label for="customer_groups" class="required">{{ __('admin::app.promotion.general-info.cust-groups') }}</label>
<select type="text" class="control" name="customer_groups[]" v-model="customer_groups" v-validate="'required'" value="{{ old('customer_groups[]') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.cust-groups') }}&quot;" multiple="multiple">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Customer Group']) }}</option>
@foreach(app('Webkul\Customer\Repositories\CustomerGroupRepository')->all() as $channel)
<option value="{{ $channel->id }}">{{ $channel->name }}</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('customer_groups[]')">@{{ errors.first('customer_groups[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('channels[]') ? 'has-error' : '']">
<label for="channels" class="required">{{ __('admin::app.promotion.general-info.channels') }}</label>
<select type="text" class="control" name="channels[]" v-model="channels" v-validate="'required'" value="{{ old('channels[]') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.channels-req') }}&quot;" multiple="multiple">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Channels']) }}</option>
@foreach(app('Webkul\Core\Repositories\ChannelRepository')->all() as $channel)
<option value="{{ $channel->id }}">{{ $channel->name }}</option>
@endforeach
</select>
<span class="control-error" v-if="errors.first('channels[]')">@{{ errors.first('channels[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('status') ? 'has-error' : '']">
<label for="status" class="required">{{ __('admin::app.promotion.general-info.status') }}</label>
<select type="text" class="control" name="status" v-model="status" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.status') }}&quot;">
<option value="1">Yes</option>
<option value="0">No</option>
</select>
<span class="control-error" v-if="errors.has('status')">@{{ errors.first('status') }}</span>
</div>
<div class="control-group" :class="[errors.has('use_coupon') ? 'has-error' :
'']">
<label for="customer_groups" class="required">{{ __('admin::app.promotion.general-info.is-coupon') }}</label>
<select type="text" class="control" name="use_coupon" v-model="use_coupon" v-validate="'required'" value="{{ old('use_coupon')}}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.is-coupon') }}&quot;">
<option value="1" :selected="use_coupon == 1">{{ __('admin::app.promotion.general-info.is-coupon-yes') }}</option>
<option value="0" :selected="use_coupon == 0">{{ __('admin::app.promotion.general-info.is-coupon-no') }}</option>
</select>
<span class="control-error" v-if="errors.has('use_coupon')">@{{ errors.first('use_coupon') }}</span>
</div>
{{-- <div class="control-group" :class="[errors.has('auto_generation') ? 'has-error' : '']" v-if="use_coupon == 1">
<label for="auto_generation" class="required">{{ __('admin::app.promotion.general-info.specific-coupon') }}</label>
<input type="checkbox" class="control" name="auto_generation" v-model="auto_generation" value="{{ old('auto_generation') }}" data-vv-as="&quot;Specific Coupon&quot;" v-on:change="checkAutogen">
<span class="control-error" v-if="errors.has('auto_generation')">@{{ errors.first('auto_generation') }}</span>
</div> --}}
{{-- <input type="hidden" name="auto_generation" v-model="auto_generation"> --}}
{{-- <div class="control-group" :class="[errors.has('per_customer') ? 'has-error' : '']">
<label for="per_customer" class="required">{{ __('admin::app.promotion.general-info.uses-per-cust') }}</label>
<input type="number" step="1" class="control" name="per_customer" v-model="per_customer" v-validate="'required|numeric|min_value:0'" value="{{ old('per_customer') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.uses-per-cust') }}&quot;">
<span class="control-error" v-if="errors.has('per_customer')">@{{ errors.first('per_customer') }}</span>
</div>
<div class="control-group" :class="[errors.has('usage_limit') ? 'has-error' : '']">
<label for="usage_limit" class="required">{{ __('admin::app.promotion.general-info.limit') }}</label>
<input type="number" step="1" class="control" name="usage_limit" v-model="usage_limit" v-validate="'required|numeric|min_value:0'" value="{{ old('usage_limit') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.uses-per-cust') }}&quot;">
<span class="control-error" v-if="errors.has('usage_limit')">@{{ errors.first('usage_limit') }}</span>
</div> --}}
<div class="control-group" :class="[errors.has('priority') ? 'has-error' : '']">
<label for="priority" class="required">{{ __('admin::app.promotion.general-info.priority') }}</label>
<input type="number" class="control" step="1" name="priority" v-model="priority" v-validate="'required|numeric|min_value:1'" value="{{ old('priority') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.priority') }}&quot;">
<span class="control-error" v-if="errors.has('priority')">@{{ errors.first('priority') }}</span>
</div>
</div>
</accordian>
<accordian :active="false" title="{{ __('admin::app.promotion.conditions') }}">
<div slot="body">
<input type="hidden" name="all_conditions" v-model="all_conditions">
{{-- <div class="add-condition">
<div class="control-group">
<label for="criteria" class="required">{{ __('admin::app.promotion.general-info.add-condition') }}</label>
<select type="text" class="control" v-model="criteria">
<option value="cart">{{ __('admin::app.promotion.cart-properties') }}</option>
</select>
</div>
</div> --}}
<div class="control-group">
{{ __('admin::app.promotion.general-info.test-mode') }}
<select class="control" v-model="match_criteria" style="margin-right: 15px;">
{{ $i = 0 }}
@foreach(config('pricerules.test_mode') as $key => $value)
<option value="{{ $key }}">{{ $value }}</option>
{{ $i++ }}
@endforeach
</select>
</div>
<div class="condition-set">
<!-- Cart Attributes -->
<div class="control-container mt-20" v-for="(condition, index) in conditions_list" :key="index">
<select class="control" name="cart_attributes[]" v-model="conditions_list[index].attribute" title="You Can Make Multiple Selections Here" style="margin-right: 15px; width: 30%;" v-on:change="enableCondition($event, index)">
<option disabled="disabled">{{ __('admin::app.select-option') }}</option>
<option v-for="(cart_ip, index1) in cart_input" :value="cart_ip.code" :key="index1">@{{ cart_ip.name }}</option>
</select>
<div v-if='conditions_list[index].type == "string"' style="display: flex">
<select class="control" name="cart_attributes[]" v-model="conditions_list[index].condition" style="margin-right: 15px;">
<option v-for="(condition, index) in conditions.string" :value="index" :key="index">@{{ condition }}</option>
</select>
<div v-if='conditions_list[index].attribute == "shipping_state"'>
<select class="control" v-model="conditions_list[index].value">
<option disabled="disabled">{{ __('admin::app.select-option') }}</option>
<optgroup v-for='(state, code) in country_and_states.states' :label="code">
<option v-for="(stateObj, index) in state" :value="stateObj.code">@{{ stateObj.default_name }}</option>
</optgroup>
</select>
</div>
<div v-if='conditions_list[index].attribute == "shipping_country"'>
<select class="control" v-model="conditions_list[index].value">
<option disabled="disabled">{{ __('admin::app.select-option') }}</option>
<option v-for="(country, index) in country_and_states.countries" :value="country.code">@{{ country.name }}</option>
</select>
</div>
<input class="control" type="text" name="cart_attributes[]" v-model="conditions_list[index].value" placeholder="Enter Value" v-if='conditions_list[index].attribute != "shipping_state" && conditions_list[index].attribute != "shipping_country"'>
</div>
<div v-if='conditions_list[index].type == "numeric"' style="display: flex">
<select class="control" name="attributes[]" v-model="conditions_list[index].condition" style="margin-right: 15px;">
<option v-for="(condition, index) in conditions.numeric" :value="index" :key="index">@{{ condition }}</option>
</select>
<input class="control" type="number" step="0.1000" name="cart_attributes[]" v-model="conditions_list[index].value" placeholder="Enter Value">
</div>
<span class="icon trash-icon" v-on:click="removeCartAttr(index)"></span>
</div>
</div>
<span class="btn btn-primary btn-lg mt-20" v-on:click="addCondition">{{ __('admin::app.promotion.add-condition') }}</span>
</div>
</accordian>
<accordian :active="false" title="{{ __('admin::app.promotion.actions') }}">
<div slot="body">
<div class="control-group" :class="[errors.has('action_type') ? 'has-error' : '']">
<label for="action_type" class="required">{{ __('admin::app.action') }}</label>
<select class="control" name="action_type" v-model="action_type" v-validate="'required'" value="{{ old('action_type') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.apply') }}&quot;" v-on:change="detectApply">
<option v-for="(action, index) in actions" :value="index">@{{ action }}</option>
</select>
<span class="control-error" v-if="errors.has('action_type')">@{{ errors.first('action_type') }}</span>
</div>
<div class="control-group" :class="[errors.has('disc_amount') ? 'has-error' : '']">
<label for="disc_amount" class="required">{{ __('admin::app.promotion.general-info.disc_amt') }}</label>
<input type="number" step="0.0001" class="control" name="disc_amount" v-model="disc_amount" v-validate="'required|min_value:0.0001'" value="{{ old('disc_amount') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.disc_amt') }}&quot;">
<span class="control-error" v-if="errors.has('disc_amount')">@{{ errors.first('disc_amount') }}</span>
</div>
{{-- <div class="control-group" :class="[errors.has('disc_threshold') ? 'has-error' : '']">
<label for="disc_threshold" class="required">{{ __('admin::app.promotion.cart.buy-atleast') }}</label>
<input type="number" step="1" class="control" name="disc_threshold" v-model="disc_threshold" v-validate="'required|numeric|min_value:1'" value="{{ old('disc_threshold') }}" data-vv-as="&quot;{{ __('admin::app.promotion.cart.buy-atleast') }}&quot;">
<span class="control-error" v-if="errors.has('disc_threshold')">@{{ errors.first('disc_threshold') }}</span>
</div> --}}
<div class="control-group" :class="[errors.has('disc_quantity') ? 'has-error' : '']">
<label for="disc_quantity" class="required">{{ __('admin::app.promotion.general-info.disc_qty') }}</label>
<input type="number" step="1" class="control" name="disc_quantity" v-model="disc_quantity" v-validate="'required|decimal|min_value:1'" value="{{ old('disc_quantity') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.disc_qty') }}&quot;">
<span class="control-error" v-if="errors.has('disc_quantity')">@{{ errors.first('disc_quantity') }}</span>
</div>
<div class="boolean-control-container">
<div class="control-group" :class="[errors.has('free_shipping') ? 'has-error' : '']">
<label for="free_shipping" class="required">{{ __('admin::app.promotion.general-info.free-shipping') }}</label>
<select type="text" class="control" name="free_shipping" v-model="free_shipping" v-validate="'required'" value="{{ old('free_shipping') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.free-shipping') }}&quot;">
<option value="1">{{ __('admin::app.promotion.general-info.is-coupon-yes') }}</option>
<option value="0">{{ __('admin::app.promotion.general-info.is-coupon-no') }}</option>
</select>
<span class="control-error" v-if="errors.has('free_shipping')">@{{ errors.first('free_shipping') }}</span>
</div>
<div class="control-group" :class="[errors.has('apply_to_shipping') ? 'has-error' : '']">
<label for="customer_groups" class="required">{{ __('admin::app.promotion.cart.apply-to-shipping') }}</label>
<select type="text" class="control" name="apply_to_shipping" v-model="apply_to_shipping" v-validate="'required'" value="{{ old('apply_to_shipping') }}" data-vv-as="&quot;{{ __('admin::app.promotion.cart.apply-to-shipping') }}&quot;">
<option value="1" :selected="apply_to_shipping == 0">{{ __('admin::app.promotion.general-info.is-coupon-yes') }}</option>
<option value="0" :selected="apply_to_shipping == 1">{{ __('admin::app.promotion.general-info.is-coupon-no') }}</option>
</select>
<span class="control-error" v-if="errors.has('apply_to_shipping')">@{{ errors.first('apply_to_shipping') }}</span>
</div>
<div class="control-group" :class="[errors.has('end_other_rules') ? 'has-error' : '']">
<label for="end_other_rules" class="required">{{ __('admin::app.promotion.general-info.end-other-rules') }}</label>
<select type="text" class="control" name="end_other_rules" v-model="end_other_rules" v-validate="'required'" value="{{ old('end_other_rules')}}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.end-other-rules') }}&quot;">
<option value="1" :selected="end_other_rules == 1">{{ __('admin::app.promotion.general-info.is-coupon-yes') }}</option>
<option value="0" :selected="end_other_rules == 0">{{ __('admin::app.promotion.general-info.is-coupon-no') }}</option>
</select>
<span class="control-error" v-if="errors.has('end_other_rules')">@{{ errors.first('end_other_rules') }}</span>
</div>
</div>
</div>
</accordian>
<accordian :active="false" title="{{ __('admin::app.promotion.coupons') }}" v-if="use_coupon == 1">
<div slot="body">
{{-- <div v-if="!auto_generation">
<div class="control-group" :class="[errors.has('prefix') ? 'has-error' : '']">
<label for="prefix" class="required">{{ __('admin::app.promotion.general-info.prefix') }}</label>
<input type="text" class="control" name="prefix" v-model="prefix" v-validate="'alpha'" value="{{ old('prefix') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.prefix') }}&quot;">
<span class="control-error" v-if="errors.has('prefix')">@{{ errors.first('prefix') }}</span>
</div>
<div class="control-group" :class="[errors.has('suffix') ? 'has-error' : '']"">
<label for="suffix" class="required">{{ __('admin::app.promotion.general-info.suffix') }}</label>
<input type="text" class="control" name="suffix" v-model="suffix" v-validate="'alpha'" value="{{ old('suffix') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.suffix') }}&quot;">
<span class="control-error" v-if="errors.has('suffix')">@{{ errors.first('suffix') }}</span>
</div>
</div> --}}
<div>
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
<label for="code" class="required">{{ __('admin::app.promotion.general-info.code') }}</label>
<input type="text" class="control" name="code" v-model="code" v-validate="'required'" value="{{ old('code') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.code') }}&quot;">
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
</div>
</div>
</div>
</accordian>
<accordian :active="true" title="{{ __('admin::app.promotion.select-products') }}">
<div slot="body">
<input type="hidden" name="all_attributes" v-model="all_attributes">
<div class="control-group" :class="[errors.has('category_values') ? 'has-error' : '']">
<label class="mb-10" for="categories">{{ __('admin::app.promotion.select-category') }}</label>
<multiselect v-model="category_values" :close-on-select="false" :options="category_options" :searchable="false" :custom-label="categoryLabel" :show-labels="true" placeholder="Select Categories" track-by="slug" :multiple="true"></multiselect>
</div>
<label class="mb-10" for="attributes">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Attribute']) }}</label>
<br/>
<div class="control-container mt-20" v-for="(condition, index) in attribute_values" :key="index">
<select class="control" v-model="attribute_values[index].attribute" title="You Can Make Multiple Selections Here" style="margin-right: 15px; width: 30%;" v-on:change="enableAttributeCondition($event, index)">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Option']) }}</option>
<option v-for="(attr_ip, index1) in attribute_input" :value="attr_ip.code" :key="index1">@{{ attr_ip.name }}</option>
</select>
<select class="control" v-model="attribute_values[index].condition" style="margin-right: 15px;">
<option v-for="(condition, index) in conditions.string" :value="index" :key="index">@{{ condition }}</option>
</select>
<div v-show='attribute_values[index].type == "select" || attribute_values[index].type == "multiselect"' style="display: flex;">
<select class="control" v-model="attribute_values[index].value" style="margin-right: 15px; height: 100px" :multiple="true">
<option :disabled="true">
{{ __('ui::form.select-attribute', ['attribute' => 'Values']) }}
</option>
<option v-for="(label, index2) in attribute_values[index].options" :value="label.id" :key="index2">@{{ label.admin_name }}</option>
</select>
{{-- <multiselect v-model="attribute_values[index].value" :close-on-select="false" :options="attribute_values[index].options" :searchable="false" :track-by="admin_name" :custom-label="attributeListLabel" :multiple="true" ></multiselect> --}}
</div>
<div v-show='attribute_values[index].type == "text" || attribute_values[index].type == "textarea" || attribute_values[index].type == "price" || attribute_values[index].type == "textarea"' style="display: flex">
<input class="control" v-model="attribute_values[index].value" type="text" placeholder="{{ __('ui::form.enter-attribute', ['attribute' => 'Text']) }}">
</div>
<span class="icon trash-icon" v-on:click="removeAttr(index)"></span>
</div>
<span class="btn btn-primary btn-lg mt-20" v-on:click="addAttributeCondition">{{ __('admin::app.promotion.add-attr-condition') }}</span>
</div>
</accordian>
<accordian :active="false" :title="'{{ __('admin::app.promotion.general-info.labels') }}'">
<div slot="body">
<div class="control-group" :class="[errors.has('label') ? 'has-error' : '']" v-if="dedicated_label">
<label for="label">{{ __('admin::app.promotion.general-info.global-label') }}</label>
<input type="text" class="control" name="label[global]" v-model="label.global" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.label') }}&quot;">
<span class="control-error" v-if="errors.has('label')">@{{ errors.first('label') }}</span>
</div>
<div v-if="label.global == null || label.global == ''">
@foreach(core()->getAllChannels() as $channel)
@foreach($channel->locales as $locale)
<div class="control-group" :class="[errors.has('label') ? 'has-error' : '']">
<label for="code">{{ __('admin::app.label') }}<span class="locale">[{{ $channel->code }} - {{ $locale->code }}]</span></label>
<input type="text" class="control" name="label[{{ $channel->code }}][{{ $locale->code }}]" v-model="label.{{ $channel->code }}.{{ $locale->code }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.label') }}&quot;">
<span class="control-error" v-if="errors.has('label')">@{{ errors.first('label') }}</span>
</div>
@endforeach
@endforeach
</div>
</div>
</accordian>
</div>
</div>
</div>
</form>
</script>
<script>
Vue.component('cart-rule', {
template: '#cart-rule-form-template',
inject: ['$validator'],
data () {
return {
name: null,
description: null,
conditions_list: [],
channels: ['{{ core()->getCurrentChannel()->id }}'],
customer_groups: ['{{ app('Webkul\Customer\Repositories\CustomerGroupRepository')->findOneWhere(["code" => "general"])->id }}'],
ends_till: null,
starts_from: null,
priority: 0,
per_customer: 0,
status: 0,
use_coupon: 0,
auto_generation: false,
usage_limit: 0,
action_type: null,
apply: null,
apply_to_shipping: 0,
disc_amount: 1,
// disc_threshold: null,
disc_quantity: 1,
end_other_rules: 0,
coupon_type: null,
free_shipping: 0,
all_conditions: [],
match_criteria: 'all_are_true',
all_attributes: {
'categories' : [],
'attributes' : []
},
code: null,
suffix: null,
prefix: null,
dedicated_label: true,
label: {
global: null,
@foreach(core()->getAllChannels() as $channel)
@foreach($channel->locales as $locale)
{{ trim($channel->code) }} : {
{{ trim($locale->code) }}: ''
},
@endforeach
@endforeach
},
criteria: 'cart',
conditions: @json($cart_rule[0]).conditions,
cart_input: @json($cart_rule[0]).attributes,
actions: @json($cart_rule[0]).actions,
cart_object: {
attribute: [],
condition: [],
value: []
},
country_and_states: @json($cart_rule[2]),
category_options: @json($cart_rule[1]),
category_values: [],
attribute_values: [],
attr_object: {
attribute: null,
condition: null,
value: [],
options: []
},
attribute_input: @json($cart_rule[3]),
}
},
methods: {
categoryLabel (option) {
return option.name + ' [ ' + option.slug + ' ]';
},
attributeListLabel(option) {
return option.label;
},
addCondition () {
if (this.criteria == 'product_subselection' || this.criteria == 'cart') {
this.condition_on = this.criteria;
} else {
alert('Please select type of condition');
return false;
}
if (this.condition_on == 'cart') {
this.conditions_list.push(this.cart_object);
this.cart_object = {
attribute: null,
condition: null,
value: []
};
}
},
addAttributeCondition() {
this.attribute_values.push(this.attr_object);
this.attr_object = {
attribute: null,
condition: null,
value: [],
options: []
};
},
checkAutogen() {
},
detectApply() {
return;
},
enableCondition(event, index) {
selectedIndex = event.target.selectedIndex - 1;
for (i in this.cart_input) {
if (i == selectedIndex) {
this.conditions_list[index].type = this.cart_input[i].type;
}
}
},
enableAttributeCondition (event, index) {
selectedIndex = event.target.selectedIndex - 1;
for(i in this.attribute_input) {
if (i == selectedIndex) {
if (this.attribute_input[i].has_options == true) {
this.attribute_values[index].options = this.attribute_input[i].options;
}
this.attribute_values[index].type = this.attribute_input[i].type;
}
}
},
// useCoupon() {
// if (this.use_coupon == 0) {
// this.auto_generation = null;
// } else {
// this.auto_generation = true;
// }
// },
removeCartAttr(index) {
this.conditions_list.splice(index, 1);
},
removeAttr(index) {
this.attribute_values.splice(index, 1);
},
onSubmit: function (e) {
if (this.attribute_values.length != 0 || this.category_values.length != 0) {
for (i in this.attribute_values) {
delete this.attribute_values[i].options;
}
this.all_attributes.categories = this.category_values;
this.all_attributes.attributes = this.attribute_values;
}
this.all_attributes = JSON.stringify(this.all_attributes);
if (this.conditions_list != null && this.conditions_list.length != 0) {
this.conditions_list.push({'criteria': this.match_criteria});
this.all_conditions = JSON.stringify(this.conditions_list);
this.conditions_list.pop();
}
this.$validator.validateAll().then(result => {
if (result) {
e.target.submit();
}
});
},
addFlashMessages() {
const flashes = this.$refs.flashes;
flashMessages.forEach(function(flash) {
flashes.addFlash(flash);
}, this);
}
}
});
</script>
@endpush
@stop

View File

@ -1,740 +0,0 @@
@extends('admin::layouts.content')
@section('page_title')
{{ __('admin::app.promotion.edit-cart-rule') }}
@stop
@section('content')
<div class="content">
<cart-rule></cart-rule>
</div>
@push('scripts')
<script type="text/x-template" id="cart-rule-form-template">
<form method="POST" action="{{ route('admin.cart-rule.update', $cart_rule[3]->id) }}" @submit.prevent="onSubmit">
@csrf
<div class="page-header">
<div class="page-title">
<h1>
<i class="icon angle-left-icon back-link" onclick="history.length > 1 ? history.go(-1) : window.location = '{{ url('/admin/dashboard') }}';"></i>
{{ __('admin::app.promotion.edit-cart-rule') }}
</h1>
</div>
<div class="page-action">
<button type="submit" class="btn btn-lg btn-primary">
{{ __('admin::app.promotion.save') }}
</button>
</div>
</div>
<div class="page-content">
<div class="form-container">
<div>
@csrf()
<accordian :active="true" title="{{ __('admin::app.promotion.information') }}">
<div slot="body">
<input type="hidden" name="all_conditions" v-model="all_conditions">
<div class="control-group" :class="[errors.has('name') ? 'has-error' : '']">
<label for="name" class="required">{{ __('admin::app.promotion.general-info.name') }}</label>
<input type="text" class="control" name="name" v-model="name" v-validate="'required'" value="{{ old('name') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.name') }}&quot;">
<span class="control-error" v-if="errors.has('name')">@{{ errors.first('name') }}</span>
</div>
<div class="control-group" :class="[errors.has('description') ? 'has-error' : '']">
<label for="description">{{ __('admin::app.promotion.general-info.description') }}</label>
<textarea class="control" name="description" v-model="description" value="{{ old('description') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.description') }}&quot;"></textarea>
<span class="control-error" v-if="errors.has('description')">@{{ errors.first('description') }}</span>
</div>
<datetime :name="starts_from">
<div class="control-group" :class="[errors.has('starts_from') ? 'has-error' : '']">
<label for="starts_from">{{ __('admin::app.promotion.general-info.starts-from') }}</label>
<input type="text" class="control" v-model="starts_from" name="starts_from" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.starts-from') }}&quot;">
<span class="control-error" v-if="errors.has('starts_from')">@{{ errors.first('starts_from') }}</span>
</div>
</datetime>
<datetime :name="starts_from">
<div class="control-group" :class="[errors.has('ends_till') ? 'has-error' : '']">
<label for="ends_till">{{ __('admin::app.promotion.general-info.ends-till') }}</label>
<input type="text" class="control" v-model="ends_till" name="ends_till" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.ends-till') }}&quot;">
<span class="control-error" v-if="errors.has('ends_till')">@{{ errors.first('ends_till') }}</span>
</div>
</datetime>
<div class="control-group" :class="[errors.has('customer_groups[]') ? 'has-error' : '']">
<label for="customer_groups" class="required">{{ __('admin::app.promotion.general-info.cust-groups') }}</label>
<select type="text" class="control" name="customer_groups[]" v-model="customer_groups" v-validate="'required'" value="{{ old('customer_groups[]') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.cust-groups') }}&quot;" multiple="multiple">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Customer Group']) }}</option>
@foreach(app('Webkul\Customer\Repositories\CustomerGroupRepository')->all() as $customerGroup)
<option value="{{ $customerGroup->id }}">{{ $customerGroup->name }}</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('customer_groups[]')">@{{ errors.first('customer_groups[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('channels[]') ? 'has-error' : '']">
<label for="channels" class="required">{{ __('admin::app.promotion.general-info.channels') }}</label>
<select type="text" class="control" name="channels[]" v-model="channels" v-validate="'required'" value="{{ old('channels[]') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.channels-req') }}&quot;" multiple="multiple">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Channels']) }}</option>
@foreach(app('Webkul\Core\Repositories\ChannelRepository')->all() as $channel)
<option value="{{ $channel->id }}">{{ $channel->name }}</option>
@endforeach
</select>
<span class="control-error" v-if="errors.first('channels[]')">@{{ errors.first('channels[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('status') ? 'has-error' : '']">
<label for="status" class="required">{{ __('admin::app.promotion.general-info.status') }}</label>
<select type="text" class="control" name="status" v-model="status" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.status') }}&quot;">
{{-- <option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Status']) }}</option> --}}
<option value="1">{{ __('admin::app.promotion.yes') }}</option>
<option value="0">{{ __('admin::app.promotion.no') }}</option>
</select>
<span class="control-error" v-if="errors.has('status')">@{{ errors.first('status') }}</span>
</div>
<div class="control-group" :class="[errors.has('use_coupon') ? 'has-error' :
'']">
<label for="customer_groups" class="required">{{ __('admin::app.promotion.general-info.is-coupon') }}</label>
<select type="text" class="control" name="use_coupon" v-model="use_coupon" v-validate="'required'" value="{{ old('use_coupon')}}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.is-coupon') }}&quot;" v-on:change="useCoupon">
<option value="1" :selected="use_coupon == 1">{{ __('admin::app.promotion.general-info.is-coupon-yes') }}</option>
<option value="0" :selected="use_coupon == 0">{{ __('admin::app.promotion.general-info.is-coupon-no') }}</option>
</select>
<span class="control-error" v-if="errors.has('use_coupon')">@{{ errors.first('use_coupon') }}</span>
</div>
{{-- <div class="control-group" :class="[errors.has('auto_generation') ? 'has-error' : '']" v-if="use_coupon == 1">
<label for="auto_generation" class="required">{{ __('admin::app.promotion.general-info.specific-coupon') }}</label>
<input type="checkbox" class="control" name="auto_generation" v-model="auto_generation" value="{{ old('auto_generation') }}" data-vv-as="&quot;Specific Coupon&quot;" v-on:change="checkAutogen">
<span class="control-error" v-if="errors.has('auto_generation')">@{{ errors.first('auto_generation') }}</span>
</div> --}}
{{-- <input type="hidden" name="auto_generation" v-model="auto_generation"> --}}
{{-- <div class="control-group" :class="[errors.has('per_customer') ? 'has-error' : '']">
<label for="per_customer" class="required">{{ __('admin::app.promotion.general-info.uses-per-cust') }}</label>
<input type="number" step="1" class="control" name="per_customer" v-model="per_customer" v-validate="'required|numeric|min_value:0'" value="{{ old('per_customer') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.uses-per-cust') }}&quot;">
<figcaption class="required">* {{ __('admin::app.promotion.zero-unlimited') }}</figcaption>
<span class="control-error" v-if="errors.has('per_customer')">@{{ errors.first('per_customer') }}</span>
</div>
<div class="control-group" :class="[errors.has('usage_limit') ? 'has-error' : '']">
<label for="usage_limit" class="required">{{ __('admin::app.promotion.general-info.limit') }}</label>
<input type="number" step="1" class="control" name="usage_limit" v-model="usage_limit" v-validate="'required|numeric|min_value:0'" value="{{ old('usage_limit') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.uses-per-cust') }}&quot;">
<figcaption class="required">* {{ __('admin::app.promotion.zero-unlimited') }}</figcaption>
<span class="control-error" v-if="errors.has('usage_limit')">@{{ errors.first('usage_limit') }}</span>
</div> --}}
<div class="control-group" :class="[errors.has('priority') ? 'has-error' : '']">
<label for="priority" class="required">{{ __('admin::app.promotion.general-info.priority') }}</label>
<input type="number" class="control" step="1" name="priority" v-model="priority" v-validate="'required|numeric|min_value:1'" value="{{ old('priority') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.priority') }}&quot;">
<span class="control-error" v-if="errors.has('priority')">@{{ errors.first('priority') }}</span>
</div>
</div>
</accordian>
<accordian :active="false" title="{{ __('admin::app.promotion.conditions') }}">
<div slot="body">
<input type="hidden" name="all_conditions" v-model="all_conditions">
{{-- <div class="add-condition">
<div class="control-group">
<label for="criteria" class="required">{{ __('admin::app.promotion.general-info.add-condition') }}</label>
<select type="text" class="control" v-model="criteria">
<option value="cart">Cart Properties</option>
</select>
</div>
</div> --}}
<div class="control-group">
{{ __('admin::app.promotion.general-info.test-mode') }}
<select class="control" v-model="match_criteria" style="margin-right: 15px;">
{{ $i = 0 }}
@foreach(config('pricerules.test_mode') as $key => $value)
<option value="{{ $key }}">{{ $value }}</option>
{{ $i++ }}
@endforeach
</select>
</div>
<div class="condition-set">
<!-- Cart Attributes -->
<div class="control-container mt-20" v-for="(condition, index) in conditions_list" :key="index">
<select class="control" name="cart_attributes[]" v-model="conditions_list[index].attribute" title="You Can Make Multiple Selections Here" style="margin-right: 15px; width: 30%;" v-on:change="enableCondition($event, index)">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Option']) }}</option>
<option v-for="(cart_ip, index1) in cart_input" :value="cart_ip.code" :key="index1">@{{ cart_ip.name }}</option>
</select>
<div v-if='conditions_list[index].type == "string"' style="display: flex">
<select class="control" name="cart_attributes[]" v-model="conditions_list[index].condition" style="margin-right: 15px;">
<option v-for="(condition, index) in conditions.string" :value="index" :key="index">@{{ condition }}</option>
</select>
<div v-if='conditions_list[index].attribute == "shipping_state"'>
<select class="control" v-model="conditions_list[index].value">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'State']) }}</option>
<optgroup v-for='(state, code) in country_and_states.states' :label="code">
<option v-for="(stateObj, index) in state" :value="stateObj.code">@{{ stateObj.default_name }}</option>
</optgroup>
</select>
</div>
<div v-if='conditions_list[index].attribute == "shipping_country"'>
<select class="control" v-model="conditions_list[index].value">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Country']) }}</option>
<option v-for="(country, index) in country_and_states.countries" :value="country.code">@{{ country.name }}</option>
</select>
</div>
<input class="control" type="text" name="cart_attributes[]" v-model="conditions_list[index].value" placeholder="{{ __('admin::app.promotion.enter-attribtue', ['attrbibute' => 'Value']) }}" v-if='conditions_list[index].attribute != "shipping_state" && conditions_list[index].attribute != "shipping_country"'>
</div>
<div v-if='conditions_list[index].type == "numeric"' style="display: flex">
<select class="control" name="attributes[]" v-model="conditions_list[index].condition" style="margin-right: 15px;">
<option v-for="(condition, index) in conditions.numeric" :value="index" :key="index">@{{ condition }}</option>
</select>
<input class="control" type="number" step="0.1000" name="cart_attributes[]" v-model="conditions_list[index].value">
</div>
<span class="icon trash-icon" v-on:click="removeCartAttr(index)"></span>
</div>
</div>
<span class="btn btn-primary btn-lg mt-20" v-on:click="addCondition">{{ __('admin::app.promotion.add-condition') }}</span>
</div>
</accordian>
<accordian :active="false" title="{{ __('admin::app.promotion.actions') }}">
<div slot="body">
<div class="control-group" :class="[errors.has('action_type') ? 'has-error' : '']">
<label for="action_type" class="required">{{ __('admin::app.action') }}</label>
<select class="control" name="action_type" v-model="action_type" v-validate="'required'" value="{{ old('action_type') }}" data-vv-as="&quot;Apply As&quot;" v-on:change="detectApply">
<option v-for="(action, index) in actions" :value="index">@{{ action }}</option>
</select>
<span class="control-error" v-if="errors.has('action_type')">@{{ errors.first('action_type') }}</span>
</div>
<div class="control-group" :class="[errors.has('disc_amount') ? 'has-error' : '']">
<label for="disc_amount" class="required">{{ __('admin::app.promotion.general-info.disc_amt') }}</label>
<input type="number" step="0.0001" class="control" name="disc_amount" v-model="disc_amount" v-validate="'required|decimal|min_value:0.0001'" value="{{ old('disc_amount') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.disc_amt') }}&quot;">
<span class="control-error" v-if="errors.has('disc_amount')">@{{ errors.first('disc_amount') }}</span>
</div>
<div class="control-group" :class="[errors.has('disc_quantity') ? 'has-error' : '']">
<label for="disc_quantity" class="required">{{ __('admin::app.promotion.general-info.disc_qty') }}</label>
<input type="number" step="1" class="control" name="disc_quantity" v-model="disc_quantity" v-validate="'required|decimal|min_value:1'" value="{{ old('disc_quantity') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.disc_qty') }}&quot;">
<span class="control-error" v-if="errors.has('disc_quantity')">@{{ errors.first('disc_quantity') }}</span>
</div>
<div class="boolean-control-container">
<div class="control-group" :class="[errors.has('free_shipping') ? 'has-error' : '']">
<label for="free_shipping" class="required">{{ __('admin::app.promotion.general-info.free-shipping') }}</label>
<select type="text" class="control" name="free_shipping" v-model="free_shipping" v-validate="'required'" value="{{ old('free_shipping') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.free-shipping') }}&quot;">
<option value="1">{{ __('admin::app.promotion.general-info.is-coupon-yes') }}</option>
<option value="0">{{ __('admin::app.promotion.general-info.is-coupon-no') }}</option>
</select>
<span class="control-error" v-if="errors.has('free_shipping')">@{{ errors.first('free_shipping') }}</span>
</div>
<div class="control-group" :class="[errors.has('apply_to_shipping') ? 'has-error' : '']">
<label for="apply_to_shipping" class="required">{{ __('admin::app.promotion.cart.apply-to-shipping') }}</label>
<select type="text" class="control" name="apply_to_shipping" v-model="apply_to_shipping" v-validate="'required'" value="{{ old('apply_to_shipping') }}" data-vv-as="&quot;{{ __('admin::app.promotion.cart.apply-to-shipping') }}&quot;">
<option value="1">{{ __('admin::app.promotion.general-info.is-coupon-yes') }}</option>
<option value="0">{{ __('admin::app.promotion.general-info.is-coupon-no') }}</option>
</select>
<span class="control-error" v-if="errors.has('apply_to_shipping')">@{{ errors.first('apply_to_shipping') }}</span>
</div>
<div class="control-group" :class="[errors.has('end_other_rules') ? 'has-error' : '']">
<label for="end_other_rules" class="required">{{ __('admin::app.promotion.general-info.end-other-rules') }}</label>
<select type="text" class="control" name="end_other_rules" v-model="end_other_rules" v-validate="'required'" value="{{ old('end_other_rules')}}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.end-other-rules') }}&quot;">
<option value="1" :selected="end_other_rules == 1">{{ __('admin::app.promotion.general-info.is-coupon-yes') }}</option>
<option value="0" :selected="end_other_rules == 0">{{ __('admin::app.promotion.general-info.is-coupon-no') }}</option>
</select>
<span class="control-error" v-if="errors.has('end_other_rules')">@{{ errors.first('end_other_rules') }}</span>
</div>
</div>
</div>
</accordian>
<accordian :active="false" title="{{ __('admin::app.promotion.coupons') }}" v-if="use_coupon == 1">
<div slot="body">
{{-- <div v-if="!auto_generation">
<div class="control-group" :class="[errors.has('prefix') ? 'has-error' : '']">
<label for="prefix" class="required">{{ __('admin::app.promotion.general-info.prefix') }}</label>
<input type="text" class="control" name="prefix" v-model="prefix" value="{{ old('prefix') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.prefix') }}&quot;">
<span class="control-error" v-if="errors.has('prefix')">@{{ errors.first('prefix') }}</span>
</div>
<div class="control-group" :class="[errors.has('suffix') ? 'has-error' : '']"">
<label for="suffix" class="required">{{ __('admin::app.promotion.general-info.suffix') }}</label>
<input type="text" class="control" name="suffix" v-model="suffix" value="{{ old('suffix') }}" data-vv-as="&quot;suffix&quot;">
<span class="control-error" v-if="errors.has('suffix')">@{{ errors.first('suffix') }}</span>
</div>
</div> --}}
{{-- <div v-if="auto_generation != 0"> --}}
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
<label for="code" class="required">{{ __('admin::app.promotion.general-info.code') }}</label>
<input type="text" class="control" name="code" v-model="code" v-validate="'required'" value="{{ old('code') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.code') }}&quot;">
<span class="control-error" v-if="errors.has('code')">@{{ errors.first('code') }}</span>
</div>
{{-- </div> --}}
</div>
</accordian>
<accordian :active="true" title="{{ __('admin::app.promotion.select-products') }}">
<div slot="body">
<input type="hidden" name="all_attributes" v-model="all_attributes">
<span class="info mb-20" style="display: block;">
<b>{{ __('admin::app.promotion.note') }}:</b>
{{ __('admin::app.promotion.convert-x-note') }}
</span>
<div class="control-group" :class="[errors.has('category_values') ? 'has-error' : '']">
<label class="mb-10" for="categories">{{ __('admin::app.promotion.select-category') }}</label>
<multiselect v-model="category_values" :close-on-select="false" :options="category_options" :searchable="false" :custom-label="categoryLabel" :show-labels="true" placeholder="{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Categories']) }}" track-by="slug" :multiple="true"></multiselect>
</div>
<label class="mb-10" for="attributes">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Option']) }}</label>
<br/>
<div class="control-container mt-20" v-for="(condition, index) in attribute_values" :key="index">
<select class="control" v-model="attribute_values[index].attribute" title="You Can Make Multiple Selections Here" style="margin-right: 15px; width: 30%;" v-on:change="enableAttributeCondition($event, index)">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Option']) }}</option>
<option v-for="(attr_ip, index1) in attribute_input" :value="attr_ip.code" :key="index1">@{{ attr_ip.name }}</option>
</select>
<select class="control" v-model="attribute_values[index].condition" style="margin-right: 15px;">
<option v-for="(condition, index) in conditions.string" :value="index" :key="index">@{{ condition }}</option>
</select>
<div v-show='attribute_values[index].type == "select" || attribute_values[index].type == "multiselect"' style="display: flex;">
<select class="control" v-model="attribute_values[index].value" style="margin-right: 15px; height: 100px" :multiple="true">
<option :disabled="true">
{{ __('ui::form.select-attribute', ['attribute' => 'Values']) }}
</option>
<option v-for="(label, index2) in attribute_values[index].options" :value="label.id" :key="index2">@{{ label.admin_name }}</option>
</select>
{{-- <multiselect v-model="attribute_values[index].value" :close-on-select="false" :options="attribute_values[index].options" :searchable="false" :track-by="admin_name" :custom-label="attributeListLabel" :multiple="true" ></multiselect> --}}
</div>
<div v-show='attribute_values[index].type == "text" || attribute_values[index].type == "textarea" || attribute_values[index].type == "price" || attribute_values[index].type == "textarea"' style="display: flex">
<input class="control" v-model="attribute_values[index].value" type="text" placeholder="{{ __('ui::form.enter-attribute', ['attribute' => 'Text']) }}">
</div>
<span class="icon trash-icon" v-on:click="removeAttr(index)"></span>
</div>
<span class="btn btn-primary btn-lg mt-20" v-on:click="addAttributeCondition">{{ __('admin::app.promotion.add-attr-condition') }}</span>
</div>
</accordian>
<accordian :active="false" :title="'{{ __('admin::app.promotion.general-info.labels') }}'">
<div slot="body">
@foreach($cart_rule[3]->labels as $label)
<div class="control-group" :class="[errors.has('label') ? 'has-error' : '']">
<label for="code">{{ __('admin::app.label') }}
<span class="locale">[{{ $label->channel->code }} - {{ $label->locale->code }}]</span>
</label>
<input type="text" class="control" name="label[{{ $label->channel->code }}][{{ $label->locale->code }}]" value="{{ $label->label }}" data-vv-as="&quot;Label&quot;">
<span class="control-error" v-if="errors.has('label')">@{{ errors.first('label') }}</span>
</div>
@endforeach
</div>
</accordian>
</div>
</div>
</div>
</form>
</script>
<script>
Vue.component('cart-rule', {
template: '#cart-rule-form-template',
inject: ['$validator'],
data () {
return {
name: '{{ __('admin::app.promotion.rule-name') }}',
description: '{{ __('admin::app.promotion.rule-desc') }}',
channels: [],
customer_groups: [],
ends_till: null,
starts_from: null,
priority: 0,
per_customer: 0,
status: null,
use_coupon: null,
// auto_generation: 0,
usage_limit: 0,
action_type: null,
apply: null,
apply_to_shipping: null,
disc_amount: null,
disc_quantity: null,
end_other_rules: null,
coupon_type: null,
free_shipping: null,
all_conditions: null,
match_criteria: 'all_are_true',
all_attributes: {
'categories' : null,
'attributes' : null
},
code: null,
suffix: null,
prefix: null,
dedicated_label: true,
global_label: null,
labels: [],
// label: {
// @foreach(core()->getAllChannels() as $channel)
// @foreach($channel->locales as $locale)
// {{ trim($channel->code) }} : null,
// @endforeach
// @endforeach
// },
criteria: 'cart',
conditions: @json($cart_rule[0]).conditions,
cart_input: @json($cart_rule[0]).attributes,
actions: @json($cart_rule[0]).actions,
conditions_list:[],
cart_object: {
attribute: null,
condition: null,
value: []
},
country_and_states: @json($cart_rule[2]),
category_options: @json($cart_rule[1]),
category_values: [],
attribute_values: [],
attr_object: {
attribute: null,
condition: null,
value: [],
options: []
},
attribute_input: @json($cart_rule[4]),
}
},
mounted () {
data = @json($cart_rule[3]);
this.name = data.name;
this.description = data.description;
this.channels = [];
for (i in data.channels) {
this.channels.push(data.channels[i].channel_id);
}
this.customer_groups = data.customer_groups;
for (i in data.customer_groups) {
this.customer_groups.push(data.customer_groups[i].customer_group_id);
}
this.ends_till = data.ends_till;
this.starts_from = data.starts_from;
this.priority = data.priority;
this.per_customer = data.per_customer;
this.status = data.status;
if (data.use_coupon == 0) {
// this.auto_generation = null;
this.use_coupon = 0;
} else {
this.use_coupon = 1;
// this.auto_generation = data.auto_generation;
this.code = data.coupons.code;
// this.suffix = data.coupons.suffix;
// this.prefix = data.coupons.prefix;
// if (data.auto_generation == 0)
// this.auto_generation = true;
// else
// this.auto_generation = false;
}
this.usage_limit = data.usage_limit;
this.is_guest = data.is_guest;
this.action_type = data.action_type;
this.apply = null;
this.apply_to_shipping = data.apply_to_shipping;
this.disc_amount = data.disc_amount;
// this.disc_threshold = data.disc_threshold;
this.disc_quantity = data.disc_quantity;
this.end_other_rules = data.end_other_rules;
this.coupon_type = data.coupon_type;
this.free_shipping = data.free_shipping;
this.all_conditions = null;
if (data.hasOwnProperty('conditions') && data.conditions != null) {
this.conditions_list = JSON.parse(JSON.parse(data.conditions));
this.match_criteria = this.conditions_list.pop().criteria;
}
hasSubSelectionConditions = JSON.parse(data.actions).hasOwnProperty('attribute_conditions');
if (hasSubSelectionConditions) {
if (JSON.parse(data.actions).attribute_conditions.hasOwnProperty('categories')) {
this.category_values = JSON.parse(data.actions).attribute_conditions.categories;
} else {
this.category_values = [];
}
if (JSON.parse(data.actions).attribute_conditions.hasOwnProperty('attributes')) {
this.attribute_values = JSON.parse(data.actions).attribute_conditions.attributes;
} else {
this.attribute_values = [];
}
// creating options and has option param on the frontend
for (i in this.attribute_values) {
for (j in this.attribute_input) {
if (this.attribute_input[j].code == this.attribute_values[i].attribute) {
if (this.attribute_input[j].has_options == true) {
this.attribute_values[i].has_options = true;
this.attribute_values[i].options = this.attribute_input[j].options;
} else {
this.attribute_values[i].has_options = false;
this.attribute_values[i].options = null;
}
}
}
}
}
criteria = null;
},
methods: {
categoryLabel (option) {
return option.name + ' [ ' + option.slug + ' ]';
},
attributeListLabel(option) {
return option.label;
},
addCondition () {
if (this.criteria == 'product_subselection' || this.criteria == 'cart') {
this.condition_on = this.criteria;
} else {
alert('please select type of condition');
return false;
}
if (this.condition_on == 'cart') {
this.conditions_list.push(this.cart_object);
this.cart_object = {
attribute: null,
condition: null,
value: []
};
}
},
addAttributeCondition() {
this.attribute_values.push(this.attr_object);
this.attr_object = {
attribute: null,
condition: null,
value: [],
options: []
};
},
checkAutogen() {
},
detectApply() {
return;
},
enableCondition(event, index) {
selectedIndex = event.target.selectedIndex - 1;
for (i in this.cart_input) {
if (i == selectedIndex) {
this.conditions_list[index].type = this.cart_input[i].type;
}
}
},
enableAttributeCondition (event, index) {
selectedIndex = event.target.selectedIndex - 1;
for(i in this.attribute_input) {
if (i == selectedIndex) {
if (this.attribute_input[i].has_options == true) {
this.attribute_values[index].options = this.attribute_input[i].options;
}
this.attribute_values[index].type = this.attribute_input[i].type;
}
}
},
useCoupon() {
if (this.use_coupon == 0) {
this.auto_generation = null;
} else {
this.auto_generation = true;
}
},
removeCartAttr(index) {
this.conditions_list.splice(index, 1);
},
removeCat(index) {
this.cats.splice(index, 1);
},
removeAttr(index) {
this.attribute_values.splice(index, 1);
},
onSubmit: function (e) {
if (this.attribute_values.length != 0 || this.category_values.length != 0) {
for (i in this.attribute_values) {
delete this.attribute_values[i].options;
}
this.all_attributes.categories = this.category_values;
this.all_attributes.attributes = this.attribute_values;
this.all_attributes = JSON.stringify(this.all_attributes);
} else {
this.all_attributes = null;
}
if (this.conditions_list.length != 0) {
this.conditions_list.push({'criteria': this.match_criteria});
this.all_conditions = JSON.stringify(this.conditions_list);
this.conditions_list.pop();
}
this.$validator.validateAll().then(result => {
if (result) {
e.target.submit();
}
});
},
addFlashMessages() {
const flashes = this.$refs.flashes;
flashMessages.forEach(function(flash) {
flashes.addFlash(flash);
}, this);
}
}
});
</script>
@endpush
@stop

View File

@ -0,0 +1,614 @@
@extends('admin::layouts.content')
@section('page_title')
{{ __('admin::app.promotions.cart-rules.add-title') }}
@stop
@section('content')
<div class="content">
<cart-rule></cart-rule>
</div>
@stop
@push('scripts')
@parent
<script type="text/x-template" id="cart-rule-template">
<div>
<form method="POST" action="{{ route('admin.cart-rules.store') }}" @submit.prevent="onSubmit">
<div class="page-header">
<div class="page-title">
<h1>
<i class="icon angle-left-icon back-link" @click="redirectBack('{{ url('/admin/dashboard') }}')"></i>
{{ __('admin::app.promotions.cart-rules.add-title') }}
</h1>
</div>
<div class="page-action">
<button type="submit" class="btn btn-lg btn-primary">
{{ __('admin::app.promotions.cart-rules.save-btn-title') }}
</button>
</div>
</div>
<div class="page-content">
<div class="form-container">
@csrf()
{!! view_render_event('bagisto.admin.promotions.cart-rules.create.before') !!}
<accordian :title="'{{ __('admin::app.promotions.cart-rules.rule-information') }}'" :active="true">
<div slot="body">
<div class="control-group" :class="[errors.has('name') ? 'has-error' : '']">
<label for="name" class="required">{{ __('admin::app.promotions.cart-rules.name') }}</label>
<input v-validate="'required'" class="control" id="name" name="name" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.name') }}&quot;" value="{{ old('name') }}"/>
<span class="control-error" v-if="errors.has('name')">@{{ errors.first('name') }}</span>
</div>
<div class="control-group">
<label for="description">{{ __('admin::app.promotions.cart-rules.description') }}</label>
<textarea class="control" id="description" name="description">{{ old('description') }}</textarea>
</div>
<div class="control-group">
<label for="status">{{ __('admin::app.promotions.cart-rules.status') }}</label>
<span class="checkbox">
<input type="checkbox" id="status" name="status" value="1">
<label class="checkbox-view" for="status"></label>
{{ __('admin::app.promotions.cart-rules.is-active') }}
</span>
</div>
<div class="control-group" :class="[errors.has('channels[]') ? 'has-error' : '']">
<label for="channels" class="required">{{ __('admin::app.promotions.cart-rules.channels') }}</label>
<select class="control" id="channels" name="channels[]" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.channels') }}&quot;" multiple="multiple">
@foreach(core()->getAllChannels() as $channel)
<option value="{{ $channel->id }}" {{ old('channels') && in_array($channel->id, old('channels')) ? 'selected' : '' }}>
{{ $channel->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('channels[]')">@{{ errors.first('channels[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('customer_groups[]') ? 'has-error' : '']">
<label for="customer_groups" class="required">{{ __('admin::app.promotions.cart-rules.customer-groups') }}</label>
<select class="control" id="customer_groups" name="customer_groups[]" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.customer-groups') }}&quot;" multiple="multiple">
@foreach(app('Webkul\Customer\Repositories\CustomerGroupRepository')->all() as $customerGroup)
<option value="{{ $customerGroup->id }}" {{ old('customer_groups') && in_array($customerGroup->id, old('customer_groups')) ? 'selected' : '' }}>
{{ $customerGroup->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('customer_groups[]')">@{{ errors.first('customer_groups[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('coupon_type') ? 'has-error' : '']">
<label for="coupon_type" class="required">{{ __('admin::app.promotions.cart-rules.coupon-type') }}</label>
<select class="control" id="coupon_type" name="coupon_type" v-model="coupon_type" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.coupon-type') }}&quot;">
<option value="0" {{ old('coupon_type') == 0 ? 'selected' : '' }}>{{ __('admin::app.promotions.cart-rules.no-coupon') }}</option>
<option value="1" {{ old('coupon_type') == 1 ? 'selected' : '' }}>{{ __('admin::app.promotions.cart-rules.specific-coupon') }}</option>
</select>
<span class="control-error" v-if="errors.has('coupon_type')">@{{ errors.first('coupon_type') }}</span>
</div>
<div v-if="parseInt(coupon_type)">
<div class="control-group" :class="[errors.has('use_auto_generation') ? 'has-error' : '']">
<label for="use_auto_generation" class="required">{{ __('admin::app.promotions.cart-rules.auto-generate-coupon') }}</label>
<select class="control" id="use_auto_generation" name="use_auto_generation" v-model="use_auto_generation" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.auto-generate-coupon') }}&quot;">
<option value="0">{{ __('admin::app.promotions.cart-rules.no') }}</option>
<option value="1">{{ __('admin::app.promotions.cart-rules.yes') }}</option>
</select>
<span class="control-error" v-if="errors.has('use_auto_generation')">@{{ errors.first('use_auto_generation') }}</span>
</div>
<div v-if="! parseInt(use_auto_generation)">
<div class="control-group" :class="[errors.has('coupon_code') ? 'has-error' : '']">
<label for="coupon_code" class="required">{{ __('admin::app.promotions.cart-rules.coupon-code') }}</label>
<input v-validate="'required'" class="control" id="coupon_code" name="coupon_code" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.coupon-code') }}&quot;" value="{{ old('coupon_code') }}"/>
<span class="control-error" v-if="errors.has('coupon_code')">@{{ errors.first('coupon_code') }}</span>
</div>
</div>
<div class="control-group">
<label for="uses_per_coupon">{{ __('admin::app.promotions.cart-rules.uses-per-coupon') }}</label>
<input class="control" id="uses_per_coupon" name="uses_per_coupon" value="{{ old('uses_per_coupon') }}"/>
</div>
</div>
<div class="control-group">
<label for="usage_per_customer">{{ __('admin::app.promotions.cart-rules.uses-per-customer') }}</label>
<input class="control" id="usage_per_customer" name="usage_per_customer" value="{{ old('usage_per_customer') }}"/>
<span class="control-info">{{ __('admin::app.promotions.cart-rules.uses-per-customer-control-info') }}</span>
</div>
<div class="control-group date">
<label for="starts_from">{{ __('admin::app.promotions.cart-rules.from') }}</label>
<date>
<input type="text" name="starts_from" class="control" value="{{ old('starts_from') }}"/>
</date>
</div>
<div class="control-group date">
<label for="ends_till">{{ __('admin::app.promotions.cart-rules.to') }}</label>
<date>
<input type="text" name="ends_till" class="control" value="{{ old('ends_till') }}"/>
</date>
</div>
<div class="control-group">
<label for="sort_order">{{ __('admin::app.promotions.cart-rules.priority') }}</label>
<input type="text" class="control" id="sort_order" name="sort_order" value="{{ old('sort_order') ?? 0 }}"/>
</div>
</div>
</accordian>
<accordian :title="'{{ __('admin::app.promotions.cart-rules.conditions') }}'" :active="false">
<div slot="body">
<div class="control-group">
<label for="condition_type">{{ __('admin::app.promotions.cart-rules.condition-type') }}</label>
<select class="control" id="condition_type" name="condition_type" v-model="condition_type">
<option value="1">{{ __('admin::app.promotions.cart-rules.all-conditions-true') }}</option>
<option value="2">{{ __('admin::app.promotions.cart-rules.any-condition-true') }}</option>
</select>
</div>
<div class="table cart-rule-conditions" style="margin-top: 20px; overflow-x: unset;">
<table>
<tbody>
<cart-rule-condition-item
v-for='(condition, index) in conditions'
:condition="condition"
:key="index"
:index="index"
@onRemoveCondition="removeCondition($event)">
</cart-rule-condition-item>
</tbody>
</table>
</div>
<button type="button" class="btn btn-lg btn-primary" style="margin-top: 20px;" @click="addCondition">
{{ __('admin::app.promotions.cart-rules.add-condition') }}
</button>
</div>
</accordian>
<accordian :title="'{{ __('admin::app.promotions.cart-rules.actions') }}'" :active="false">
<div slot="body">
<div class="control-group" :class="[errors.has('action_type') ? 'has-error' : '']">
<label for="action_type" class="required">{{ __('admin::app.promotions.cart-rules.action-type') }}</label>
<select class="control" id="action_type" name="action_type" v-validate="'required'" v-model="action_type" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.action-type') }}&quot;">
<option value="by_percent" {{ old('action_type') == 'by_percent' ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.percentage-product-price') }}
</option>
<option value="by_fixed" {{ old('action_type') == 'by_fixed' ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.fixed-amount') }}
</option>
<option value="cart_fixed" {{ old('action_type') == 'cart_fixed' ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.fixed-amount-whole-cart') }}
</option>
<option value="buy_x_get_y" {{ old('action_type') == 'buy_x_get_y' ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.buy-x-get-y-free') }}
</option>
</select>
<span class="control-error" v-if="errors.has('action_type')">@{{ errors.first('action_type') }}</span>
</div>
<div class="control-group" :class="[errors.has('discount_amount') ? 'has-error' : '']">
<label for="discount_amount" class="required">{{ __('admin::app.promotions.cart-rules.discount-amount') }}</label>
<input v-validate="'required'" class="control" id="discount_amount" name="discount_amount" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.discount-amount') }}&quot;" value="{{ old('discount_amount') ?? 0 }}"/>
<span class="control-error" v-if="errors.has('discount_amount')">@{{ errors.first('discount_amount') }}</span>
</div>
<div class="control-group">
<label for="discount_quantity">{{ __('admin::app.promotions.cart-rules.discount-quantity') }}</label>
<input class="control" id="discount_quantity" name="discount_quantity" value="{{ old('discount_quantity') ?? 0 }}"/>
</div>
<div class="control-group">
<label for="discount_step">{{ __('admin::app.promotions.cart-rules.discount-step') }}</label>
<input class="control" id="discount_step" name="discount_step" value="{{ old('discount_step') ?? 0 }}"/>
</div>
<div class="control-group">
<label for="apply_to_shipping">{{ __('admin::app.promotions.cart-rules.apply-to-shipping') }}</label>
<select class="control" id="apply_to_shipping" name="apply_to_shipping" :disabled="action_type == 'cart_fixed'">
<option value="0" {{ ! old('apply_to_shipping') ? 'selected' : '' }}>{{ __('admin::app.promotions.cart-rules.no') }}</option>
<option value="1" {{ old('apply_to_shipping') ? 'selected' : '' }}>{{ __('admin::app.promotions.cart-rules.yes') }}</option>
</select>
</div>
<div class="control-group">
<label for="free_shipping">{{ __('admin::app.promotions.cart-rules.free-shipping') }}</label>
<select class="control" id="free_shipping" name="free_shipping">
<option value="0" {{ ! old('free_shipping') ? 'selected' : '' }}>{{ __('admin::app.promotions.cart-rules.no') }}</option>
<option value="1" {{ old('free_shipping') ? 'selected' : '' }}>{{ __('admin::app.promotions.cart-rules.yes') }}</option>
</select>
</div>
<div class="control-group">
<label for="end_other_rules">{{ __('admin::app.promotions.cart-rules.end-other-rules') }}</label>
<select class="control" id="end_other_rules" name="end_other_rules">
<option value="0" {{ ! old('end_other_rules') ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.no') }}
</option>
<option value="1" {{ old('end_other_rules') ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.yes') }}
</option>
</select>
</div>
</div>
</accordian>
{!! view_render_event('bagisto.admin.promotions.cart-rules.create.after') !!}
</div>
</div>
</form>
</div>
</script>
<script type="text/x-template" id="cart-rule-condition-item-template">
<tr>
<td class="attribute">
<div class="control-group">
<select :name="['conditions[' + index + '][attribute]']" class="control" v-model="condition.attribute">
<option value="">{{ __('admin::app.promotions.cart-rules.choose-condition-to-add') }}</option>
<optgroup v-for='(conditionAttribute, index) in condition_attributes' :label="conditionAttribute.label">
<option v-for='(childAttribute, index) in conditionAttribute.children' :value="childAttribute.key">
@{{ childAttribute.label }}
</option>
</optgroup>
</select>
</div>
</td>
<td class="operator">
<div class="control-group" v-if="matchedAttribute">
<select :name="['conditions[' + index + '][operator]']" class="control" v-model="condition.operator">
<option v-for='operator in condition_operators[matchedAttribute.type]' :value="operator.operator">
@{{ operator.label }}
</option>
</select>
</div>
</td>
<td class="value">
<div v-if="matchedAttribute">
<input type="hidden" :name="['conditions[' + index + '][attribute_type]']" v-model="matchedAttribute.type">
<div v-if="matchedAttribute.key == 'product|category_ids' || matchedAttribute.key == 'product|category_ids' || matchedAttribute.key == 'product|parent::category_ids'">
<tree-view value-field="id" id-field="id" :name-field="'conditions[' + index + '][value]'" input-type="checkbox" :items='matchedAttribute.options' :behavior="'no'"></tree-view>
</div>
<div v-else>
<div class="control-group" v-if="matchedAttribute.type == 'text' || matchedAttribute.type == 'price' || matchedAttribute.type == 'decimal' || matchedAttribute.type == 'integer'">
<input class="control" :name="['conditions[' + index + '][value]']" v-model="condition.value"/>
</div>
<div class="control-group date" v-if="matchedAttribute.type == 'date'">
<date>
<input class="control" :name="['conditions[' + index + '][value]']" v-model="condition.value"/>
</date>
</div>
<div class="control-group date" v-if="matchedAttribute.type == 'datetime'">
<datetime>
<input class="control" :name="['conditions[' + index + '][value]']" v-model="condition.value"/>
</datetime>
</div>
<div class="control-group" v-if="matchedAttribute.type == 'boolean'">
<select :name="['conditions[' + index + '][value]']" class="control" v-model="condition.value">
<option value="1">{{ __('admin::app.promotions.cart-rules.yes') }}</option>
<option value="0">{{ __('admin::app.promotions.cart-rules.no') }}</option>
</select>
</div>
<div class="control-group" v-if="matchedAttribute.type == 'select' || matchedAttribute.type == 'radio'">
<select :name="['conditions[' + index + '][value]']" class="control" v-model="condition.value" v-if="matchedAttribute.key != 'cart|state'">
<option v-for='option in matchedAttribute.options' :value="option.id">
@{{ option.admin_name }}
</option>
</select>
<select :name="['conditions[' + index + '][value]']" class="control" v-model="condition.value" v-else>
<optgroup v-for='option in matchedAttribute.options' :label="option.admin_name">
<option v-for='state in option.states' :value="state.code">
@{{ state.admin_name }}
</option>
</optgroup>
</select>
</div>
<div class="control-group" v-if="matchedAttribute.type == 'multiselect' || matchedAttribute.type == 'checkbox'">
<select :name="['conditions[' + index + '][value][]']" class="control" v-model="condition.value" multiple>
<option v-for='option in matchedAttribute.options' :value="option.id">
@{{ option.admin_name }}
</option>
</select>
</div>
</div>
</div>
</td>
<td class="actions">
<i class="icon trash-icon" @click="removeCondition"></i>
</td>
</tr>
</script>
<script>
Vue.component('cart-rule', {
template: '#cart-rule-template',
inject: ['$validator'],
data: function() {
return {
coupon_type: 0,
use_auto_generation: 0,
condition_type: 1,
conditions: [],
action_type: "{{ old('action_type') ?: 'by_percent' }}"
}
},
methods: {
addCondition: function() {
this.conditions.push({
'attribute': '',
'operator': '==',
'value': '',
});
},
removeCondition: function(condition) {
let index = this.conditions.indexOf(condition)
this.conditions.splice(index, 1)
},
onSubmit: function(e) {
this.$root.onSubmit(e)
},
onSubmit: function(e) {
this.$root.onSubmit(e)
},
redirectBack: function(fallbackUrl) {
this.$root.redirectBack(fallbackUrl)
}
}
});
Vue.component('cart-rule-condition-item', {
template: '#cart-rule-condition-item-template',
props: ['index', 'condition'],
data: function() {
return {
condition_attributes: @json(app('\Webkul\CartRule\Repositories\CartRuleRepository')->getConditionAttributes()),
attribute_type_indexes: {
'cart': 0,
'cart_item': 1,
'product': 2
},
condition_operators: {
'price': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-less-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.less-than') }}'
}],
'decimal': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.cart-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.cart-rules.less-than') }}'
}],
'integer': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.cart-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.cart-rules.less-than') }}'
}],
'text': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}, {
'operator': '{}',
'label': '{{ __('admin::app.promotions.cart-rules.contain') }}'
}, {
'operator': '!{}',
'label': '{{ __('admin::app.promotions.cart-rules.does-not-contain') }}'
}],
'boolean': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}],
'date': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.cart-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.cart-rules.less-than') }}'
}],
'datetime': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.cart-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.cart-rules.less-than') }}'
}],
'select': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}],
'radio': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}],
'multiselect': [{
'operator': '{}',
'label': '{{ __('admin::app.promotions.cart-rules.contains') }}'
}, {
'operator': '!{}',
'label': '{{ __('admin::app.promotions.cart-rules.does-not-contain') }}'
}],
'checkbox': [{
'operator': '{}',
'label': '{{ __('admin::app.promotions.cart-rules.contains') }}'
}, {
'operator': '!{}',
'label': '{{ __('admin::app.promotions.cart-rules.does-not-contain') }}'
}]
}
}
},
computed: {
matchedAttribute: function () {
if (this.condition.attribute == '')
return;
var this_this = this;
var attributeIndex = this.attribute_type_indexes[this.condition.attribute.split("|")[0]];
matchedAttribute = this.condition_attributes[attributeIndex]['children'].filter(function (attribute) {
return attribute.key == this_this.condition.attribute;
});
if (matchedAttribute[0]['type'] == 'multiselect' || matchedAttribute[0]['type'] == 'checkbox') {
this.condition.operator = '{}';
this.condition.value = [];
}
return matchedAttribute[0];
}
},
methods: {
removeCondition: function() {
this.$emit('onRemoveCondition', this.condition)
}
}
});
</script>
@endpush

View File

@ -0,0 +1,753 @@
@extends('admin::layouts.content')
@section('page_title')
{{ __('admin::app.promotions.cart-rules.edit-title') }}
@stop
@section('content')
<div class="content">
<cart-rule></cart-rule>
</div>
@stop
@push('scripts')
@parent
<script type="text/x-template" id="cart-rule-template">
<div>
<form method="POST" action="{{ route('admin.cart-rules.update', $cartRule->id) }}" @submit.prevent="onSubmit">
<div class="page-header">
<div class="page-title">
<h1>
<i class="icon angle-left-icon back-link" @click="redirectBack('{{ url('/admin/dashboard') }}')"></i>
{{ __('admin::app.promotions.cart-rules.edit-title') }}
</h1>
</div>
<div class="page-action">
<button type="submit" class="btn btn-lg btn-primary">
{{ __('admin::app.promotions.cart-rules.save-btn-title') }}
</button>
</div>
</div>
<div class="page-content">
<div class="form-container">
@csrf()
{!! view_render_event('bagisto.admin.promotions.cart-rules.create.before') !!}
<accordian :title="'{{ __('admin::app.promotions.cart-rules.rule-information') }}'" :active="true">
<div slot="body">
<div class="control-group" :class="[errors.has('name') ? 'has-error' : '']">
<label for="name" class="required">{{ __('admin::app.promotions.cart-rules.name') }}</label>
<input v-validate="'required'" class="control" id="name" name="name" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.name') }}&quot;" value="{{ old('name') ?: $cartRule->name }}"/>
<span class="control-error" v-if="errors.has('name')">@{{ errors.first('name') }}</span>
</div>
<div class="control-group">
<label for="description">{{ __('admin::app.promotions.cart-rules.description') }}</label>
<textarea class="control" id="description" name="description">{{ old('description') ?: $cartRule->description }}</textarea>
</div>
<div class="control-group">
<label for="status">{{ __('admin::app.promotions.cart-rules.status') }}</label>
<span class="checkbox">
<input type="checkbox" id="status" name="status" value="{{ $cartRule->status }}" {{ $cartRule->status ? 'checked' : '' }}>
<label class="checkbox-view" for="status"></label>
{{ __('admin::app.promotions.cart-rules.is-active') }}
</span>
</div>
<div class="control-group" :class="[errors.has('channels[]') ? 'has-error' : '']">
<label for="channels" class="required">{{ __('admin::app.promotions.cart-rules.channels') }}</label>
<?php $selectedOptionIds = old('channels') ?: $cartRule->channels->pluck('id')->toArray() ?>
<select class="control" id="channels" name="channels[]" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.channels') }}&quot;" multiple="multiple">
@foreach(core()->getAllChannels() as $channel)
<option value="{{ $channel->id }}" {{ in_array($channel->id, $selectedOptionIds) ? 'selected' : '' }}>
{{ $channel->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('channels[]')">@{{ errors.first('channels[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('customer_groups[]') ? 'has-error' : '']">
<label for="customer_groups" class="required">{{ __('admin::app.promotions.cart-rules.customer-groups') }}</label>
<?php $selectedOptionIds = old('customer_groups') ?: $cartRule->customer_groups->pluck('id')->toArray() ?>
<select class="control" id="customer_groups" name="customer_groups[]" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.customer-groups') }}&quot;" multiple="multiple">
@foreach(app('Webkul\Customer\Repositories\CustomerGroupRepository')->all() as $customerGroup)
<option value="{{ $customerGroup->id }}" {{ in_array($customerGroup->id, $selectedOptionIds) ? 'selected' : '' }}>
{{ $customerGroup->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('customer_groups[]')">@{{ errors.first('customer_groups[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('coupon_type') ? 'has-error' : '']">
<label for="coupon_type" class="required">{{ __('admin::app.promotions.cart-rules.coupon-type') }}</label>
<select class="control" id="coupon_type" name="coupon_type" v-model="coupon_type" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.coupon-type') }}&quot;">
<option value="0" {{ old('coupon_type') == 0 ? 'selected' : '' }}>{{ __('admin::app.promotions.cart-rules.no-coupon') }}</option>
<option value="1" {{ old('coupon_type') == 1 ? 'selected' : '' }}>{{ __('admin::app.promotions.cart-rules.specific-coupon') }}</option>
</select>
<span class="control-error" v-if="errors.has('coupon_type')">@{{ errors.first('coupon_type') }}</span>
</div>
<div v-if="parseInt(coupon_type)">
<div class="control-group" :class="[errors.has('use_auto_generation') ? 'has-error' : '']">
<label for="use_auto_generation" class="required">{{ __('admin::app.promotions.cart-rules.auto-generate-coupon') }}</label>
<select class="control" id="use_auto_generation" name="use_auto_generation" v-model="use_auto_generation" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.auto-generate-coupon') }}&quot;">
<option value="0">{{ __('admin::app.promotions.cart-rules.no') }}</option>
<option value="1">{{ __('admin::app.promotions.cart-rules.yes') }}</option>
</select>
<span class="control-error" v-if="errors.has('use_auto_generation')">@{{ errors.first('use_auto_generation') }}</span>
</div>
<div v-if="! parseInt(use_auto_generation)">
<div class="control-group" :class="[errors.has('coupon_code') ? 'has-error' : '']">
<label for="coupon_code" class="required">{{ __('admin::app.promotions.cart-rules.coupon-code') }}</label>
<input v-validate="'required'" class="control" id="coupon_code" name="coupon_code" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.coupon-code') }}&quot;" value="{{ old('coupon_code') ?: $cartRule->coupon_code }}"/>
<span class="control-error" v-if="errors.has('coupon_code')">@{{ errors.first('coupon_code') }}</span>
</div>
</div>
<div class="control-group">
<label for="uses_per_coupon">{{ __('admin::app.promotions.cart-rules.uses-per-coupon') }}</label>
<input class="control" id="uses_per_coupon" name="uses_per_coupon" value="{{ old('uses_per_coupon') ?: $cartRule->uses_per_coupon }}"/>
</div>
</div>
<div class="control-group">
<label for="usage_per_customer">{{ __('admin::app.promotions.cart-rules.uses-per-customer') }}</label>
<input class="control" id="usage_per_customer" name="usage_per_customer" value="{{ old('usage_per_customer') ?: $cartRule->usage_per_customer }}"/>
<span class="control-info">{{ __('admin::app.promotions.cart-rules.uses-per-customer-control-info') }}</span>
</div>
<div class="control-group date">
<label for="starts_from">{{ __('admin::app.promotions.cart-rules.from') }}</label>
<date>
<input type="text" name="starts_from" class="control" value="{{ old('starts_from') ?: $cartRule->starts_from }}"/>
</date>
</div>
<div class="control-group date">
<label for="ends_till">{{ __('admin::app.promotions.cart-rules.to') }}</label>
<date>
<input type="text" name="ends_till" class="control" value="{{ old('ends_till') ?: $cartRule->ends_till }}"/>
</date>
</div>
<div class="control-group">
<label for="sort_order">{{ __('admin::app.promotions.cart-rules.priority') }}</label>
<input type="text" class="control" id="sort_order" name="sort_order" value="{{ $cartRule->sort_order }}" {{ $cartRule->sort_order ? 'checked' : '' }}/>
</div>
</div>
</accordian>
<accordian :title="'{{ __('admin::app.promotions.cart-rules.conditions') }}'" :active="false">
<div slot="body">
<div class="control-group">
<label for="condition_type">{{ __('admin::app.promotions.cart-rules.condition-type') }}</label>
<select class="control" id="condition_type" name="condition_type" v-model="condition_type">
<option value="1">{{ __('admin::app.promotions.cart-rules.all-conditions-true') }}</option>
<option value="2">{{ __('admin::app.promotions.cart-rules.any-condition-true') }}</option>
</select>
</div>
<div class="table cart-rule-conditions" style="margin-top: 20px; overflow-x: unset;">
<table>
<tbody>
<cart-rule-condition-item
v-for='(condition, index) in conditions'
:condition="condition"
:key="index"
:index="index"
@onRemoveCondition="removeCondition($event)">
</cart-rule-condition-item>
</tbody>
</table>
</div>
<button type="button" class="btn btn-lg btn-primary" style="margin-top: 20px;" @click="addCondition">
{{ __('admin::app.promotions.cart-rules.add-condition') }}
</button>
</div>
</accordian>
<accordian :title="'{{ __('admin::app.promotions.cart-rules.actions') }}'" :active="false">
<div slot="body">
<div class="control-group" :class="[errors.has('action_type') ? 'has-error' : '']">
<label for="action_type" class="required">{{ __('admin::app.promotions.cart-rules.action-type') }}</label>
<?php $selectedOption = old('action_type') ?: $cartRule->action_type ?>
<select class="control" id="action_type" name="action_type" v-validate="'required'" v-model="action_type" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.action-type') }}&quot;">
<option value="by_percent" {{ $selectedOption == 'by_percent' ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.percentage-product-price') }}
</option>
<option value="by_fixed" {{ $selectedOption == 'by_fixed' ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.fixed-amount') }}
</option>
<option value="cart_fixed" {{ $selectedOption == 'cart_fixed' ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.fixed-amount-whole-cart') }}
</option>
<option value="buy_x_get_y" {{ $selectedOption == 'buy_x_get_y' ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.buy-x-get-y-free') }}
</option>
</select>
<span class="control-error" v-if="errors.has('action_type')">@{{ errors.first('action_type') }}</span>
</div>
<div class="control-group" :class="[errors.has('discount_amount') ? 'has-error' : '']">
<label for="discount_amount" class="required">{{ __('admin::app.promotions.cart-rules.discount-amount') }}</label>
<input v-validate="'required'" class="control" id="discount_amount" name="discount_amount" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.discount-amount') }}&quot;" value="{{ old('discount_amount') ?: $cartRule->discount_amount }}"/>
<span class="control-error" v-if="errors.has('discount_amount')">@{{ errors.first('discount_amount') }}</span>
</div>
<div class="control-group">
<label for="discount_quantity">{{ __('admin::app.promotions.cart-rules.discount-quantity') }}</label>
<input class="control" id="discount_quantity" name="discount_quantity" value="{{ old('discount_quantity') ?: $cartRule->discount_quantity }}"/>
</div>
<div class="control-group">
<label for="discount_step">{{ __('admin::app.promotions.cart-rules.discount-step') }}</label>
<input class="control" id="discount_step" name="discount_step" value="{{ old('discount_step') ?: $cartRule->discount_step }}"/>
</div>
<div class="control-group">
<label for="apply_to_shipping">{{ __('admin::app.promotions.cart-rules.apply-to-shipping') }}</label>
<?php $selectedOption = old('apply_to_shipping') ?: $cartRule->apply_to_shipping ?>
<select class="control" id="apply_to_shipping" name="apply_to_shipping" :disabled="action_type == 'cart_fixed'">
<option value="0" {{ ! $selectedOption ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.no') }}
</option>
<option value="1" {{ $selectedOption ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.yes') }}
</option>
</select>
</div>
<div class="control-group">
<label for="free_shipping">{{ __('admin::app.promotions.cart-rules.free-shipping') }}</label>
<?php $selectedOption = old('free_shipping') ?: $cartRule->free_shipping ?>
<select class="control" id="free_shipping" name="free_shipping">
<option value="0" {{ ! $selectedOption ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.no') }}
</option>
<option value="1" {{ $selectedOption ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.yes') }}
</option>
</select>
</div>
<div class="control-group">
<label for="end_other_rules">{{ __('admin::app.promotions.cart-rules.end-other-rules') }}</label>
<?php $selectedOption = old('end_other_rules') ?: $cartRule->end_other_rules ?>
<select class="control" id="end_other_rules" name="end_other_rules">
<option value="0" {{ ! $selectedOption ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.no') }}
</option>
<option value="1" {{ $selectedOption ? 'selected' : '' }}>
{{ __('admin::app.promotions.cart-rules.yes') }}
</option>
</select>
</div>
</div>
</accordian>
{!! view_render_event('bagisto.admin.promotions.cart-rules.create.after') !!}
</div>
</div>
</form>
<accordian :title="'{{ __('admin::app.promotions.cart-rules.coupon-codes') }}'" :active="false" v-if="coupon_type && use_auto_generation">
<div slot="body">
<create-coupon-form></create-coupon-form>
</div>
</accordian>
</div>
</script>
<script type="text/x-template" id="cart-rule-condition-item-template">
<tr>
<td class="attribute">
<div class="control-group">
<select :name="['conditions[' + index + '][attribute]']" class="control" v-model="condition.attribute">
<option value="">{{ __('admin::app.promotions.cart-rules.choose-condition-to-add') }}</option>
<optgroup v-for='conditionAttribute in condition_attributes' :label="conditionAttribute.label">
<option v-for='childAttribute in conditionAttribute.children' :value="childAttribute.key">
@{{ childAttribute.label }}
</option>
</optgroup>
</select>
</div>
</td>
<td class="operator">
<div class="control-group" v-if="matchedAttribute">
<select :name="['conditions[' + index + '][operator]']" class="control" v-model="condition.operator">
<option v-for='operator in condition_operators[matchedAttribute.type]' :value="operator.operator">
@{{ operator.label }}
</option>
</select>
</div>
</td>
<td class="value">
<div v-if="matchedAttribute">
<input type="hidden" :name="['conditions[' + index + '][attribute_type]']" v-model="matchedAttribute.type">
<div v-if="matchedAttribute.key == 'product|children::category_ids' || matchedAttribute.key == 'product|category_ids' || matchedAttribute.key == 'product|parent::category_ids'">
<tree-view value-field="id" id-field="id" :name-field="'conditions[' + index + '][value]'" input-type="checkbox" :items='matchedAttribute.options' :value='condition.value' :behavior="'no'"></tree-view>
</div>
<div v-else>
<div class="control-group" v-if="matchedAttribute.type == 'text' || matchedAttribute.type == 'price' || matchedAttribute.type == 'decimal' || matchedAttribute.type == 'integer'">
<input class="control" :name="['conditions[' + index + '][value]']" v-model="condition.value"/>
</div>
<div class="control-group date" v-if="matchedAttribute.type == 'date'">
<date>
<input class="control" :name="['conditions[' + index + '][value]']" v-model="condition.value"/>
</date>
</div>
<div class="control-group date" v-if="matchedAttribute.type == 'datetime'">
<datetime>
<input class="control" :name="['conditions[' + index + '][value]']" v-model="condition.value"/>
</datetime>
</div>
<div class="control-group" v-if="matchedAttribute.type == 'boolean'">
<select :name="['conditions[' + index + '][value]']" class="control" v-model="condition.value">
<option value="1">{{ __('admin::app.promotions.cart-rules.yes') }}</option>
<option value="0">{{ __('admin::app.promotions.cart-rules.no') }}</option>
</select>
</div>
<div class="control-group" v-if="matchedAttribute.type == 'select' || matchedAttribute.type == 'radio'">
<select :name="['conditions[' + index + '][value]']" class="control" v-model="condition.value" v-if="matchedAttribute.key != 'cart|state'">
<option v-for='option in matchedAttribute.options' :value="option.id">
@{{ option.admin_name }}
</option>
</select>
<select :name="['conditions[' + index + '][value]']" class="control" v-model="condition.value" v-else>
<optgroup v-for='option in matchedAttribute.options' :label="option.admin_name">
<option v-for='state in option.states' :value="state.code">
@{{ state.admin_name }}
</option>
</optgroup>
</select>
</div>
<div class="control-group" v-if="matchedAttribute.type == 'multiselect' || matchedAttribute.type == 'checkbox'">
<select :name="['conditions[' + index + '][value][]']" class="control" v-model="condition.value" multiple>
<option v-for='option in matchedAttribute.options' :value="option.id">
@{{ option.admin_name }}
</option>
</select>
</div>
</div>
</div>
</td>
<td class="actions">
<i class="icon trash-icon" @click="removeCondition"></i>
</td>
</tr>
</script>
<script type="text/x-template" id="create-coupon-form-template">
<div class="">
<form method="POST" data-vv-scope="create-coupun-form" @submit.prevent="generateCopuns('create-coupun-form')">
<div class="control-group" :class="[errors.has('create-coupun-form.coupon_qty') ? 'has-error' : '']">
<label for="coupon_qty" class="required">{{ __('admin::app.promotions.cart-rules.coupon-qty') }}</label>
<input v-validate="'required|min_value:1'" class="control" id="coupon_qty" name="coupon_qty" v-model="coupon_format.coupon_qty" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.coupon-qty') }}&quot;"/>
<span class="control-error" v-if="errors.has('create-coupun-form.coupon_qty')">
@{{ errors.first('create-coupun-form.coupon_qty') }}
</span>
</div>
<div class="control-group" :class="[errors.has('create-coupun-form.code_length') ? 'has-error' : '']">
<label for="code_length" class="required">{{ __('admin::app.promotions.cart-rules.code-length') }}</label>
<input v-validate="'required|min_value:10'" class="control" id="code_length" name="code_length" v-model="coupon_format.code_length" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.code-length') }}&quot;"/>
<span class="control-error" v-if="errors.has('create-coupun-form.code_length')">
@{{ errors.first('create-coupun-form.code_length') }}
</span>
</div>
<div class="control-group" :class="[errors.has('create-coupun-form.code_format') ? 'has-error' : '']">
<label for="code_format" class="required">{{ __('admin::app.promotions.cart-rules.code-format') }}</label>
<select class="control" id="code_format" name="code_format" v-model="coupon_format.code_format" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.cart-rules.code-format') }}&quot;">
<option value="alphanumeric">{{ __('admin::app.promotions.cart-rules.alphanumeric') }}</option>
<option value="alphabetical">{{ __('admin::app.promotions.cart-rules.alphabetical') }}</option>
<option value="numeric">{{ __('admin::app.promotions.cart-rules.numeric') }}</option>
</select>
<span class="control-error" v-if="errors.has('create-coupun-form.code_format')">
@{{ errors.first('create-coupun-form.code_format') }}
</span>
</div>
<div class="control-group">
<label for="code_prefix">{{ __('admin::app.promotions.cart-rules.code-prefix') }}</label>
<input class="control" id="code_prefix" name="code_prefix" v-model="coupon_format.code_prefix"/>
</div>
<div class="control-group">
<label for="code_suffix">{{ __('admin::app.promotions.cart-rules.code-suffix') }}</label>
<input class="control" id="code_suffix" name="code_suffix" v-model="coupon_format.code_suffix"/>
</div>
<div class="button-group">
<button class="btn btn-xl btn-primary">{{ __('admin::app.promotions.cart-rules.generate') }}</button>
</div>
</form>
@inject('cartRuleCouponGrid','Webkul\Admin\DataGrids\CartRuleCouponDataGrid')
{!! $cartRuleCouponGrid->render() !!}
</div>
</script>
<script>
Vue.component('cart-rule', {
template: '#cart-rule-template',
inject: ['$validator'],
data: function() {
return {
coupon_type: {{ old('coupon_type') ?: $cartRule->coupon_type }},
use_auto_generation: {{ old('use_auto_generation') ?: $cartRule->use_auto_generation }},
condition_type: {{ old('condition_type') ?: $cartRule->condition_type }},
conditions: @json($cartRule->conditions ?: []),
action_type: "{{ old('action_type') ?: $cartRule->action_type }}"
}
},
methods: {
addCondition: function() {
this.conditions.push({
'attribute': '',
'operator': '==',
'value': '',
});
},
removeCondition: function(condition) {
let index = this.conditions.indexOf(condition)
this.conditions.splice(index, 1)
},
onSubmit: function(e) {
this.$root.onSubmit(e)
},
redirectBack: function(fallbackUrl) {
this.$root.redirectBack(fallbackUrl)
}
}
});
Vue.component('cart-rule-condition-item', {
template: '#cart-rule-condition-item-template',
props: ['index', 'condition'],
data: function() {
return {
condition_attributes: @json(app('\Webkul\CartRule\Repositories\CartRuleRepository')->getConditionAttributes()),
attribute_type_indexes: {
'cart': 0,
'cart_item': 1,
'product': 2
},
condition_operators: {
'price': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-less-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.less-than') }}'
}],
'decimal': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.cart-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.cart-rules.less-than') }}'
}],
'integer': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.cart-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.cart-rules.less-than') }}'
}],
'text': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}, {
'operator': '{}',
'label': '{{ __('admin::app.promotions.cart-rules.contain') }}'
}, {
'operator': '!{}',
'label': '{{ __('admin::app.promotions.cart-rules.does-not-contain') }}'
}],
'boolean': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}],
'date': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.cart-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.cart-rules.less-than') }}'
}],
'datetime': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.cart-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.cart-rules.less-than') }}'
}],
'select': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}],
'radio': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.cart-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.cart-rules.is-not-equal-to') }}'
}],
'multiselect': [{
'operator': '{}',
'label': '{{ __('admin::app.promotions.cart-rules.contains') }}'
}, {
'operator': '!{}',
'label': '{{ __('admin::app.promotions.cart-rules.does-not-contain') }}'
}],
'checkbox': [{
'operator': '{}',
'label': '{{ __('admin::app.promotions.cart-rules.contains') }}'
}, {
'operator': '!{}',
'label': '{{ __('admin::app.promotions.cart-rules.does-not-contain') }}'
}]
}
}
},
computed: {
matchedAttribute: function () {
if (this.condition.attribute == '')
return;
var this_this = this;
var attributeIndex = this.attribute_type_indexes[this.condition.attribute.split("|")[0]];
matchedAttribute = this.condition_attributes[attributeIndex]['children'].filter(function (attribute) {
return attribute.key == this_this.condition.attribute;
});
if (matchedAttribute[0]['type'] == 'multiselect' || matchedAttribute[0]['type'] == 'checkbox') {
this.condition.operator = '{}';
this.condition.value = this.condition.value == '' && this.condition.value != undefined ? [] : this.condition.value;
}
return matchedAttribute[0];
}
},
methods: {
removeCondition: function() {
this.$emit('onRemoveCondition', this.condition)
}
}
});
Vue.component('create-coupon-form', {
template: '#create-coupon-form-template',
inject: ['$validator'],
data: function() {
return {
coupon_format: {
coupon_qty: '',
code_length: 12,
code_format: 'alphanumeric',
code_prefix: '',
code_suffix: ''
}
}
},
methods: {
generateCopuns: function(formScope) {
var this_this = this;
this.$validator.validateAll(formScope).then(function (result) {
if (result) {
this_this.$http.post("{{ route('admin.cart-rules.generate-coupons', $cartRule->id) }}", this_this.coupon_format)
.then(function(response) {
window.flashMessages = [{
'type': 'alert-success',
'message': response.data.message
}];
this_this.$root.addFlashMessages()
})
.catch(function (error) {
window.flashMessages = [{
'type': 'alert-error',
'message': error.response.data.message
}];
this_this.$root.addFlashMessages()
})
}
});
}
}
});
</script>
@endpush

View File

@ -1,7 +1,7 @@
@extends('admin::layouts.content')
@section('page_title')
{{ __('admin::app.promotion.cart-rule') }}
{{ __('admin::app.promotions.cart-rules.title') }}
@stop
@section('content')
@ -9,12 +9,12 @@
<div class="content">
<div class="page-header">
<div class="page-title">
<h1>{{ __('admin::app.promotion.cart-rule') }}</h1>
<h1>{{ __('admin::app.promotions.cart-rules.title') }}</h1>
</div>
<div class="page-action">
<a href="{{ route('admin.cart-rule.create') }}" class="btn btn-lg btn-primary">
{{ __('admin::app.promotion.add-cart-rule') }}
<a href="{{ route('admin.cart-rules.create') }}" class="btn btn-lg btn-primary">
{{ __('admin::app.promotions.cart-rules.add-title') }}
</a>
</div>
</div>

View File

@ -1,415 +0,0 @@
@extends('admin::layouts.content')
@section('page_title')
{{ __('admin::app.promotion.add-catalog-rule') }}
@stop
@section('content')
<div class="content">
<catalog-rule></catalog-rule>
</div>
@push('scripts')
<script type="text/x-template" id="catalog-rule-form-template">
<div>
<form method="POST" action="{{ route('admin.catalog-rule.store') }}" @submit.prevent="onSubmit">
@csrf
<div class="page-header">
<div class="page-title">
<h1>
<i class="icon angle-left-icon back-link" onclick="history.length > 1 ? history.go(-1) : window.location = '{{ url('/admin/dashboard') }}';"></i>
{{ __('admin::app.promotion.add-catalog-rule') }}
</h1>
</div>
<div class="page-action">
<button type="submit" class="btn btn-lg btn-primary">
{{ __('admin::app.promotion.save-btn-title') }}
</button>
</div>
</div>
<div class="page-content">
<div class="form-container">
@csrf()
<accordian :active="true" title="{{ __('admin::app.promotion.information') }}">
<div slot="body">
<div class="control-group" :class="[errors.has('name') ? 'has-error' : '']">
<label for="name" class="required">{{ __('admin::app.promotion.general-info.name') }}</label>
<input type="text" class="control" name="name" v-model="name" v-validate="'required'" value="{{ old('name') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.name') }}&quot;">
<span class="control-error" v-if="errors.has('name')">@{{ errors.first('name') }}</span>
</div>
<div class="control-group" :class="[errors.has('description') ? 'has-error' : '']">
<label for="description" class="required">{{ __('admin::app.promotion.general-info.description') }}</label>
<textarea class="control" name="description" v-model="description" v-validate="'required'" value="{{ old('description') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.description') }}&quot;"></textarea>
<span class="control-error" v-if="errors.has('description')">@{{ errors.first('description') }}</span>
</div>
<div class="control-group" :class="[errors.has('customer_groups[]') ? 'has-error' : '']">
<label for="customer_groups" class="required">{{ __('admin::app.promotion.general-info.cust-groups') }}</label>
<select type="text" class="control" name="customer_groups[]" v-model="customer_groups" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.cust-groups') }}&quot;" multiple="multiple">
<option disabled="disabled">Select Customer Groups</option>
@foreach(app('Webkul\Customer\Repositories\CustomerGroupRepository')->all() as $channel)
<option value="{{ $channel->id }}">{{ $channel->name }}</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('customer_groups[]')">@{{ errors.first('customer_groups[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('channels[]') ? 'has-error' : '']">
<label for="channels" class="required">{{ __('admin::app.promotion.general-info.channels') }}</label>
<select type="text" class="control" name="channels[]" v-model="channels" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.channels') }}&quot;" multiple="multiple">
<option disabled="disabled">Select Channels</option>
@foreach(app('Webkul\Core\Repositories\ChannelRepository')->all() as $channel)
<option value="{{ $channel->id }}">{{ $channel->name }}</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('channels[]')">@{{ errors.first('status') }}</span>
</div>
<div class="control-group" :class="[errors.has('status') ? 'has-error' : '']">
<label for="status" class="required">{{ __('admin::app.promotion.general-info.status') }}</label>
<select type="text" class="control" name="status" v-model="status" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.status') }}&quot;">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Option']) }}</option>
<option value="1">{{ __('admin::app.promotion.yes') }}</option>
<option value="0">{{ __('admin::app.promotion.no') }}</option>
</select>
<span class="control-error" v-if="errors.has('status')">@{{ errors.first('status') }}</span>
</div>
<datetime :name="starts_from">
<div class="control-group" :class="[errors.has('starts_from') ? 'has-error' : '']">
<label for="starts_from">{{ __('admin::app.promotion.general-info.starts-from') }}</label>
<input type="text" class="control" v-model="starts_from" name="starts_from" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.starts-from') }}&quot;">
<span class="control-error" v-if="errors.has('starts_from')">@{{ errors.first('starts_from') }}</span>
</div>
</datetime>
<datetime :name="starts_from">
<div class="control-group" :class="[errors.has('ends_till') ? 'has-error' : '']">
<label for="ends_till">{{ __('admin::app.promotion.general-info.ends-till') }}</label>
<input type="text" class="control" v-model="ends_till" name="ends_till" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.ends-till') }}&quot;">
<span class="control-error" v-if="errors.has('ends_till')">@{{ errors.first('ends_till') }}</span>
</div>
</datetime>
</div>
</accordian>
<accordian :active="false" title="{{ __('admin::app.promotion.conditions') }}">
<div slot="body">
<input type="hidden" name="all_conditions" v-model="all_conditions">
<!-- Categories selection input block -->
<div class="control-group" :class="[errors.has('category_values') ? 'has-error' : '']">
<label class="mb-10" for="categories">{{ __('admin::app.promotion.select-category') }}</label>
<multiselect v-model="category_values" :close-on-select="false" :options="category_options" :searchable="false" :custom-label="categoryLabel" :show-labels="true" placeholder="Select Categories" track-by="slug" :multiple="true"></multiselect>
</div>
<label class="mb-10" for="attributes">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Attribute']) }}</label>
<br/>
<!-- Product attributes conditions block -->
<div class="control-container mt-20" v-for="(condition, index) in attribute_values" :key="index">
<select class="control" v-model="attribute_values[index].attribute" style="margin-right: 15px; width: 30%;" v-on:change="enableAttributeCondition($event, index)">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Option']) }}</option>
<option v-for="(attr_ip, index1) in attribute_input" :value="attr_ip.code" :key="index1">@{{ attr_ip.name }}</option>
</select>
<select v-show='attribute_values[index].type == "select" || attribute_values[index].type == "multiselect"' class="control" v-model="attribute_values[index].condition" style="margin-right: 15px;">
<option v-for="(condition, index) in conditions.select" :value="index" :key="index">@{{ condition }}</option>
</select>
<select v-show='attribute_values[index].type == "text" || attribute_values[index].type == "textarea" || attribute_values[index].type == "price"' class="control" v-model="attribute_values[index].condition" style="margin-right: 15px;">
<option v-for="(condition, index) in conditions.string" :value="index" :key="index">@{{ condition }}</option>
</select>
<div v-show='attribute_values[index].type == "select" || attribute_values[index].type == "multiselect"' style="display: flex;">
<select class="control" v-model="attribute_values[index].value" style="margin-right: 15px; height: 100px" :multiple="true">
<option :disabled="true">
{{ __('ui::form.select-attribute', ['attribute' => 'Values']) }}
</option>
<option v-for="(label, index2) in attribute_values[index].options" :value="index2" :key="index2">@{{ label.admin_name }}</option>
</select>
{{-- <multiselect v-model="attribute_values[index].value" :close-on-select="false" :options="attribute_values[index].options" :searchable="false" :track-by="admin_name" :custom-label="attributeListLabel" :multiple="true" ></multiselect> --}}
</div>
<div v-show='attribute_values[index].type == "text" || attribute_values[index].type == "textarea" || attribute_values[index].type == "price" || attribute_values[index].type == "textarea"' style="display: flex">
<input class="control" v-model="attribute_values[index].value" type="text" placeholder="{{ __('ui::form.enter-attribute', ['attribute' => 'Text']) }}">
</div>
<span class="icon trash-icon" v-on:click="removeAttr(index)"></span>
</div>
<span class="btn btn-primary btn-lg mt-20" v-on:click="addAttributeCondition">{{ __('admin::app.promotion.add-attr-condition') }}</span>
</div>
</accordian>
<accordian :active="false" title="{{ __('admin::app.promotion.actions') }}">
<div slot="body">
<div class="control-group" :class="[errors.has('action_type') ? 'has-error' : '']">
<label for="action_type" class="required">{{ __('admin::app.promotion.general-info.apply') }}</label>
<select class="control" name="action_type" v-model="action_type" v-validate="'required'" value="{{ old('action_type') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.apply') }}&quot;" v-on:change="detectApply">
<option v-for="(action, index) in actions" :value="index">@{{ action }}</option>
</select>
<span class="control-error" v-if="errors.has('action_type')">@{{ errors.first('action_type') }}</span>
</div>
<div class="control-group" :class="[errors.has('disc_amount') ? 'has-error' : '']">
<label for="disc_amount" class="required">{{ __('admin::app.promotion.general-info.disc_amt') }}</label>
<input type="number" step="0.5000" class="control" name="disc_amount" v-model="disc_amount" v-validate="'required|min_value:0.0001'" value="{{ old('disc_amount') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.disc_amt') }}&quot;">
<span class="control-error" v-if="errors.has('disc_amount')">@{{ errors.first('disc_amount') }}</span>
</div>
<div class="control-group" :class="[errors.has('end_other_rules') ? 'has-error' : '']">
<label for="end_other_rules" class="required">{{ __('admin::app.promotion.general-info.end-other-rules') }}</label>
<select type="text" class="control" name="end_other_rules" v-model="end_other_rules" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.end-other-rules') }}&quot;">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Option']) }}</option>
<option value="1">{{ __('admin::app.promotion.yes') }}</option>
<option value="0">{{ __('admin::app.promotion.no') }}</option>
</select>
<span class="control-error" v-if="errors.has('end_other_rules')">@{{ errors.first('end_other_rules') }}</span>
</div>
</div>
</accordian>
</div>
</div>
</form>
</div>
</script>
<script>
Vue.component('catalog-rule', {
template: '#catalog-rule-form-template',
inject: ['$validator'],
data () {
return {
name: null,
description: null,
conditions_list: [],
channels: [],
customer_groups: [],
ends_till: null,
starts_from: null,
per_customer: 0,
status: 1,
action_type: null,
apply: null,
apply_amt: false,
disc_amount: null,
end_other_rules: 0,
all_conditions: [],
all_attributes: {
'categories' : [],
'attributes' : []
},
criteria: 'cart',
actions: @json($catalog_rule[0]).actions,
category_options: @json($catalog_rule[1]),
category_values: [],
conditions: @json($catalog_rule[0]).conditions,
attribute_values: [],
attr_object: {
attribute: null,
condition: null,
value: [],
options: []
},
attribute_input: @json($catalog_rule[3])
}
},
mounted () {
},
methods: {
categoryLabel (option) {
return option.name + ' [ ' + option.slug + ' ]';
},
attributeListLabel(option) {
return option.label;
},
addCondition () {
if (this.criteria == 'attribute' || this.criteria == 'attribute_family' || this.criteria == 'category') {
this.condition_on = this.criteria;
} else {
alert('please try again');
return false;
}
if (this.condition_on == 'attribute') {
this.conditions_list.push(this.attr_object);
this.attr_object = {
criteria: this.condition_on,
attribute: null,
condition: null,
value: null,
type: null,
options: null
};
} else if (this.condition_on == 'category') {
this.conditions_list.push(this.cat_object);
this.cat_object = {
criteria: this.condition_on,
category: 'category',
condition: null,
value: []
};
} else if (this.condition_on == 'attribute_family') {
this.conditions_list.push(this.fam_object);
this.fam_object = {
criteria: this.condition_on,
family: 'attribute_family',
condition: null,
value: null
};
}
},
addAttributeCondition() {
this.attribute_values.push(this.attr_object);
this.attr_object = {
attribute: null,
condition: null,
value: [],
options: []
};
},
enableCondition(event, index) {
this.conditions_list[index].type = this.attrs_input[event.target.selectedIndex - 1].type;
var this_this = this;
if (this.attrs_input[event.target.selectedIndex - 1].type == 'select' || this.attrs_input[event.target.selectedIndex - 1].type == 'multiselect') {
this.conditions_list[index].options = this.attrs_options[this.attrs_input[event.target.selectedIndex - 1].code];
this.conditions_list[index].value = [];
}
},
enableAttributeCondition (event, index) {
selectedIndex = event.target.selectedIndex - 1;
for(i in this.attribute_input) {
if (i == selectedIndex) {
if (this.attribute_input[i].has_options == true) {
this.selectedIndex
this.attribute_values[index].options = this.attribute_input[i].options;
}
this.attribute_values[index].type = this.attribute_input[i].type;
}
}
},
detectApply() {
if (this.apply == 0 || this.apply == 2) {
this.apply_prct = true;
this.apply_amt = false;
} else if (this.apply == 1 || this.apply == 3) {
this.apply_prct = false;
this.apply_amt = true;
}
},
removeAttr(index) {
this.attribute_values.splice(index, 1);
},
removeCat(index) {
this.cats.splice(index, 1);
},
onSubmit: function (e) {
if (this.attribute_values.length > 0 || this.category_values.length > 0) {
for (i in this.attribute_values) {
delete this.attribute_values[i].options;
}
if (this.category_values.length > 0) {
this.all_attributes.categories = this.category_values;
}
if (this.attribute_values.length > 0) {
this.all_attributes.attributes = this.attribute_values;
}
}
this.all_conditions = JSON.stringify(this.all_attributes);
// this.all_conditions = JSON.stringify(this.conditions_list);
// if (this.conditions_list.length != 0) {
// this.conditions_list.push({'criteria': this.match_criteria});
// this.all_conditions = JSON.stringify(this.conditions_list);
// }
// return false;
this.$validator.validateAll().then(result => {
if (result) {
e.target.submit();
}
});
},
genericGroupCondition() {
this.generic_condition = false;
},
addFlashMessages() {
const flashes = this.$refs.flashes;
flashMessages.forEach(function(flash) {
flashes.addFlash(flash);
}, this);
}
}
});
</script>
@endpush
@stop

View File

@ -1,414 +0,0 @@
@extends('admin::layouts.content')
@section('page_title')
{{ __('admin::app.promotion.edit-catalog-rule') }}
@stop
@section('content')
<div class="content">
<catalog-rule></catalog-rule>
</div>
@push('scripts')
<script type="text/x-template" id="catalog-rule-form-template">
<div>
<form method="POST" action="{{ route('admin.catalog-rule.update', $catalog_rule[5]->id) }}" @submit.prevent="onSubmit">
@csrf
<div class="page-header">
<div class="page-title">
<h1>
<i class="icon angle-left-icon back-link" onclick="history.length > 1 ? history.go(-1) : window.location = '{{ url('/admin/dashboard') }}';"></i>
{{ __('admin::app.promotion.edit-catalog-rule') }}
</h1>
</div>
<div class="page-action">
<button type="submit" class="btn btn-lg btn-primary">
{{ __('admin::app.promotion.edit-btn-title') }}
</button>
</div>
</div>
<div class="page-content">
<div class="form-container">
@csrf()
<accordian :active="true" title="{{ __('admin::app.promotion.information') }}">
<div slot="body">
<div class="control-group" :class="[errors.has('name') ? 'has-error' : '']">
<label for="name" class="required">{{ __('admin::app.promotion.general-info.name') }}</label>
<input type="text" class="control" name="name" v-model="name" v-validate="'required'" value="{{ old('name') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.name') }}&quot;">
<span class="control-error" v-if="errors.has('name')">@{{ errors.first('name') }}</span>
</div>
<div class="control-group" :class="[errors.has('description') ? 'has-error' : '']">
<label for="description" class="required">{{ __('admin::app.promotion.general-info.description') }}</label>
<textarea class="control" name="description" v-model="description" v-validate="'required'" value="{{ old('description') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.description') }}&quot;"></textarea>
<span class="control-error" v-if="errors.has('description')">@{{ errors.first('description') }}</span>
</div>
<div class="control-group" :class="[errors.has('customer_groups[]') ? 'has-error' : '']">
<label for="customer_groups" class="required">{{ __('admin::app.promotion.general-info.cust-groups') }}</label>
<select type="text" class="control" name="customer_groups[]" v-model="customer_groups" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.cust-groups') }}&quot;" multiple="multiple">
<option disabled="disabled">Select Customer Groups</option>
@foreach(app('Webkul\Customer\Repositories\CustomerGroupRepository')->all() as $channel)
<option value="{{ $channel->id }}">{{ $channel->name }}</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('customer_groups[]')">@{{ errors.first('customer_groups[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('channels[]') ? 'has-error' : '']">
<label for="channels" class="required">{{ __('admin::app.promotion.general-info.channels') }}</label>
<select type="text" class="control" name="channels[]" v-model="channels" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.channels') }}&quot;" multiple="multiple">
<option disabled="disabled">Select Channels</option>
@foreach(app('Webkul\Core\Repositories\ChannelRepository')->all() as $channel)
<option value="{{ $channel->id }}">{{ $channel->name }}</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('channels[]')">@{{ errors.first('status') }}</span>
</div>
<div class="control-group" :class="[errors.has('status') ? 'has-error' : '']">
<label for="status" class="required">{{ __('admin::app.promotion.general-info.status') }}</label>
<select type="text" class="control" name="status" v-model="status" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.status') }}&quot;">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Option']) }}</option>
<option value="1">{{ __('admin::app.promotion.yes') }}</option>
<option value="0">{{ __('admin::app.promotion.no') }}</option>
</select>
<span class="control-error" v-if="errors.has('status')">@{{ errors.first('status') }}</span>
</div>
@php
$now = new \Carbon\Carbon();
@endphp
<date :name="starts_from">
<div class="control-group" :class="[errors.has('starts_from') ? 'has-error' : '']">
<label for="starts_from">{{ __('admin::app.promotion.general-info.starts-from') }}</label>
<input type="text" class="control" v-model="starts_from" name="starts_from" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.starts-from') }}&quot;">
<span class="control-error" v-if="errors.has('starts_from')">@{{ errors.first('starts_from') }}</span>
</div>
</date>
<date :name="starts_from">
<div class="control-group" :class="[errors.has('ends_till') ? 'has-error' : '']">
<label for="ends_till">{{ __('admin::app.promotion.general-info.ends-till') }}</label>
<input type="text" class="control" v-model="ends_till" name="ends_till" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.ends-till') }}&quot;">
<span class="control-error" v-if="errors.has('ends_till')">@{{ errors.first('ends_till') }}</span>
</div>
</date>
</div>
</accordian>
<accordian :active="false" title="{{ __('admin::app.promotion.conditions') }}">
<div slot="body">
<input type="hidden" name="all_conditions" v-model="all_conditions">
<!-- Categories selection input block -->
<div class="control-group" :class="[errors.has('category_values') ? 'has-error' : '']">
<label class="mb-10" for="categories">{{ __('admin::app.promotion.select-category') }}</label>
<multiselect v-model="category_values" :close-on-select="false" :options="category_options" :searchable="false" :custom-label="categoryLabel" :show-labels="true" placeholder="Select Categories" track-by="slug" :multiple="true"></multiselect>
</div>
<label class="mb-10" for="attributes">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Attribute']) }}</label>
<br/>
<!-- Product attributes conditions block -->
<div class="control-container mt-20" v-for="(condition, index) in attribute_values" :key="index">
<select class="control" v-model="attribute_values[index].attribute" style="margin-right: 15px; width: 30%;" v-on:change="enableAttributeCondition($event, index)">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Option']) }}</option>
<option v-for="(attr_ip, index1) in attribute_input" :value="attr_ip.code" :key="index1">@{{ attr_ip.name }}</option>
</select>
<select v-show='attribute_values[index].type == "select" || attribute_values[index].type == "multiselect"' class="control" v-model="attribute_values[index].condition" style="margin-right: 15px;">
<option v-for="(condition, index) in conditions.select" :value="index" :key="index">@{{ condition }}</option>
</select>
<select v-show='attribute_values[index].type == "text" || attribute_values[index].type == "textarea" || attribute_values[index].type == "price"' class="control" v-model="attribute_values[index].condition" style="margin-right: 15px;">
<option v-for="(condition, index) in conditions.string" :value="index" :key="index">@{{ condition }}</option>
</select>
<div v-show='attribute_values[index].type == "select" || attribute_values[index].type == "multiselect"' style="display: flex;">
<select class="control" v-model="attribute_values[index].value" style="margin-right: 15px; height: 100px" :multiple="true">
<option :disabled="true">
{{ __('ui::form.select-attribute', ['attribute' => 'Values']) }}
</option>
<option v-for="(label, index2) in attribute_values[index].options" :value="index2" :key="index2">@{{ label.admin_name }}</option>
</select>
{{-- <multiselect v-model="attribute_values[index].value" :close-on-select="false" :options="attribute_values[index].options" :searchable="false" :track-by="admin_name" :custom-label="attributeListLabel" :multiple="true" ></multiselect> --}}
</div>
<div v-show='attribute_values[index].type == "text" || attribute_values[index].type == "textarea" || attribute_values[index].type == "price" || attribute_values[index].type == "textarea"' style="display: flex">
<input class="control" v-model="attribute_values[index].value" type="text" placeholder="{{ __('ui::form.enter-attribute', ['attribute' => 'Text']) }}">
</div>
<span class="icon trash-icon" v-on:click="removeAttr(index)"></span>
</div>
<span class="btn btn-primary btn-lg mt-20" v-on:click="addAttributeCondition">{{ __('admin::app.promotion.add-attr-condition') }}</span>
</div>
</accordian>
<accordian :active="false" title="{{ __('admin::app.promotion.actions') }}">
<div slot="body">
<div class="control-group" :class="[errors.has('action_type') ? 'has-error' : '']">
<label for="action_type" class="required">{{ __('admin::app.promotion.general-info.apply') }}</label>
<select class="control" name="action_type" v-model="action_type" v-validate="'required'" value="{{ old('action_type') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.apply') }}&quot;" v-on:change="detectApply">
<option v-for="(action, index) in actions" :value="index">@{{ action }}</option>
</select>
<span class="control-error" v-if="errors.has('action_type')">@{{ errors.first('action_type') }}</span>
</div>
<div class="control-group" :class="[errors.has('disc_amount') ? 'has-error' : '']">
<label for="disc_amount" class="required">{{ __('admin::app.promotion.general-info.disc_amt') }}</label>
<input type="number" step="0.5000" class="control" name="disc_amount" v-model="disc_amount" v-validate="'required|min_value:0.0001'" value="{{ old('disc_amount') }}" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.disc_amt') }}&quot;">
<span class="control-error" v-if="errors.has('disc_amount')">@{{ errors.first('disc_amount') }}</span>
</div>
<div class="control-group" :class="[errors.has('end_other_rules') ? 'has-error' : '']">
<label for="end_other_rules" class="required">{{ __('admin::app.promotion.general-info.end-other-rules') }}</label>
<select type="text" class="control" name="end_other_rules" v-model="end_other_rules" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotion.general-info.end-other-rules') }}&quot;">
<option disabled="disabled">{{ __('admin::app.promotion.select-attribute', ['attribute' => 'Option']) }}</option>
<option value="1">{{ __('admin::app.promotion.yes') }}</option>
<option value="0">{{ __('admin::app.promotion.no') }}</option>
</select>
<span class="control-error" v-if="errors.has('end_other_rules')">@{{ errors.first('end_other_rules') }}</span>
</div>
</div>
</accordian>
</div>
</div>
</form>
</div>
</script>
<script>
Vue.component('catalog-rule', {
template: '#catalog-rule-form-template',
inject: ['$validator'],
data () {
return {
name: '{{ $catalog_rule[5]->name }}',
description: '{{ $catalog_rule[5]->description }}',
conditions_list: [],
channels: [],
customer_groups: [],
ends_till: '{{ $catalog_rule[5]->ends_till }}',
starts_from: '{{ $catalog_rule[5]->starts_from }}',
status: '{{ $catalog_rule[5]->status }}',
actions: @json($catalog_rule[3]).actions,
action_type: '{{ $catalog_rule[5]->action_code }}',
disc_amount: null,
end_other_rules: '{{ $catalog_rule[5]->end_other_rules }}',
all_conditions: [],
all_attributes: {
'categories' : [],
'attributes' : []
},
criteria: 'cart',
category_options: @json($catalog_rule[1]),
category_values: [],
conditions: @json($catalog_rule[3]).conditions,
attribute_values: [],
attr_object: {
attribute: null,
condition: null,
value: [],
options: []
},
attribute_input: @json($catalog_rule[0])
}
},
mounted () {
catalog_rule = @json($catalog_rule[5]);
channels = @json($catalog_rule[5]->channels);
this.channels = [];
for (i in channels) {
this.channels.push(channels[i].channel_id);
}
customer_groups = @json($catalog_rule[5]->customer_groups);
for (i in customer_groups) {
this.customer_groups.push(customer_groups[i].customer_group_id);
}
data = @json($catalog_rule[5]->conditions);
if (JSON.parse(JSON.parse(data))) {
this.category_values = JSON.parse(JSON.parse(data)).categories;
this.attribute_values = JSON.parse(JSON.parse(data)).attributes;
// creating options and has option param on the frontend
for (i in this.attribute_values) {
for (j in this.attribute_input) {
if (this.attribute_input[j].code == this.attribute_values[i].attribute) {
if (this.attribute_input[j].has_options == true) {
this.attribute_values[i].has_options = true;
this.attribute_values[i].options = this.attribute_input[j].options;
} else {
this.attribute_values[i].has_options = false;
this.attribute_values[i].options = null;
}
}
}
}
}
this.action_type = '{{ $catalog_rule[5]->action_code }}';
this.disc_amount = catalog_rule.discount_amount;
this.end_other_rules = '{{ $catalog_rule[5]->end_other_rules }}';
},
methods: {
created() {
VeeValidate.Validator.extend('is_time', {
getMessage: field => `The format must be HH:MM:SS`,
validate: (value) => new Promise(resolve => {
let regex = new RegExp("([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])");
resolve({
valid: value && regex.test(value)
});
})
});
},
categoryLabel (option) {
return option.name + ' [ ' + option.slug + ' ]';
},
attributeListLabel(option) {
return option.label;
},
addAttributeCondition() {
this.attribute_values.push(this.attr_object);
this.attr_object = {
attribute: null,
condition: null,
value: [],
options: []
};
},
enableAttributeCondition (event, index) {
selectedIndex = event.target.selectedIndex - 1;
for(i in this.attribute_input) {
if (i == selectedIndex) {
if (this.attribute_input[i].has_options == true) {
this.attribute_values[index].options = this.attribute_input[i].options;
}
this.attribute_values[index].type = this.attribute_input[i].type;
}
}
},
detectApply() {
if (this.apply == 0 || this.apply == 2) {
this.apply_prct = true;
this.apply_amt = false;
} else if (this.apply == 1 || this.apply == 3) {
this.apply_prct = false;
this.apply_amt = true;
}
},
removeAttr(index) {
this.attribute_values.splice(index, 1);
},
removeCat(index) {
this.cats.splice(index, 1);
},
onSubmit: function (e) {
if (this.attribute_values.length > 0 || this.category_values.length > 0) {
for (i in this.attribute_values) {
delete this.attribute_values[i].options;
}
if (this.category_values.length > 0) {
this.all_attributes.categories = this.category_values;
}
this.all_attributes.attributes = this.attribute_values;
}
this.all_conditions = JSON.stringify(this.all_attributes);
// this.all_conditions = JSON.stringify(this.conditions_list);
// if (this.conditions_list.length != 0) {
// this.conditions_list.push({'criteria': this.match_criteria});
// this.all_conditions = JSON.stringify(this.conditions_list);
// }
// return false;
this.$validator.validateAll().then(result => {
if (result) {
e.target.submit();
}
});
},
genericGroupCondition() {
this.generic_condition = false;
},
addFlashMessages() {
const flashes = this.$refs.flashes;
flashMessages.forEach(function(flash) {
flashes.addFlash(flash);
}, this);
}
}
});
</script>
@endpush
@stop

View File

@ -1,35 +0,0 @@
@extends('admin::layouts.content')
@section('page_title')
{{ __('admin::app.promotion.catalog-rule') }}
@stop
@section('content')
<div class="content">
<div class="page-header">
<div class="page-title">
<h1>{{ __('admin::app.promotion.catalog-rule') }}</h1>
</div>
<div class="page-action">
<a href="{{ route('admin.catalog-rule.create') }}" class="btn btn-lg btn-primary">
{{ __('admin::app.promotion.add-catalog-rule') }}
</a>
<a href="{{ route('admin.catalog-rule.apply') }}" class="btn btn-lg btn-primary">
{{ __('admin::app.promotion.apply') }}
</a>
<a href="{{ route('admin.catalog-rule.declut') }}" class="btn btn-lg btn-primary">
{{ __('admin::app.promotion.declut') }}
</a>
</div>
</div>
<div class="page-content">
@inject('catalogRuleGrid','Webkul\Admin\DataGrids\CatalogRuleDataGrid')
{!! $catalogRuleGrid->render() !!}
</div>
</div>
@endsection

View File

@ -0,0 +1,528 @@
@extends('admin::layouts.content')
@section('page_title')
{{ __('admin::app.promotions.catalog-rules.add-title') }}
@stop
@section('content')
<div class="content">
<catalog-rule></catalog-rule>
</div>
@stop
@push('scripts')
@parent
<script type="text/x-template" id="catalog-rule-template">
<div>
<form method="POST" action="{{ route('admin.catalog-rules.store') }}" @submit.prevent="onSubmit">
<div class="page-header">
<div class="page-title">
<h1>
<i class="icon angle-left-icon back-link" @click="redirectBack('{{ url('/admin/dashboard') }}')"></i>
{{ __('admin::app.promotions.catalog-rules.add-title') }}
</h1>
</div>
<div class="page-action">
<button type="submit" class="btn btn-lg btn-primary">
{{ __('admin::app.promotions.catalog-rules.save-btn-title') }}
</button>
</div>
</div>
<div class="page-content">
<div class="form-container">
@csrf()
{!! view_render_event('bagisto.admin.promotions.catalog-rules.create.before') !!}
<accordian :title="'{{ __('admin::app.promotions.catalog-rules.rule-information') }}'" :active="true">
<div slot="body">
<div class="control-group" :class="[errors.has('name') ? 'has-error' : '']">
<label for="name" class="required">{{ __('admin::app.promotions.catalog-rules.name') }}</label>
<input v-validate="'required'" class="control" id="name" name="name" data-vv-as="&quot;{{ __('admin::app.promotions.catalog-rules.name') }}&quot;" value="{{ old('name') }}"/>
<span class="control-error" v-if="errors.has('name')">@{{ errors.first('name') }}</span>
</div>
<div class="control-group">
<label for="description">{{ __('admin::app.promotions.catalog-rules.description') }}</label>
<textarea class="control" id="description" name="description">{{ old('description') }}</textarea>
</div>
<div class="control-group">
<label for="status">{{ __('admin::app.promotions.catalog-rules.status') }}</label>
<span class="checkbox">
<input type="checkbox" id="status" name="status" value="1">
<label class="checkbox-view" for="status"></label>
{{ __('admin::app.promotions.catalog-rules.is-active') }}
</span>
</div>
<div class="control-group" :class="[errors.has('channels[]') ? 'has-error' : '']">
<label for="channels" class="required">{{ __('admin::app.promotions.catalog-rules.channels') }}</label>
<select class="control" id="channels" name="channels[]" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.catalog-rules.channels') }}&quot;" multiple="multiple">
@foreach(core()->getAllChannels() as $channel)
<option value="{{ $channel->id }}" {{ old('channels') && in_array($channel->id, old('channels')) ? 'selected' : '' }}>
{{ $channel->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('channels[]')">@{{ errors.first('channels[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('customer_groups[]') ? 'has-error' : '']">
<label for="customer_groups" class="required">{{ __('admin::app.promotions.catalog-rules.customer-groups') }}</label>
<select class="control" id="customer_groups" name="customer_groups[]" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.catalog-rules.customer-groups') }}&quot;" multiple="multiple">
@foreach(app('Webkul\Customer\Repositories\CustomerGroupRepository')->all() as $customerGroup)
<option value="{{ $customerGroup->id }}" {{ old('customer_groups') && in_array($customerGroup->id, old('customer_groups')) ? 'selected' : '' }}>
{{ $customerGroup->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('customer_groups[]')">@{{ errors.first('customer_groups[]') }}</span>
</div>
<div class="control-group date">
<label for="starts_from">{{ __('admin::app.promotions.catalog-rules.from') }}</label>
<date>
<input type="text" name="starts_from" class="control" value="{{ old('starts_from') }}"/>
</date>
</div>
<div class="control-group date">
<label for="ends_till">{{ __('admin::app.promotions.catalog-rules.to') }}</label>
<date>
<input type="text" name="ends_till" class="control" value="{{ old('ends_till') }}"/>
</date>
</div>
<div class="control-group">
<label for="sort_order">{{ __('admin::app.promotions.catalog-rules.priority') }}</label>
<input type="text" class="control" id="sort_order" name="sort_order" value="{{ old('sort_order') ?? 0 }}"/>
</div>
</div>
</accordian>
<accordian :title="'{{ __('admin::app.promotions.catalog-rules.conditions') }}'" :active="false">
<div slot="body">
<div class="control-group">
<label for="condition_type">{{ __('admin::app.promotions.catalog-rules.condition-type') }}</label>
<select class="control" id="condition_type" name="condition_type" v-model="condition_type">
<option value="1">{{ __('admin::app.promotions.catalog-rules.all-conditions-true') }}</option>
<option value="2">{{ __('admin::app.promotions.catalog-rules.any-condition-true') }}</option>
</select>
</div>
<div class="table catalog-rule-conditions" style="margin-top: 20px; overflow-x: unset;">
<table>
<tbody>
<catalog-rule-condition-item
v-for='(condition, index) in conditions'
:condition="condition"
:key="index"
:index="index"
@onRemoveCondition="removeCondition($event)">
</catalog-rule-condition-item>
</tbody>
</table>
</div>
<button type="button" class="btn btn-lg btn-primary" style="margin-top: 20px;" @click="addCondition">
{{ __('admin::app.promotions.catalog-rules.add-condition') }}
</button>
</div>
</accordian>
<accordian :title="'{{ __('admin::app.promotions.catalog-rules.actions') }}'" :active="false">
<div slot="body">
<div class="control-group" :class="[errors.has('action_type') ? 'has-error' : '']">
<label for="action_type" class="required">{{ __('admin::app.promotions.catalog-rules.action-type') }}</label>
<select class="control" id="action_type" name="action_type" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.catalog-rules.action-type') }}&quot;">
<option value="by_percent" {{ old('action_type') == 'by_percent' ? 'selected' : '' }}>
{{ __('admin::app.promotions.catalog-rules.percentage-product-price') }}
</option>
<option value="by_fixed" {{ old('action_type') == 'by_fixed' ? 'selected' : '' }}>
{{ __('admin::app.promotions.catalog-rules.fixed-amount') }}
</option>
</select>
<span class="control-error" v-if="errors.has('action_type')">@{{ errors.first('action_type') }}</span>
</div>
<div class="control-group" :class="[errors.has('discount_amount') ? 'has-error' : '']">
<label for="discount_amount" class="required">{{ __('admin::app.promotions.catalog-rules.discount-amount') }}</label>
<input v-validate="'required'" class="control" id="discount_amount" name="discount_amount" data-vv-as="&quot;{{ __('admin::app.promotions.catalog-rules.discount-amount') }}&quot;" value="{{ old('discount_amount') ?? 0 }}"/>
<span class="control-error" v-if="errors.has('discount_amount')">@{{ errors.first('discount_amount') }}</span>
</div>
<div class="control-group">
<label for="end_other_rules">{{ __('admin::app.promotions.catalog-rules.end-other-rules') }}</label>
<select class="control" id="end_other_rules" name="end_other_rules">
<option value="0" {{ ! old('end_other_rules') ? 'selected' : '' }}>
{{ __('admin::app.promotions.catalog-rules.no') }}
</option>
<option value="1" {{ old('end_other_rules') ? 'selected' : '' }}>
{{ __('admin::app.promotions.catalog-rules.yes') }}
</option>
</select>
</div>
</div>
</accordian>
{!! view_render_event('bagisto.admin.promotions.catalog-rules.create.after') !!}
</div>
</div>
</form>
</div>
</script>
<script type="text/x-template" id="catalog-rule-condition-item-template">
<tr>
<td class="attribute">
<div class="control-group">
<select :name="['conditions[' + index + '][attribute]']" class="control" v-model="condition.attribute">
<option value="">{{ __('admin::app.promotions.catalog-rules.choose-condition-to-add') }}</option>
<optgroup v-for='(conditionAttribute, index) in condition_attributes' :label="conditionAttribute.label">
<option v-for='(childAttribute, index) in conditionAttribute.children' :value="childAttribute.key">
@{{ childAttribute.label }}
</option>
</optgroup>
</select>
</div>
</td>
<td class="operator">
<div class="control-group" v-if="matchedAttribute">
<select :name="['conditions[' + index + '][operator]']" class="control" v-model="condition.operator">
<option v-for='operator in condition_operators[matchedAttribute.type]' :value="operator.operator">
@{{ operator.label }}
</option>
</select>
</div>
</td>
<td class="value">
<div v-if="matchedAttribute">
<input type="hidden" :name="['conditions[' + index + '][attribute_type]']" v-model="matchedAttribute.type">
<div v-if="matchedAttribute.key == 'product|category_ids'">
<tree-view value-field="id" id-field="id" :name-field="'conditions[' + index + '][value]'" input-type="checkbox" :items='matchedAttribute.options' :behavior="'no'"></tree-view>
</div>
<div v-else>
<div class="control-group" v-if="matchedAttribute.type == 'text' || matchedAttribute.type == 'price' || matchedAttribute.type == 'decimal' || matchedAttribute.type == 'integer'">
<input class="control" :name="['conditions[' + index + '][value]']" v-model="condition.value"/>
</div>
<div class="control-group date" v-if="matchedAttribute.type == 'date'">
<date>
<input class="control" :name="['conditions[' + index + '][value]']" v-model="condition.value"/>
</date>
</div>
<div class="control-group date" v-if="matchedAttribute.type == 'datetime'">
<datetime>
<input class="control" :name="['conditions[' + index + '][value]']" v-model="condition.value"/>
</datetime>
</div>
<div class="control-group" v-if="matchedAttribute.type == 'boolean'">
<select :name="['conditions[' + index + '][value]']" class="control" v-model="condition.value">
<option value="1">{{ __('admin::app.promotions.catalog-rules.yes') }}</option>
<option value="0">{{ __('admin::app.promotions.catalog-rules.no') }}</option>
</select>
</div>
<div class="control-group" v-if="matchedAttribute.type == 'select' || matchedAttribute.type == 'radio'">
<select :name="['conditions[' + index + '][value]']" class="control" v-model="condition.value" v-if="matchedAttribute.key != 'catalog|state'">
<option v-for='option in matchedAttribute.options' :value="option.id">
@{{ option.admin_name }}
</option>
</select>
<select :name="['conditions[' + index + '][value]']" class="control" v-model="condition.value" v-else>
<optgroup v-for='option in matchedAttribute.options' :label="option.admin_name">
<option v-for='state in option.states' :value="state.code">
@{{ state.admin_name }}
</option>
</optgroup>
</select>
</div>
<div class="control-group" v-if="matchedAttribute.type == 'multiselect' || matchedAttribute.type == 'checkbox'">
<select :name="['conditions[' + index + '][value][]']" class="control" v-model="condition.value" multiple>
<option v-for='option in matchedAttribute.options' :value="option.id">
@{{ option.admin_name }}
</option>
</select>
</div>
</div>
</div>
</td>
<td class="actions">
<i class="icon trash-icon" @click="removeCondition"></i>
</td>
</tr>
</script>
<script>
Vue.component('catalog-rule', {
template: '#catalog-rule-template',
inject: ['$validator'],
data: function() {
return {
condition_type: 1,
conditions: []
}
},
methods: {
addCondition: function() {
this.conditions.push({
'attribute': '',
'operator': '==',
'value': '',
});
},
removeCondition: function(condition) {
let index = this.conditions.indexOf(condition)
this.conditions.splice(index, 1)
},
onSubmit: function(e) {
this.$root.onSubmit(e)
},
onSubmit: function(e) {
this.$root.onSubmit(e)
},
redirectBack: function(fallbackUrl) {
this.$root.redirectBack(fallbackUrl)
}
}
});
Vue.component('catalog-rule-condition-item', {
template: '#catalog-rule-condition-item-template',
props: ['index', 'condition'],
data: function() {
return {
condition_attributes: @json(app('\Webkul\CatalogRule\Repositories\CatalogRuleRepository')->getConditionAttributes()),
attribute_type_indexes: {
'product': 0
},
condition_operators: {
'price': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-less-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.catalog-rules.greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.catalog-rules.less-than') }}'
}],
'decimal': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.catalog-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.catalog-rules.less-than') }}'
}],
'integer': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.catalog-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.catalog-rules.less-than') }}'
}],
'text': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}, {
'operator': '{}',
'label': '{{ __('admin::app.promotions.catalog-rules.contain') }}'
}, {
'operator': '!{}',
'label': '{{ __('admin::app.promotions.catalog-rules.does-not-contain') }}'
}],
'boolean': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}],
'date': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.catalog-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.catalog-rules.less-than') }}'
}],
'datetime': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.catalog-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.catalog-rules.less-than') }}'
}],
'select': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}],
'radio': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}],
'multiselect': [{
'operator': '{}',
'label': '{{ __('admin::app.promotions.catalog-rules.contains') }}'
}, {
'operator': '!{}',
'label': '{{ __('admin::app.promotions.catalog-rules.does-not-contain') }}'
}],
'checkbox': [{
'operator': '{}',
'label': '{{ __('admin::app.promotions.catalog-rules.contains') }}'
}, {
'operator': '!{}',
'label': '{{ __('admin::app.promotions.catalog-rules.does-not-contain') }}'
}]
}
}
},
computed: {
matchedAttribute: function () {
if (this.condition.attribute == '')
return;
var this_this = this;
var attributeIndex = this.attribute_type_indexes[this.condition.attribute.split("|")[0]];
matchedAttribute = this.condition_attributes[attributeIndex]['children'].filter(function (attribute) {
return attribute.key == this_this.condition.attribute;
});
if (matchedAttribute[0]['type'] == 'multiselect' || matchedAttribute[0]['type'] == 'checkbox') {
this.condition.operator = '{}';
this.condition.value = [];
}
return matchedAttribute[0];
}
},
methods: {
removeCondition: function() {
this.$emit('onRemoveCondition', this.condition)
}
}
});
</script>
@endpush

View File

@ -0,0 +1,533 @@
@extends('admin::layouts.content')
@section('page_title')
{{ __('admin::app.promotions.catalog-rules.edit-title') }}
@stop
@section('content')
<div class="content">
<catalog-rule></catalog-rule>
</div>
@stop
@push('scripts')
@parent
<script type="text/x-template" id="catalog-rule-template">
<div>
<form method="POST" action="{{ route('admin.catalog-rules.update', $catalogRule->id) }}" @submit.prevent="onSubmit">
<div class="page-header">
<div class="page-title">
<h1>
<i class="icon angle-left-icon back-link" @click="redirectBack('{{ url('/admin/dashboard') }}')"></i>
{{ __('admin::app.promotions.catalog-rules.edit-title') }}
</h1>
</div>
<div class="page-action">
<button type="submit" class="btn btn-lg btn-primary">
{{ __('admin::app.promotions.catalog-rules.save-btn-title') }}
</button>
</div>
</div>
<div class="page-content">
<div class="form-container">
@csrf()
{!! view_render_event('bagisto.admin.promotions.catalog-rules.create.before') !!}
<accordian :title="'{{ __('admin::app.promotions.catalog-rules.rule-information') }}'" :active="true">
<div slot="body">
<div class="control-group" :class="[errors.has('name') ? 'has-error' : '']">
<label for="name" class="required">{{ __('admin::app.promotions.catalog-rules.name') }}</label>
<input v-validate="'required'" class="control" id="name" name="name" data-vv-as="&quot;{{ __('admin::app.promotions.catalog-rules.name') }}&quot;" value="{{ old('name') ?: $catalogRule->name }}"/>
<span class="control-error" v-if="errors.has('name')">@{{ errors.first('name') }}</span>
</div>
<div class="control-group">
<label for="description">{{ __('admin::app.promotions.catalog-rules.description') }}</label>
<textarea class="control" id="description" name="description">{{ old('description') ?: $catalogRule->description }}</textarea>
</div>
<div class="control-group">
<label for="status">{{ __('admin::app.promotions.catalog-rules.status') }}</label>
<span class="checkbox">
<input type="checkbox" id="status" name="status" value="{{ $catalogRule->status }}" {{ $catalogRule->status ? 'checked' : '' }}>
<label class="checkbox-view" for="status"></label>
{{ __('admin::app.promotions.catalog-rules.is-active') }}
</span>
</div>
<div class="control-group" :class="[errors.has('channels[]') ? 'has-error' : '']">
<label for="channels" class="required">{{ __('admin::app.promotions.catalog-rules.channels') }}</label>
<?php $selectedOptionIds = old('channels') ?: $catalogRule->channels->pluck('id')->toArray() ?>
<select class="control" id="channels" name="channels[]" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.catalog-rules.channels') }}&quot;" multiple="multiple">
@foreach(core()->getAllChannels() as $channel)
<option value="{{ $channel->id }}" {{ in_array($channel->id, $selectedOptionIds) ? 'selected' : '' }}>
{{ $channel->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('channels[]')">@{{ errors.first('channels[]') }}</span>
</div>
<div class="control-group" :class="[errors.has('customer_groups[]') ? 'has-error' : '']">
<label for="customer_groups" class="required">{{ __('admin::app.promotions.catalog-rules.customer-groups') }}</label>
<?php $selectedOptionIds = old('customer_groups') ?: $catalogRule->customer_groups->pluck('id')->toArray() ?>
<select class="control" id="customer_groups" name="customer_groups[]" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.catalog-rules.customer-groups') }}&quot;" multiple="multiple">
@foreach(app('Webkul\Customer\Repositories\CustomerGroupRepository')->all() as $customerGroup)
<option value="{{ $customerGroup->id }}" {{ in_array($customerGroup->id, $selectedOptionIds) ? 'selected' : '' }}>
{{ $customerGroup->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('customer_groups[]')">@{{ errors.first('customer_groups[]') }}</span>
</div>
<div class="control-group date">
<label for="starts_from">{{ __('admin::app.promotions.catalog-rules.from') }}</label>
<date>
<input type="text" name="starts_from" class="control" value="{{ old('starts_from') ?: $catalogRule->starts_from }}"/>
</date>
</div>
<div class="control-group date">
<label for="ends_till">{{ __('admin::app.promotions.catalog-rules.to') }}</label>
<date>
<input type="text" name="ends_till" class="control" value="{{ old('ends_till') ?: $catalogRule->ends_till }}"/>
</date>
</div>
<div class="control-group">
<label for="sort_order">{{ __('admin::app.promotions.catalog-rules.priority') }}</label>
<input type="text" class="control" id="sort_order" name="sort_order" value="{{ $catalogRule->sort_order }}" {{ $catalogRule->status ? 'checked' : '' }}/>
</div>
</div>
</accordian>
<accordian :title="'{{ __('admin::app.promotions.catalog-rules.conditions') }}'" :active="false">
<div slot="body">
<div class="control-group">
<label for="condition_type">{{ __('admin::app.promotions.catalog-rules.condition-type') }}</label>
<select class="control" id="condition_type" name="condition_type" v-model="condition_type">
<option value="1">{{ __('admin::app.promotions.catalog-rules.all-conditions-true') }}</option>
<option value="2">{{ __('admin::app.promotions.catalog-rules.any-condition-true') }}</option>
</select>
</div>
<div class="table catalog-rule-conditions" style="margin-top: 20px; overflow-x: unset;">
<table>
<tbody>
<catalog-rule-condition-item
v-for='(condition, index) in conditions'
:condition="condition"
:key="index"
:index="index"
@onRemoveCondition="removeCondition($event)">
</catalog-rule-condition-item>
</tbody>
</table>
</div>
<button type="button" class="btn btn-lg btn-primary" style="margin-top: 20px;" @click="addCondition">
{{ __('admin::app.promotions.catalog-rules.add-condition') }}
</button>
</div>
</accordian>
<accordian :title="'{{ __('admin::app.promotions.catalog-rules.actions') }}'" :active="false">
<div slot="body">
<div class="control-group" :class="[errors.has('action_type') ? 'has-error' : '']">
<label for="action_type" class="required">{{ __('admin::app.promotions.catalog-rules.action-type') }}</label>
<?php $selectedOption = old('action_type') ?: $catalogRule->action_type ?>
<select class="control" id="action_type" name="action_type" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.promotions.catalog-rules.action-type') }}&quot;">
<option value="by_percent" {{ $selectedOption == 'by_percent' ? 'selected' : '' }}>
{{ __('admin::app.promotions.catalog-rules.percentage-product-price') }}
</option>
<option value="by_fixed" {{ $selectedOption == 'by_fixed' ? 'selected' : '' }}>
{{ __('admin::app.promotions.catalog-rules.fixed-amount') }}
</option>
</select>
<span class="control-error" v-if="errors.has('action_type')">@{{ errors.first('action_type') }}</span>
</div>
<div class="control-group" :class="[errors.has('discount_amount') ? 'has-error' : '']">
<label for="discount_amount" class="required">{{ __('admin::app.promotions.catalog-rules.discount-amount') }}</label>
<input v-validate="'required'" class="control" id="discount_amount" name="discount_amount" data-vv-as="&quot;{{ __('admin::app.promotions.catalog-rules.discount-amount') }}&quot;" value="{{ old('discount_amount') ?: $catalogRule->discount_amount }}"/>
<span class="control-error" v-if="errors.has('discount_amount')">@{{ errors.first('discount_amount') }}</span>
</div>
<div class="control-group">
<label for="end_other_rules">{{ __('admin::app.promotions.catalog-rules.end-other-rules') }}</label>
<?php $selectedOption = old('end_other_rules') ?: $catalogRule->end_other_rules ?>
<select class="control" id="end_other_rules" name="end_other_rules">
<option value="0" {{ ! $selectedOption ? 'selected' : '' }}>
{{ __('admin::app.promotions.catalog-rules.no') }}
</option>
<option value="1" {{ $selectedOption ? 'selected' : '' }}>
{{ __('admin::app.promotions.catalog-rules.yes') }}
</option>
</select>
</div>
</div>
</accordian>
{!! view_render_event('bagisto.admin.promotions.catalog-rules.create.after') !!}
</div>
</div>
</form>
</div>
</script>
<script type="text/x-template" id="catalog-rule-condition-item-template">
<tr>
<td class="attribute">
<div class="control-group">
<select :name="['conditions[' + index + '][attribute]']" class="control" v-model="condition.attribute">
<option value="">{{ __('admin::app.promotions.catalog-rules.choose-condition-to-add') }}</option>
<optgroup v-for='(conditionAttribute, index) in condition_attributes' :label="conditionAttribute.label">
<option v-for='(childAttribute, index) in conditionAttribute.children' :value="childAttribute.key">
@{{ childAttribute.label }}
</option>
</optgroup>
</select>
</div>
</td>
<td class="operator">
<div class="control-group" v-if="matchedAttribute">
<select :name="['conditions[' + index + '][operator]']" class="control" v-model="condition.operator">
<option v-for='operator in condition_operators[matchedAttribute.type]' :value="operator.operator">
@{{ operator.label }}
</option>
</select>
</div>
</td>
<td class="value">
<div v-if="matchedAttribute">
<input type="hidden" :name="['conditions[' + index + '][attribute_type]']" v-model="matchedAttribute.type">
<div v-if="matchedAttribute.key == 'product|category_ids'">
<tree-view value-field="id" id-field="id" :name-field="'conditions[' + index + '][value]'" input-type="checkbox" :items='matchedAttribute.options' :value='condition.value' :behavior="'no'"></tree-view>
</div>
<div v-else>
<div class="control-group" v-if="matchedAttribute.type == 'text' || matchedAttribute.type == 'price' || matchedAttribute.type == 'decimal' || matchedAttribute.type == 'integer'">
<input class="control" :name="['conditions[' + index + '][value]']" v-model="condition.value"/>
</div>
<div class="control-group date" v-if="matchedAttribute.type == 'date'">
<date>
<input class="control" :name="['conditions[' + index + '][value]']" v-model="condition.value"/>
</date>
</div>
<div class="control-group date" v-if="matchedAttribute.type == 'datetime'">
<datetime>
<input class="control" :name="['conditions[' + index + '][value]']" v-model="condition.value"/>
</datetime>
</div>
<div class="control-group" v-if="matchedAttribute.type == 'boolean'">
<select :name="['conditions[' + index + '][value]']" class="control" v-model="condition.value">
<option value="1">{{ __('admin::app.promotions.catalog-rules.yes') }}</option>
<option value="0">{{ __('admin::app.promotions.catalog-rules.no') }}</option>
</select>
</div>
<div class="control-group" v-if="matchedAttribute.type == 'select' || matchedAttribute.type == 'radio'">
<select :name="['conditions[' + index + '][value]']" class="control" v-model="condition.value" v-if="matchedAttribute.key != 'catalog|state'">
<option v-for='option in matchedAttribute.options' :value="option.id">
@{{ option.admin_name }}
</option>
</select>
<select :name="['conditions[' + index + '][value]']" class="control" v-model="condition.value" v-else>
<optgroup v-for='option in matchedAttribute.options' :label="option.admin_name">
<option v-for='state in option.states' :value="state.code">
@{{ state.admin_name }}
</option>
</optgroup>
</select>
</div>
<div class="control-group" v-if="matchedAttribute.type == 'multiselect' || matchedAttribute.type == 'checkbox'">
<select :name="['conditions[' + index + '][value][]']" class="control" v-model="condition.value" multiple>
<option v-for='option in matchedAttribute.options' :value="option.id">
@{{ option.admin_name }}
</option>
</select>
</div>
</div>
</div>
</td>
<td class="actions">
<i class="icon trash-icon" @click="removeCondition"></i>
</td>
</tr>
</script>
<script>
Vue.component('catalog-rule', {
template: '#catalog-rule-template',
inject: ['$validator'],
data: function() {
return {
condition_type: {{ old('condition_type') ?: $catalogRule->condition_type }},
conditions: @json($catalogRule->conditions ?: [])
}
},
methods: {
addCondition: function() {
this.conditions.push({
'attribute': '',
'operator': '==',
'value': '',
});
},
removeCondition: function(condition) {
let index = this.conditions.indexOf(condition)
this.conditions.splice(index, 1)
},
onSubmit: function(e) {
this.$root.onSubmit(e)
},
redirectBack: function(fallbackUrl) {
this.$root.redirectBack(fallbackUrl)
}
}
});
Vue.component('catalog-rule-condition-item', {
template: '#catalog-rule-condition-item-template',
props: ['index', 'condition'],
data: function() {
return {
condition_attributes: @json(app('\Webkul\CatalogRule\Repositories\CatalogRuleRepository')->getConditionAttributes()),
attribute_type_indexes: {
'product': 0
},
condition_operators: {
'price': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-less-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.catalog-rules.greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.catalog-rules.less-than') }}'
}],
'decimal': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.catalog-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.catalog-rules.less-than') }}'
}],
'integer': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.catalog-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.catalog-rules.less-than') }}'
}],
'text': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}, {
'operator': '{}',
'label': '{{ __('admin::app.promotions.catalog-rules.contain') }}'
}, {
'operator': '!{}',
'label': '{{ __('admin::app.promotions.catalog-rules.does-not-contain') }}'
}],
'boolean': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}],
'date': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.catalog-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.catalog-rules.less-than') }}'
}],
'datetime': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}, {
'operator': '>=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-greater-than') }}'
}, {
'operator': '<=',
'label': '{{ __('admin::app.promotions.catalog-rules.equals-or-less-than') }}'
}, {
'operator': '>',
'label': '{{ __('admin::app.promotions.catalog-rules.greater-than') }}'
}, {
'operator': '<',
'label': '{{ __('admin::app.promotions.catalog-rules.less-than') }}'
}],
'select': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}],
'radio': [{
'operator': '==',
'label': '{{ __('admin::app.promotions.catalog-rules.is-equal-to') }}'
}, {
'operator': '!=',
'label': '{{ __('admin::app.promotions.catalog-rules.is-not-equal-to') }}'
}],
'multiselect': [{
'operator': '{}',
'label': '{{ __('admin::app.promotions.catalog-rules.contains') }}'
}, {
'operator': '!{}',
'label': '{{ __('admin::app.promotions.catalog-rules.does-not-contain') }}'
}],
'checkbox': [{
'operator': '{}',
'label': '{{ __('admin::app.promotions.catalog-rules.contains') }}'
}, {
'operator': '!{}',
'label': '{{ __('admin::app.promotions.catalog-rules.does-not-contain') }}'
}]
}
}
},
computed: {
matchedAttribute: function () {
if (this.condition.attribute == '')
return;
var this_this = this;
var attributeIndex = this.attribute_type_indexes[this.condition.attribute.split("|")[0]];
matchedAttribute = this.condition_attributes[attributeIndex]['children'].filter(function (attribute) {
return attribute.key == this_this.condition.attribute;
});
if (matchedAttribute[0]['type'] == 'multiselect' || matchedAttribute[0]['type'] == 'checkbox') {
this.condition.operator = '{}';
this.condition.value = this.condition.value == '' && this.condition.value != undefined ? [] : this.condition.value;
}
return matchedAttribute[0];
}
},
methods: {
removeCondition: function() {
this.$emit('onRemoveCondition', this.condition)
}
}
});
</script>
@endpush

View File

@ -0,0 +1,27 @@
@extends('admin::layouts.content')
@section('page_title')
{{ __('admin::app.promotions.catalog-rules.title') }}
@stop
@section('content')
<div class="content">
<div class="page-header">
<div class="page-title">
<h1>{{ __('admin::app.promotions.catalog-rules.title') }}</h1>
</div>
<div class="page-action">
<a href="{{ route('admin.catalog-rules.create') }}" class="btn btn-lg btn-primary">
{{ __('admin::app.promotions.catalog-rules.add-title') }}
</a>
</div>
</div>
<div class="page-content">
@inject('catalogRuleGrid','Webkul\Admin\DataGrids\CatalogRuleDataGrid')
{!! $catalogRuleGrid->render() !!}
</div>
</div>
@endsection

View File

@ -332,7 +332,13 @@
@if ($order->base_discount_amount > 0)
<tr>
<td>{{ __('admin::app.sales.orders.discount') }}</td>
<td>
{{ __('admin::app.sales.orders.discount') }}
@if ($order->coupon_code)
({{ $order->coupon_code }})
@endif
</td>
<td>-</td>
<td>{{ core()->formatBasePrice($order->base_discount_amount) }}</td>
</tr>

View File

@ -195,14 +195,14 @@
</span>
</div>
@if ($shipment->inventory_source)
@if ($shipment->inventory_source || $shipment->inventory_source_name)
<div class="row">
<span class="title">
{{ __('admin::app.sales.shipments.inventory-source') }}
</span>
<span class="value">
{{ $shipment->inventory_source->name }}
{{ $shipment->inventory_source ? $shipment->inventory_source->name : $shipment->inventory_source_name }}
</span>
</div>
@endif

View File

@ -7,7 +7,7 @@
@section('content')
<div class="content">
<form method="POST" action="{{ route('admin.currencies.store') }}" @submit.prevent="onSubmit">
<form method="POST" action="{{ route('admin.currencies.store') }}" @submit.prevent="onSubmit" enctype="multipart/form-data">
<div class="page-header">
<div class="page-title">
<h1>

View File

@ -7,7 +7,7 @@
@section('content')
<div class="content">
<form method="POST" action="{{ route('admin.currencies.update', $currency->id) }}" @submit.prevent="onSubmit">
<form method="POST" action="{{ route('admin.currencies.update', $currency->id) }}" @submit.prevent="onSubmit" enctype="multipart/form-data">
<div class="page-header">
<div class="page-title">
<h1>

View File

@ -28,7 +28,7 @@
<div class="form-container">
@csrf()
{!! view_render_event('bagisto.admin.settings.locale.edit.before') !!}
{!! view_render_event('bagisto.admin.settings.locale.edit.before', ['locale' => $locale]) !!}
<input name="_method" type="hidden" value="PUT">
@ -60,7 +60,7 @@
</div>
</accordian>
{!! view_render_event('bagisto.admin.settings.locale.edit.after') !!}
{!! view_render_event('bagisto.admin.settings.locale.edit.after', ['locale' => $locale]) !!}
</div>
</div>
</form>

View File

@ -45,7 +45,7 @@
<span class="control-error" v-if="errors.has('identifier')">@{{ errors.first('identifier') }}</span>
</div>
@include ('admin::customers.country-state', ['countryCode' => old('country'), 'stateCode' => old('state')])
<country-state></country-state>
<div class="control-group">
<span class="checkbox">
@ -83,6 +83,50 @@
</div>
</script>
<script type="text/x-template" id="country-state-template">
<div>
<div class="control-group" :class="[errors.has('country') ? 'has-error' : '']">
<label for="country" class="required">
{{ __('admin::app.customers.customers.country') }}
</label>
<select type="text" v-validate="'required'" class="control" id="country" name="country" v-model="country" data-vv-as="&quot;{{ __('admin::app.customers.customers.country') }}&quot;">
<option value=""></option>
@foreach (core()->countries() as $country)
<option value="{{ $country->code }}">{{ $country->name }}</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('country')">
@{{ errors.first('country') }}
</span>
</div>
<div class="control-group" :class="[errors.has('state') ? 'has-error' : '']">
<label for="state">
{{ __('admin::app.customers.customers.state') }}
</label>
<select class="control" id="state" name="state" v-model="state">
<option value="" :selected="! haveStates()">*</option>
<option v-for='(state, index) in countryStates[country]' :value="state.code">
@{{ state.default_name }}
</option>
</select>
<span class="control-error" v-if="errors.has('state')">
@{{ errors.first('state') }}
</span>
</div>
</div>
</script>
<script>
Vue.component('tax-rate-form', {
@ -96,5 +140,31 @@
}
},
});
Vue.component('country-state', {
template: '#country-state-template',
inject: ['$validator'],
data: function () {
return {
country: "{{ old('country') }}",
state: "{{ old('state') }}",
countryStates: @json(core()->groupedStatesByCountries())
}
},
methods: {
haveStates: function () {
if (this.countryStates[this.country] && this.countryStates[this.country].length)
return true;
return false;
},
}
});
</script>
@endpush

View File

@ -36,7 +36,7 @@
<span class="control-error" v-if="errors.has('identifier')">@{{ errors.first('identifier') }}</span>
</div>
@include ('admin::customers.country-state', ['countryCode' => old('country') ?? $taxRate->country, 'stateCode' => old('state') ?? $taxRate->state])
<country-state></country-state>
@if ($taxRate->is_zip)
<input type="hidden" id="is_zip" name="is_zip" value="{{ $taxRate->is_zip }}">
@ -70,4 +70,79 @@
</div>
</form>
</div>
@stop
@stop
@push('scripts')
<script type="text/x-template" id="country-state-template">
<div>
<div class="control-group" :class="[errors.has('country') ? 'has-error' : '']">
<label for="country" class="required">
{{ __('admin::app.customers.customers.country') }}
</label>
<select type="text" v-validate="'required'" class="control" id="country" name="country" v-model="country" data-vv-as="&quot;{{ __('admin::app.customers.customers.country') }}&quot;">
<option value=""></option>
@foreach (core()->countries() as $country)
<option value="{{ $country->code }}">{{ $country->name }}</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('country')">
@{{ errors.first('country') }}
</span>
</div>
<div class="control-group" :class="[errors.has('state') ? 'has-error' : '']">
<label for="state">
{{ __('admin::app.customers.customers.state') }}
</label>
<select class="control" id="state" name="state" v-model="state">
<option value="" :selected="! haveStates()">*</option>
<option v-for='(state, index) in countryStates[country]' :value="state.code">
@{{ state.default_name }}
</option>
</select>
<span class="control-error" v-if="errors.has('state')">
@{{ errors.first('state') }}
</span>
</div>
</div>
</script>
<script>
Vue.component('country-state', {
template: '#country-state-template',
inject: ['$validator'],
data: function () {
return {
country: "{{ old('country') ?? $taxRate->country }}",
state: "{{ old('state') ?? $taxRate->state }}",
countryStates: @json(core()->groupedStatesByCountries())
}
},
methods: {
haveStates: function () {
if (this.countryStates[this.country] && this.countryStates[this.country].length)
return true;
return false;
},
}
});
</script>
@endpush

View File

@ -16,12 +16,15 @@ mix.setPublicPath(publicPath).mergeManifest();
mix.disableNotifications();
mix.js(__dirname + "/src/Resources/assets/js/app.js", "js/admin.js")
.copyDirectory( __dirname + '/src/Resources/assets/images', publicPath + '/images')
.sass(__dirname + "/src/Resources/assets/sass/app.scss", "css/admin.css")
.options({
processCssUrls: false
});
if (!mix.inProduction()) {
mix.sourceMaps();
}
if (mix.inProduction()) {
mix.version();
}

View File

@ -2,6 +2,6 @@
namespace Webkul\CMS\Contracts;
interface CMS
interface CmsPage
{
}

View File

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

View File

@ -0,0 +1,41 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCmsPageTranslationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('cms_page_translations', function (Blueprint $table) {
$table->increments('id');
$table->string('page_title');
$table->string('url_key');
$table->text('html_content')->nullable();
$table->text('meta_title')->nullable();
$table->text('meta_description')->nullable();
$table->text('meta_keywords')->nullable();
$table->string('locale');
$table->integer('cms_page_id')->unsigned();
$table->unique(['cms_page_id', 'url_key', 'locale']);
$table->foreign('cms_page_id')->references('id')->on('cms_pages')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('cms_page_translations');
}
}

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RemoveColumnsFromCmsPagesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('cms_pages', function (Blueprint $table) {
$table->dropForeign('cms_pages_locale_id_foreign');
$table->dropForeign('cms_pages_channel_id_foreign');
$table->dropColumn(['url_key', 'html_content', 'page_title', 'meta_title', 'meta_description', 'meta_keywords', 'content', 'locale_id', 'channel_id']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('cms_pages', function (Blueprint $table) {
//
});
}
}

View File

@ -0,0 +1,35 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCmsPageChannelsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('cms_page_channels', function (Blueprint $table) {
$table->integer('cms_page_id')->unsigned();
$table->integer('channel_id')->unsigned();
$table->unique(['cms_page_id', 'channel_id']);
$table->foreign('cms_page_id')->references('id')->on('cms_pages')->onDelete('cascade');
$table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('cms_page_channels');
}
}

View File

@ -4,6 +4,7 @@ namespace Webkul\CMS\Database\Seeders;
use Illuminate\Database\Seeder;
use DB;
use Carbon\Carbon;
class CMSPagesTableSeeder extends Seeder
{
@ -13,101 +14,99 @@ class CMSPagesTableSeeder extends Seeder
DB::table('cms_pages')->insert([
[
'id' => '1',
'id' => 1,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
], [
'id' => 2,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
], [
'id' => 3,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
], [
'id' => 4,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
], [
'id' => 5,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
], [
'id' => 6,
'created_at' => Carbon::now(),
'updated_at' => Carbon::now()
]
]);
DB::table('cms_page_translations')->insert([
[
'locale' => 'en',
'cms_page_id' => 1,
'url_key' => 'about-us',
'html_content' => '<div class="static-container one-column">
'html_content' => '<div class="static-container">
<div class="mb-5">About us page content</div>
</div>',
'page_title' => 'About Us',
'meta_title' => 'about us',
'meta_description' => '',
'meta_keywords' => 'aboutus',
'content' => '{"html": "<div class=\"static-container one-column\">\r\n<div class=\"mb-5\">About us page content</div>\r\n</div>",
"meta_title": "about us",
"page_title": "About Us",
"meta_keywords": "aboutus ", "meta_description": ""}',
'channel_id' => 1,
'locale_id' => 1
'meta_keywords' => 'aboutus'
], [
'id' => '2',
'locale' => 'en',
'cms_page_id' => 2,
'url_key' => 'return-policy',
'html_content' => '<div class="static-container one-column">
'html_content' => '<div class="static-container">
<div class="mb-5">Return policy page content</div>
</div>',
'page_title' => 'Return Policy',
'meta_title' => 'return policy',
'meta_description' => '',
'meta_keywords' => 'return, policy',
'content' => '{"html": "<div class=\"static-container one-column\">\r\n<div class=\"mb-5\">Return policy page content</div>\r\n</div>",
"meta_title": "return policy",
"page_title": "Return Policy",
"meta_keywords": "return, policy ", "meta_description": ""}',
'channel_id' => 1,
'locale_id' => 1
'meta_keywords' => 'return, policy'
], [
'id' => '3',
'locale' => 'en',
'cms_page_id' => 3,
'url_key' => 'refund-policy',
'html_content' => '<div class="static-container one-column">
'html_content' => '<div class="static-container">
<div class="mb-5">Refund policy page content</div>
</div>',
'page_title' => 'Refund Policy',
'meta_title' => 'Refund policy',
'meta_description' => '',
'meta_keywords' => 'refund, policy',
'content' => '{"html": "<div class=\"static-container one-column\">\r\n<div class=\"mb-5\">Refund policy page content</div>\r\n</div>",
"meta_title": "Refund policy",
"page_title": "Refund Policy",
"meta_keywords": "refund,policy ", "meta_description": ""}',
'channel_id' => 1,
'locale_id' => 1
'meta_keywords' => 'refund, policy'
], [
'id' => '4',
'locale' => 'en',
'cms_page_id' => 4,
'url_key' => 'terms-conditions',
'html_content' => '<div class="static-container one-column">
'html_content' => '<div class="static-container">
<div class="mb-5">Terms & conditions page content</div>
</div>',
'page_title' => 'Terms & Conditions',
'meta_title' => 'Terms & Conditions',
'meta_description' => '',
'meta_keywords' => 'term, conditions',
'content' => '{"html": "<div class=\"static-container one-column\">\r\n<div class=\"mb-5\">Terms & conditions page content</div>\r\n</div>",
"meta_title": "Terms & Conditions",
"page_title": "Terms & Conditions",
"meta_keywords": "terms, conditions ", "meta_description": ""}',
'channel_id' => 1,
'locale_id' => 1
'meta_keywords' => 'term, conditions'
], [
'id' => '5',
'locale' => 'en',
'cms_page_id' => 5,
'url_key' => 'terms-of-use',
'html_content' => '<div class="static-container one-column">
'html_content' => '<div class="static-container">
<div class="mb-5">Terms of use page content</div>
</div>',
'page_title' => 'Terms of use',
'meta_title' => 'Terms of use',
'meta_description' => '',
'meta_keywords' => 'term, use',
'content' => '{"html": "<div class=\"static-container one-column\">\r\n<div class=\"mb-5\">Terms of use page content</div>\r\n</div>",
"meta_title": "Terms of use",
"page_title": "Terms of use",
"meta_keywords": "terms, use ", "meta_description": ""}',
'channel_id' => 1,
'locale_id' => 1
'meta_keywords' => 'term, use'
], [
'id' => '6',
'locale' => 'en',
'cms_page_id' => 6,
'url_key' => 'contact-us',
'html_content' => '<div class="static-container one-column">
'html_content' => '<div class="static-container">
<div class="mb-5">Contact us page content</div>
</div>',
'page_title' => 'Contact Us',
'meta_title' => 'Contact Us',
'meta_description' => '',
'meta_keywords' => 'contact, us',
'content' => '{"html": "<div class=\"static-container one-column\">\r\n<div class=\"mb-5\">Contact us page content</div>\r\n</div>",
"meta_title": "Contact Us",
"page_title": "Contact Us",
"meta_keywords": "contact, us ", "meta_description": ""}',
'channel_id' => 1,
'locale_id' => 1
'meta_keywords' => 'contact, us'
]
]);
}

View File

@ -3,67 +3,49 @@
namespace Webkul\CMS\Http\Controllers\Admin;
use Webkul\CMS\Http\Controllers\Controller;
use Webkul\CMS\Repositories\CMSRepository as CMS;
use Webkul\Core\Repositories\ChannelRepository as Channel;
use Webkul\Core\Repositories\LocaleRepository as Locale;
use Webkul\CMS\Repositories\CmsRepository;
/**
* CMS controller
*
* @author Prashant Singh <prashant.singh852@webkul.com> @prashant-webkul
* @author Jitendra Singh <jitendra@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class PageController extends Controller
{
/**
* To hold the request variables from route file
*
* @var array
*/
protected $_config;
/**
* To hold the channel reposotry instance
*/
protected $channel;
/**
* To hold the locale reposotry instance
*/
protected $locale;
/**
* To hold the CMSRepository instance
*
* @var Object
*/
protected $cms;
protected $cmsRepository;
public function __construct(Channel $channel, Locale $locale, CMS $cms)
/**
* Create a new controller instance.
*
* @param \Webkul\CMS\Repositories\CmsRepository $cmsRepository
* @return void
*/
public function __construct(CmsRepository $cmsRepository)
{
/**
* Pass the class instance through admin middleware
*/
// $this->middleware('auth:admin');
$this->middleware('admin');
/**
* Channel repository instance
*/
$this->channel = $channel;
/**
* Locale repository instance
*/
$this->locale = $locale;
/**
* CMS repository instance
*/
$this->cms = $cms;
$this->cmsRepository = $cmsRepository;
$this->_config = request('_config');
}
/**
* Loads the index page showing the static pages resources
*
* @return \Illuminate\View\View
*/
public function index()
{
@ -73,7 +55,7 @@ use Webkul\Core\Repositories\LocaleRepository as Locale;
/**
* To create a new CMS page
*
* @return view
* @return \Illuminate\View\View
*/
public function create()
{
@ -83,74 +65,22 @@ use Webkul\Core\Repositories\LocaleRepository as Locale;
/**
* To store a new CMS page in storage
*
* @return view
* @return \Illuminate\Http\Response
*/
public function store()
{
$data = request()->all();
// part one of the validation in case partials pages were generated or generating partial pages
$this->validate(request(), [
'url_key' => ['required', 'unique:cms_page_translations,url_key', new \Webkul\Core\Contracts\Validations\Slug],
'page_title' => 'required',
'channels' => 'required',
'locales' => 'required',
'url_key' => 'required'
'html_content' => 'required'
]);
$page = $this->cmsRepository->create(request()->all());
$channels = $data['channels'];
$locales = $data['locales'];
$this->validate(request(), [
'html_content' => 'required|string',
'page_title' => 'required|string',
'meta_title' => 'required|string',
'meta_description' => 'string',
'meta_keywords' => 'required|string'
]);
$data['content']['html'] = $data['html_content'];
$data['content']['page_title'] = $data['page_title'];
$data['content']['meta_keywords'] = $data['meta_keywords'];
$data['content']['meta_title'] = $data['meta_title'];
$data['content']['meta_description'] = $data['meta_description'];
$data['content'] = json_encode($data['content']);
$totalCount = 0;
$actualCount = 0;
foreach ($channels as $channel) {
foreach ($locales as $locale) {
$pageFound = $this->cms->findOneWhere([
'channel_id' => $channel,
'locale_id' => $locale,
'url_key' => $data['url_key']
]);
$totalCount++;
$data['channel_id'] = $channel;
$data['locale_id'] = $locale;
if (! $pageFound) {
$result = $this->cms->create($data);
if ($result) {
$actualCount++;
}
}
unset($pageFound);
}
}
if (($actualCount != 0 && $totalCount != 0) && ($actualCount == $totalCount)) {
session()->flash('success', trans('admin::app.cms.pages.create-success'));
} else if (($actualCount != 0 && $totalCount != 0) && ($actualCount != $totalCount)) {
session()->flash('warning', trans('admin::app.cms.pages.create-partial'));
} else {
session()->flash('error', trans('admin::app.cms.pages.create-failure'));
}
session()->flash('success', trans('admin::app.response.create-success', ['name' => 'page']));
return redirect()->route($this->_config['redirect']);
}
@ -158,105 +88,53 @@ use Webkul\Core\Repositories\LocaleRepository as Locale;
/**
* To edit a previously created CMS page
*
* @return view
* @param integer $id
* @return \Illuminate\View\View
*/
public function edit($id)
{
$page = $this->cms->findOrFail($id);
$page = $this->cmsRepository->findOrFail($id);
if (request()->has('channel') && request()->has('locale')) {
$channel = $this->channel->findOneWhere([
'code' => request()->input('channel')
]);
$locale = $this->locale->findOneWhere([
'code' => request()->input('locale')
]);
$page = $this->cms->findOneWhere([
'channel_id' => $channel->id,
'locale_id' => $locale->id,
'url_key' => $page->url_key
]);
if (! $page) {
$page = $this->cms->create([
'url_key' => str_random(8),
'channel' => $channel->code,
'locale' => $locale->code
]);
return redirect()->route('admin.cms.edit', $page->id);
}
} else {
$page = $this->cms->findOrFail($id);
}
return view($this->_config['view'])->with('page', $page);
return view($this->_config['view'], compact('page'));
}
/**
* To update the previously created CMS page in storage
*
* @param Integer $id
*
* @return View
* @param integer $id
* @return \Illuminate\Http\Response
*/
public function update($id)
{
$page = $this->cms->findOrFail($id);
$data = request()->all();
$locale = request()->get('locale') ?: app()->getLocale();
$this->validate(request(), [
'page_title' => 'required|string',
'html_content' => 'required|string',
'meta_title' => 'required|string',
'meta_description' => 'string',
'meta_keywords' => 'required|string'
$locale . '.url_key' => ['required', new \Webkul\Core\Contracts\Validations\Slug, function ($attribute, $value, $fail) use ($id) {
if (! $this->cmsRepository->isUrlKeyUnique($id, $value))
$fail(trans('admin::app.response.already-taken', ['name' => 'Page']));
}],
$locale . '.page_title' => 'required',
$locale . '.html_content' => 'required',
'channels' => 'required'
]);
$data['content']['html'] = $data['html_content'];
$data['content']['page_title'] = $data['page_title'];
$data['content']['meta_keywords'] = $data['meta_keywords'];
$data['content']['meta_title'] = $data['meta_title'];
$data['content']['meta_description'] = $data['meta_description'];
$data['content'] = json_encode($data['content']);
$this->cmsRepository->update(request()->all(), $id);
$result = $this->cms->update($data, $id);
session()->flash('success', trans('admin::app.response.update-success', ['name' => 'Page']));
if ($result) {
session()->flash('success', trans('admin::app.cms.pages.update-success'));
} else {
session()->flash('success', trans('admin::app.cms.pages.update-failure'));
}
return redirect()->route($this->_config['redirect']);
}
/**
* To preview the content of the currently creating page or previously creating page
*
* @param Integer $id
*
* @return mixed
*/
public function preview($id)
{
$page = $this->cms->findOrFail($id);
return view('shop::cms.page')->with('page', $page);
}
/**
* To delete the previously create CMS page
*
* @param Integer $id
* @param integer $id
*
* @return Response JSON
* @return \Illuminate\Http\Response
*/
public function delete($id)
{
$page = $this->cms->findOrFail($id);
$page = $this->cmsRepository->findOrFail($id);
if ($page->delete()) {
session()->flash('success', trans('admin::app.cms.pages.delete-success'));
@ -272,7 +150,7 @@ use Webkul\Core\Repositories\LocaleRepository as Locale;
/**
* To mass delete the CMS resource from storage
*
* @return Response redirect
* @return \Illuminate\Http\Response
*/
public function massDelete()
{
@ -281,13 +159,10 @@ use Webkul\Core\Repositories\LocaleRepository as Locale;
if ($data['indexes']) {
$pageIDs = explode(',', $data['indexes']);
$actualCount = count($pageIDs);
$count = 0;
foreach ($pageIDs as $pageId) {
$page = $this->cms->find($pageId);
$page = $this->cmsRepository->find($pageId);
if ($page) {
$page->delete();
@ -296,7 +171,7 @@ use Webkul\Core\Repositories\LocaleRepository as Locale;
}
}
if ($actualCount == $count) {
if (count($pageIDs) == $count) {
session()->flash('success', trans('admin::app.datagrid.mass-ops.delete-success', [
'resource' => 'CMS Pages'
]));

View File

@ -3,83 +3,44 @@
namespace Webkul\CMS\Http\Controllers\Shop;
use Webkul\CMS\Http\Controllers\Controller;
use Webkul\CMS\Repositories\CMSRepository as CMS;
use Webkul\Core\Repositories\ChannelRepository as Channel;
use Webkul\Core\Repositories\LocaleRepository as Locale;
use Webkul\CMS\Repositories\CmsRepository;
/**
* PagePresenter controller
*
* @author Prashant Singh <prashant.singh852@webkul.com> @prashant-webkul
* @author Jitendra Singh <jitendra@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class PagePresenterController extends Controller
class PagePresenterController extends Controller
{
/**
* To hold the request variables from route file
* CmsRepository object
*
* @var Object
*/
protected $_config;
protected $cmsRepository;
/**
* To hold the channel reposotry instance
* Create a new controller instance.
*
* @param \Webkul\CMS\Repositories\CmsRepository $cmsRepository
* @return void
*/
protected $channel;
/**
* To hold the locale reposotry instance
*/
protected $locale;
/**
* To hold the CMSRepository instance
*/
protected $cms;
public function __construct(Channel $channel, Locale $locale, CMS $cms)
public function __construct(CmsRepository $cmsRepository)
{
/**
* Channel repository instance
*/
$this->channel = $channel;
/**
* Locale repository instance
*/
$this->locale = $locale;
/**
* CMS repository instance
*/
$this->cms = $cms;
$this->_config = request('_config');
$this->cmsRepository = $cmsRepository;
}
/**
* To extract the page content and load it in the respective view file\
* To extract the page content and load it in the respective view file
*
* @return view
* @param string $urlKey
* @return \Illuminate\View\View
*/
public function presenter($slug)
public function presenter($urlKey)
{
$currentChannel = core()->getCurrentChannel();
$currentLocale = app()->getLocale();
$currentLocale = $this->locale->findOneWhere([
'code' => $currentLocale
]);
$page = $this->cms->findOneWhere([
'url_key' => $slug,
'locale_id' => $currentLocale->id,
'channel_id' => $currentChannel->id
]);
if ($page) {
return view('shop::cms.page')->with('page', $page);
} else {
abort(404);
}
$page = $this->cmsRepository->findByUrlKeyOrFail($urlKey);
return view('shop::cms.page')->with('page', $page);
}
}

View File

@ -1,13 +0,0 @@
<?php
namespace Webkul\CMS\Models;
use Illuminate\Database\Eloquent\Model;
use Webkul\CMS\Contracts\CMS as CMSContract;
class CMS extends Model implements CMSContract
{
protected $table = 'cms_pages';
protected $fillable = ['content', 'meta_description', 'meta_title', 'page_title', 'meta_keywords', 'html_content', 'url_key', 'layout', 'channel_id', 'locale_id'];
}

View File

@ -0,0 +1,24 @@
<?php
namespace Webkul\CMS\Models;
use Webkul\Core\Eloquent\TranslatableModel;
use Webkul\CMS\Contracts\CmsPage as CmsPageContract;
use Webkul\Core\Models\ChannelProxy;
class CmsPage extends TranslatableModel implements CmsPageContract
{
protected $fillable = ['layout'];
public $translatedAttributes = ['content', 'meta_description', 'meta_title', 'page_title', 'meta_keywords', 'html_content', 'url_key'];
protected $with = ['translations'];
/**
* Get the channels.
*/
public function channels()
{
return $this->belongsToMany(ChannelProxy::modelClass(), 'cms_page_channels');
}
}

View File

@ -4,7 +4,7 @@ namespace Webkul\CMS\Models;
use Konekt\Concord\Proxies\ModelProxy;
class CMSProxy extends ModelProxy
class CmsPageProxy extends ModelProxy
{
}

View File

@ -0,0 +1,13 @@
<?php
namespace Webkul\CMS\Models;
use Illuminate\Database\Eloquent\Model;
use Webkul\CMS\Contracts\CmsPageTranslation as CmsPageTranslationContract;
class CmsPageTranslation extends Model implements CmsPageTranslationContract
{
public $timestamps = false;
protected $fillable = ['page_title', 'url_key', 'html_content', 'meta_title', 'meta_description', 'meta_keywords', 'locale', 'cms_page_id'];
}

View File

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

View File

@ -3,15 +3,12 @@
namespace Webkul\CMS\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Routing\Router;
use Webkul\CMS\Providers\ModuleServiceProvider;
class CMSServiceProvider extends ServiceProvider
{
public function boot(Router $router)
public function boot()
{
$this->loadTranslationsFrom(__DIR__ . '/../Resources/lang', 'cms');
$this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations');
}
}

View File

@ -7,6 +7,7 @@ use Konekt\Concord\BaseModuleServiceProvider;
class ModuleServiceProvider extends BaseModuleServiceProvider
{
protected $models = [
\Webkul\CMS\Models\CMS::class
\Webkul\CMS\Models\CmsPage::class,
\Webkul\CMS\Models\CmsPageTranslation::class
];
}

View File

@ -1,57 +0,0 @@
<?php
namespace Webkul\CMS\Repositories;
use Webkul\Core\Eloquent\Repository;
use Illuminate\Container\Container as App;
use Webkul\Core\Repositories\ChannelRepository as Channel;
use Webkul\Core\Repositories\LocaleRepository as Locale;
/**
* CMS Reposotory
*
* @author Prashant Singh <prashant.singh852@webkul.com> @prashant-webkul
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class CMSRepository extends Repository
{
/**
* To hold the channel reposotry instance
*/
protected $channel;
/**
* To hold the locale reposotry instance
*/
protected $locale;
public function __construct(Channel $channel, Locale $locale, App $app)
{
$this->channel = $channel;
$this->locale = $locale;
parent::__construct($app);
}
/**
* Specify Model class name
*
* @return mixed
*/
function model()
{
return 'Webkul\CMS\Contracts\CMS';
}
public function create(array $data)
{
$result = $this->model->create($data);
if ($result) {
return $result;
} else {
return $result;
}
}
}

View File

@ -0,0 +1,110 @@
<?php
namespace Webkul\CMS\Repositories;
use Illuminate\Support\Facades\Event;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Webkul\Core\Eloquent\Repository;
use Webkul\CMS\Models\CmsPageTranslation;
/**
* CMS Reposotory
*
* @author Jitendra Singh <jitendra@webkul.com>
* @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com)
*/
class CmsRepository extends Repository
{
/**
* Specify Model class name
*
* @return mixed
*/
function model()
{
return 'Webkul\CMS\Contracts\CmsPage';
}
/**
* @param array $data
* @return mixed
*/
public function create(array $data)
{
Event::fire('cms.pages.create.before');
$model = $this->getModel();
foreach (core()->getAllLocales() as $locale) {
foreach ($model->translatedAttributes as $attribute) {
if (isset($data[$attribute]))
$data[$locale->code][$attribute] = $data[$attribute];
}
}
$page = parent::create($data);
$page->channels()->sync($data['channels']);
Event::fire('cms.pages.create.after', $page);
return $page;
}
/**
* @param array $data
* @param integer $id
* @param string $attribute
* @return mixed
*/
public function update(array $data, $id, $attribute = "id")
{
$page = $this->find($id);
Event::fire('cms.pages.update.before', $id);
parent::update($data, $id, $attribute);
$page->channels()->sync($data['channels']);
Event::fire('cms.pages.update.after', $id);
return $page;
}
/**
* Checks slug is unique or not based on locale
*
* @param integer $id
* @param string $urlKey
* @return boolean
*/
public function isUrlKeyUnique($id, $urlKey)
{
$exists = CmsPageTranslation::where('cms_page_id', '<>', $id)
->where('url_key', $urlKey)
->limit(1)
->select(\DB::raw(1))
->exists();
return $exists ? false : true;
}
/**
* Retrive category from slug
*
* @param string $urlKey
* @return mixed
*/
public function findByUrlKeyOrFail($urlKey)
{
$page = $this->model->whereTranslation('url_key', $urlKey)->first();
if ($page)
return $page;
throw (new ModelNotFoundException)->setModel(
get_class($this->model), $urlKey
);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,43 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RemoveTables extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::dropIfExists('cart_rule_cart');
Schema::dropIfExists('cart_rule_labels');
Schema::dropIfExists('cart_rule_channels');
Schema::dropIfExists('cart_rule_customer_groups');
Schema::dropIfExists('cart_rule_customers');
Schema::dropIfExists('cart_rule_coupons');
Schema::dropIfExists('cart_rule_coupon_usage');
Schema::dropIfExists('cart_rule_coupons_usage');
Schema::dropIfExists('cart_rules');
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
}
}

View File

@ -4,7 +4,7 @@ use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCartRuleTable extends Migration
class CreateCartRulesTable extends Migration
{
/**
* Run the migrations.
@ -13,38 +13,29 @@ class CreateCartRuleTable extends Migration
*/
public function up()
{
Schema::dropIfExists('discount_customer_group');
Schema::dropIfExists('discount_channels');
Schema::dropIfExists('discount_rules');
Schema::dropIfExists('discounts');
Schema::dropIfExists('products_grid');
Schema::create('cart_rules', function (Blueprint $table) {
$table->increments('id');
$table->string('name')->nullable();
$table->string('description')->nullable();
$table->datetime('starts_from')->nullable();
$table->datetime('ends_till')->nullable();
$table->date('starts_from')->nullable();
$table->date('ends_till')->nullable();
$table->boolean('status')->default(0);
$table->integer('per_customer')->unsigned()->default(0);
$table->boolean('is_guest')->default(0);
$table->boolean('use_coupon')->default(0);
$table->integer('usage_limit')->unsigned()->default(0);
$table->json('conditions')->nullable();
$table->json('actions')->nullable();
$table->boolean('end_other_rules')->default(0);
$table->integer('priority')->unsigned()->default(0);
$table->boolean('uses_attribute_conditions')->default(0);
$table->longtext('product_ids')->nullable();
$table->integer('sort_order')->unsigned()->default(0);
$table->string('action_type')->nullable();
$table->decimal('disc_amount', 12, 4)->default(0);
$table->decimal('disc_quantity', 12, 4)->default(1);
$table->string('disc_threshold')->default(1);
$table->integer('coupon_type')->default(1);
$table->boolean('auto_generation')->default(0);
$table->boolean('use_auto_generation')->default(0);
$table->integer('usage_per_customer')->default(0);
$table->integer('uses_per_coupon')->default(0);
$table->integer('times_used')->unsigned()->default(0);
$table->boolean('condition_type')->default(1);
$table->json('conditions')->nullable();
$table->boolean('end_other_rules')->default(0);
$table->boolean('uses_attribute_conditions')->default(0);
$table->string('action_type')->nullable();
$table->decimal('discount_amount', 12, 4)->default(0);
$table->integer('discount_quantity')->default(1);
$table->string('discount_step')->default(1);
$table->boolean('apply_to_shipping')->default(0);
$table->boolean('free_shipping')->default(0);
$table->integer('sort_order')->unsigned()->default(0);
$table->timestamps();
});
}

View File

@ -14,12 +14,13 @@ class CreateCartRuleChannelsTable extends Migration
public function up()
{
Schema::create('cart_rule_channels', function (Blueprint $table) {
$table->increments('id');
$table->integer('cart_rule_id')->unsigned();
$table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade');
$table->integer('channel_id')->unsigned();
$table->primary(['cart_rule_id', 'channel_id']);
$table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade');
$table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade');
$table->timestamps();
});
}

View File

@ -14,12 +14,14 @@ class CreateCartRuleCustomerGroupsTable extends Migration
public function up()
{
Schema::create('cart_rule_customer_groups', function (Blueprint $table) {
$table->increments('id');
$table->integer('cart_rule_id')->unsigned();
$table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade');
$table->integer('customer_group_id')->unsigned();
$table->primary(['cart_rule_id', 'customer_group_id']);
$table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade');
$table->foreign('customer_group_id')->references('id')->on('customer_groups')->onDelete('cascade');
$table->timestamps();
});
}

View File

@ -4,7 +4,7 @@ use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCartRuleCartTable extends Migration
class CreateCartRuleTranslationsTable extends Migration
{
/**
* Run the migrations.
@ -13,13 +13,13 @@ class CreateCartRuleCartTable extends Migration
*/
public function up()
{
Schema::create('cart_rule_cart', function (Blueprint $table) {
Schema::create('cart_rule_translations', function (Blueprint $table) {
$table->increments('id');
$table->integer('cart_rule_id')->unsigned()->nullable();
$table->string('locale');
$table->text('label')->nullable();
$table->integer('cart_rule_id')->unsigned();
$table->unique(['cart_rule_id', 'locale']);
$table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade');
$table->integer('cart_id')->unsigned()->nullable();
$table->foreign('cart_id')->references('id')->on('cart')->onDelete('cascade');
$table->timestamps();
});
}
@ -30,6 +30,6 @@ class CreateCartRuleCartTable extends Migration
*/
public function down()
{
Schema::dropIfExists('cart_rule_cart');
Schema::dropIfExists('cart_rule_translations');
}
}

View File

@ -15,12 +15,13 @@ class CreateCartruleCustomersTable extends Migration
{
Schema::create('cart_rule_customers', function (Blueprint $table) {
$table->increments('id');
$table->bigInteger('times_used')->unsigned()->default(0);
$table->integer('cart_rule_id')->unsigned();
$table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade');
$table->integer('customer_id')->unsigned();
$table->foreign('customer_id')->references('id')->on('customers')->onDelete('cascade');
$table->bigInteger('usage_throttle')->unsigned()->default(0);
$table->timestamps();
});
}
@ -31,6 +32,6 @@ class CreateCartruleCustomersTable extends Migration
*/
public function down()
{
Schema::dropIfExists('cart_rule_customers');
Schema::dropIfExists('cartrule_customers');
}
}

View File

@ -15,15 +15,16 @@ class CreateCartruleCouponsTable extends Migration
{
Schema::create('cart_rule_coupons', function (Blueprint $table) {
$table->increments('id');
$table->integer('cart_rule_id')->unsigned();
$table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade');
$table->string('prefix')->nullable();
$table->string('suffix')->nullable();
$table->string('code')->nullable();
$table->integer('usage_limit')->unsigned()->default(0);
$table->integer('usage_per_customer')->unsigned()->default(0);
$table->integer('usage_throttle')->unsigned()->default(0);
$table->integer('times_used')->unsigned()->default(0);
$table->integer('type')->unsigned()->default(0);
$table->boolean('is_primary')->default(0);
$table->date('expired_at')->nullable();
$table->integer('cart_rule_id')->unsigned();
$table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade');
$table->timestamps();
});
}
@ -35,6 +36,6 @@ class CreateCartruleCouponsTable extends Migration
*/
public function down()
{
Schema::dropIfExists('cart_rule_coupons');
Schema::dropIfExists('cartrule_coupons');
}
}

View File

@ -0,0 +1,37 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCartRuleCouponUsageTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('cart_rule_coupon_usage', function (Blueprint $table) {
$table->increments('id');
$table->integer('times_used')->default(0);
$table->integer('cart_rule_coupon_id')->unsigned();
$table->foreign('cart_rule_coupon_id')->references('id')->on('cart_rule_coupons')->onDelete('cascade');
$table->integer('customer_id')->unsigned();
$table->foreign('customer_id')->references('id')->on('customers')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('cart_rule_coupon_usage');
}
}

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