Merge branch 'master' into webinstall

This commit is contained in:
Jitendra Singh 2020-04-11 18:53:30 +05:30 committed by GitHub
commit 9508c3d05c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
128 changed files with 2952 additions and 1765 deletions

View File

@ -4,9 +4,10 @@ APP_VERSION=1.1.0
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
APP_LOCALE=
APP_TIMEZONE=Asia/Kolkata
APP_LOCALE=en
LOG_CHANNEL=stack
APP_CURRENCY=
APP_CURRENCY=USD
DB_CONNECTION=mysql
DB_HOST=127.0.0.1

View File

@ -2,7 +2,123 @@
#### This changelog consists the bug & security fixes and new features being included in the releases listed below.
## **v1.1.0 (20th of March 2020)** - *Release*
## **v1.1.0 (24th of March 2020)** - *Release*
* #797 [fixed] - Add new module
* #826 [fixed] - Impossible to create the root directory "".
* #2152 [fixed] - Product images are not showing
* #2329 [fixed] - Getting exception on frontend after updating meta data.
* #2619 [fixed] - Issue when category slug & product slug are same
* #2684 [fixed] - API checkout/cart returns null for guest user
* #2691 [fixed] - Shipping and Payment methods automatically selected on Checkout oage
* #2706 [fixed] - Getting exception on editing category for pt_BR locale in php 7.4
* #2708 [fixed] - Able to create booking product from back date.
* #2713 [fixed] - fix the invoice header in pdf
* #2726 [fixed] - is shop.js the vue framework ??
* #2752 [fixed] - Error when you create or update a new catalog under root
* #2763 [fixed] - error to add rental booking into cart
* #2764 [fixed] - fix UI when select back_date of booking product,the calendar icon is set on another place
* #2765 [fixed] - Email settings configuration values are not write in .env file
* #2768 [fixed] - Getting exception in cart when remove one ticket from event booking from backend
* #2769 [fixed] - Can't delete Exchange Rates data
* #2774 [fixed] - How to add new icon in bagisto admin panel?
* #2775 [fixed] - compare icon is missing in each product for default theme
* #2776 [fixed] - compare option in side bar menu at customer panel should be available
* #2778 [fixed] - Issue in customer profile dropdown.
* #2779 [fixed] - Issue on checkout page, email should ask first as in default theme.
* #2780 [fixed] - Sidebar layout issue.
* #2781 [fixed] - Mobile menu is not showing correct sub-menu
* #2785 [fixed] - missing address details in checkout page
* #2786 [fixed] - Getting error message on adding product to compare product from search page.
* #2788 [fixed] - guest_checkout is missing from edit product
* #2790 [fixed] - Minicart disable when use new languages only velocity theme
* #2792 [fixed] - Weight Validation Inconsistencies
* #2793 [fixed] - Stock Check Incorrect for Configurable Items
* #2794 [fixed] - When allow backorder is enabled, display a message available for order rather than in stock.
* #2796 [fixed] - Try to create category in windows 10 getting exception
* #2801 [fixed] - Address with more than 2 lines is not added correctly to the cart_address table
* #2807 [fixed] - Illegal mix of collations
* #2808 [fixed] - Correct the spelling on registration page.
* #2810 [fixed] - UI issue on compare similar item page.
* #2811 [fixed] - how to change checkout proccess
* #2812 [fixed] - getting timezone error while setup
* #2813 [fixed] - Ui issue if there is only one product in compare page.
* #2814 [fixed] - variant product's name aren't update when select their options in Front
* #2818 [fixed] - Not able to view menu in velocity theme on storefront
* #2821 [fixed] - Address Line is Null in Emails
* #2825 [fixed] - PHP Notice:
* #2827 [fixed] - default local not changing in storefront in velocity theme
* #2828 [fixed] - currency change error on velocity theme
* #2829 [fixed] - changing home page content in velocity and npm
* #2832 [fixed] - Illegal mix of collations
* #2834 [fixed] - Layout issue in compare page in pt_BR locale
* #2837 [fixed] - subscription bar content source code is not visible in text editor
* #2840 [fixed] - Velocity theme is not available on fresh install
* #2845 [fixed] - Implement custom RegistrationController
* #2846 [fixed] - does not show next step
* #2847 [fixed] - Class 'Faker\Factory' not found
* #2849 [fixed] - Can not add my stylesheet to Velocity theme
* #2851 [fixed] - Fix date picker icon layout at dashboard
* #2856 [fixed] - Issue with Sort by functionality, when open any category it by defaults show Newest First but after changing sort by when again select newest first it shows different product.
## **v1.1.0 (24th of March 2020)** - *Release*
* [feature] Added new booking type product.
@ -10,6 +126,8 @@
* [feature] Impletment compare product feature.
* #2525 [fixed] - Add more settings to the installers
* #2541 [fixed] - Showing product's price with the price including tax
* #2552 [fixed] - error mysql 8
@ -72,14 +190,20 @@
* #2606 [fixed] - custom attributes are not Visible on Product View Page on Front-end
* #2607 [fixed] - Getting exception on editing category for pt_BR locale in php 7.4
* #2608 [fixed] - Getting exception on creating category.
* #2609 [fixed] - product removed from comparison page when update product by name
* #2611 [fixed] - installer error
* #2612 [fixed] - available slots are not showing for current date even if slot time is not expired
* #2613 [fixed] - Propaganistas/Laravel-Intl is abandoned
* #2614 [fixed] - table booking slot time is expired still exist in cart
* #2619 [fixed] - Issue when category slug & product slug are same
* #2621 [fixed] - i create a site and it is up kind of noting works
@ -150,7 +274,9 @@
* #2667 [fixed] - By default wishlist option is selected in cart
* #2669 [fixed] - Booking product should be removed from the cart when selected slot time expired
* #2670 [fixed] - Booking product should be removed from the cart when selected slot time expired
* #2669 [fixed] - Browser compatibility issue
* #2671 [fixed] - Error on moving booking product to wishlist
@ -164,7 +290,25 @@
* #2693 [fixed] - Booking product page - add to cart button js error
* #2707 [fixed] Getting exception when generate invoice in appointment booking
* #2704 [fixed] - product's assigned category can't be removed
* #2707 [fixed] - Getting exception when generate invoice in appointment booking
* #2715 [fixed] - Error message should throw if "To" time is less than "From".
* #2716 [fixed] - After saving the default booking time product selected time for date range changes to 00:00:00 ,because of which not able to book appointment on frontend.
* #2717 [fixed] - Getting error message on adding rental product in cart if rental booking is not available for that day.
* #2722 [fixed] - warning showing when update event booking cart quantity from the product page
* #2723 [fixed] - Compare product icon on header showing counts of compare product but there are no product in compare list.
* #2724 [fixed] - table bookings quantity should update in existing booking added in cart for same slot/date
* #2726 [fixed] - is shop.js the vue framework ??
* #2732 [fixed] - missing product's quick view in category page
## **v1.0.0 (24th of February 2020)** - *Release*

View File

@ -33,20 +33,23 @@
"maatwebsite/excel": "3.1.18",
"nwidart/laravel-modules": "^3.2",
"prettus/l5-repository": "^2.6",
"tymon/jwt-auth": "^1.0.0"
"tymon/jwt-auth": "^1.0.0",
"barryvdh/laravel-debugbar": "^3.1",
"fzaninotto/faker": "^1.4"
},
"require-dev": {
"barryvdh/laravel-debugbar": "^3.1",
"codeception/codeception": "4.1.1",
"codeception/module-asserts": "^1.1",
"codeception/module-filesystem": "^1.0",
"codeception/module-laravel5": "^1.0",
"codeception/module-webdriver": "^1.0",
"filp/whoops": "^2.0",
"fzaninotto/faker": "^1.4",
"mockery/mockery": "^1.0",
"nunomaduro/collision": "^2.0",
"phpunit/phpunit": "^7.0",
"barryvdh/laravel-debugbar": "^3.1",
"fzaninotto/faker": "^1.4"
"phpunit/phpunit": "^7.0"
},
"replace": {

178
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "dca322023597f38ef7991bc9d9bdc50f",
"content-hash": "027ac2836216da68226e72e0ca7e4211",
"packages": [
{
"name": "astrotomic/laravel-translatable",
@ -3914,16 +3914,16 @@
},
{
"name": "symfony/http-foundation",
"version": "v4.4.5",
"version": "v4.4.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "7e41b4fcad4619535f45f8bfa7744c4f384e1648"
"reference": "62f92509c9abfd1f73e17b8cf1b72c0bdac6611b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/7e41b4fcad4619535f45f8bfa7744c4f384e1648",
"reference": "7e41b4fcad4619535f45f8bfa7744c4f384e1648",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/62f92509c9abfd1f73e17b8cf1b72c0bdac6611b",
"reference": "62f92509c9abfd1f73e17b8cf1b72c0bdac6611b",
"shasum": ""
},
"require": {
@ -3965,7 +3965,7 @@
],
"description": "Symfony HttpFoundation Component",
"homepage": "https://symfony.com",
"time": "2020-02-13T19:40:01+00:00"
"time": "2020-03-30T14:07:33+00:00"
},
{
"name": "symfony/http-kernel",
@ -4059,16 +4059,16 @@
},
{
"name": "symfony/mime",
"version": "v5.0.5",
"version": "v5.0.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
"reference": "9b3e5b5e58c56bbd76628c952d2b78556d305f3c"
"reference": "481b7d6da88922fb1e0d86a943987722b08f3955"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/9b3e5b5e58c56bbd76628c952d2b78556d305f3c",
"reference": "9b3e5b5e58c56bbd76628c952d2b78556d305f3c",
"url": "https://api.github.com/repos/symfony/mime/zipball/481b7d6da88922fb1e0d86a943987722b08f3955",
"reference": "481b7d6da88922fb1e0d86a943987722b08f3955",
"shasum": ""
},
"require": {
@ -4117,7 +4117,7 @@
"mime",
"mime-type"
],
"time": "2020-02-04T09:41:09+00:00"
"time": "2020-03-27T16:56:45+00:00"
},
{
"name": "symfony/polyfill-ctype",
@ -4238,16 +4238,16 @@
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.14.0",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "6842f1a39cf7d580655688069a03dd7cd83d244a"
"reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/6842f1a39cf7d580655688069a03dd7cd83d244a",
"reference": "6842f1a39cf7d580655688069a03dd7cd83d244a",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf",
"reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf",
"shasum": ""
},
"require": {
@ -4261,7 +4261,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.14-dev"
"dev-master": "1.15-dev"
}
},
"autoload": {
@ -4296,20 +4296,20 @@
"portable",
"shim"
],
"time": "2020-01-17T12:01:36+00:00"
"time": "2020-03-09T19:04:49+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.14.0",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "34094cfa9abe1f0f14f48f490772db7a775559f2"
"reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/34094cfa9abe1f0f14f48f490772db7a775559f2",
"reference": "34094cfa9abe1f0f14f48f490772db7a775559f2",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac",
"reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac",
"shasum": ""
},
"require": {
@ -4321,7 +4321,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.14-dev"
"dev-master": "1.15-dev"
}
},
"autoload": {
@ -4355,7 +4355,7 @@
"portable",
"shim"
],
"time": "2020-01-13T11:15:53+00:00"
"time": "2020-03-09T19:04:49+00:00"
},
{
"name": "symfony/polyfill-php56",
@ -4415,16 +4415,16 @@
},
{
"name": "symfony/polyfill-php72",
"version": "v1.14.0",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf"
"reference": "37b0976c78b94856543260ce09b460a7bc852747"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf",
"reference": "46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/37b0976c78b94856543260ce09b460a7bc852747",
"reference": "37b0976c78b94856543260ce09b460a7bc852747",
"shasum": ""
},
"require": {
@ -4433,7 +4433,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.14-dev"
"dev-master": "1.15-dev"
}
},
"autoload": {
@ -4466,7 +4466,7 @@
"portable",
"shim"
],
"time": "2020-01-13T11:15:53+00:00"
"time": "2020-02-27T09:26:54+00:00"
},
{
"name": "symfony/polyfill-php73",
@ -5619,6 +5619,61 @@
],
"time": "2019-10-10T15:58:56+00:00"
},
{
"name": "codeception/module-webdriver",
"version": "1.0.5",
"source": {
"type": "git",
"url": "https://github.com/Codeception/module-webdriver.git",
"reference": "cfeadb39170aa80e6fe244de6a130453edd79fe9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/cfeadb39170aa80e6fe244de6a130453edd79fe9",
"reference": "cfeadb39170aa80e6fe244de6a130453edd79fe9",
"shasum": ""
},
"require": {
"codeception/codeception": "4.0.x-dev | ^4.0",
"php": ">=5.6.0 <8.0",
"php-webdriver/webdriver": "^1.6.0"
},
"require-dev": {
"codeception/util-robohelpers": "dev-master"
},
"suggest": {
"codeception/phpbuiltinserver": "Start and stop PHP built-in web server for your tests"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Bodnarchuk"
},
{
"name": "Gintautas Miselis"
},
{
"name": "Zaahid Bateson"
}
],
"description": "WebDriver module for Codeception",
"homepage": "http://codeception.com/",
"keywords": [
"acceptance-testing",
"browser-testing",
"codeception"
],
"time": "2020-03-06T08:39:02+00:00"
},
{
"name": "codeception/phpunit-wrapper",
"version": "7.8.0",
@ -6248,6 +6303,71 @@
"description": "Library for handling version information and constraints",
"time": "2018-07-08T19:19:57+00:00"
},
{
"name": "php-webdriver/webdriver",
"version": "1.8.2",
"source": {
"type": "git",
"url": "https://github.com/php-webdriver/php-webdriver.git",
"reference": "3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab",
"reference": "3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-zip": "*",
"php": "^5.6 || ~7.0",
"symfony/polyfill-mbstring": "^1.12",
"symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.0",
"jakub-onderka/php-parallel-lint": "^1.0",
"php-coveralls/php-coveralls": "^2.0",
"php-mock/php-mock-phpunit": "^1.1",
"phpunit/phpunit": "^5.7",
"sebastian/environment": "^1.3.4 || ^2.0 || ^3.0",
"sminnee/phpunit-mock-objects": "^3.4",
"squizlabs/php_codesniffer": "^3.5",
"symfony/var-dumper": "^3.3 || ^4.0 || ^5.0"
},
"suggest": {
"ext-SimpleXML": "For Firefox profile creation"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8.x-dev"
}
},
"autoload": {
"psr-4": {
"Facebook\\WebDriver\\": "lib/"
},
"files": [
"lib/Exception/TimeoutException.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.",
"homepage": "https://github.com/php-webdriver/php-webdriver",
"keywords": [
"Chromedriver",
"geckodriver",
"php",
"selenium",
"webdriver"
],
"time": "2020-03-04T14:40:12+00:00"
},
{
"name": "phpdocumentor/reflection-common",
"version": "2.0.0",

View File

@ -45,9 +45,10 @@ class ProductController extends Controller
*/
public function get($id)
{
return new ProductResource(
$this->productRepository->findOrFail($id)
);
$product = $this->productRepository->findOrFail($id);
$options = $this->productRepository->findOrFail($id)->getTypeInstance()->getProductOptions($product);
return $options;
}
/**

View File

@ -16,6 +16,9 @@ class CustomerAddress extends JsonResource
{
return [
'id' => $this->id,
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'company_name' => $this->company_name,
'address1' => explode(PHP_EOL, $this->address1),
'country' => $this->country,
'country_name' => core()->country_name($this->country),
@ -27,4 +30,4 @@ class CustomerAddress extends JsonResource
'updated_at' => $this->updated_at,
];
}
}
}

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=c7c2ef0a298910b82304",
"/css/admin.css": "/css/admin.css?id=f2c6fe51889bca1fb79d"
"/js/admin.js": "/js/admin.js?id=2701b1627d73faa941d6",
"/css/admin.css": "/css/admin.css?id=bbb1e500385b8d7ade13"
}

View File

@ -13,6 +13,7 @@ class AddressDataGrid extends DataGrid
*/
public $index = 'address_id';
/**
* @var string
*/
@ -168,4 +169,4 @@ class AddressDataGrid extends DataGrid
'method' => 'DELETE',
]);
}
}
}

View File

@ -3,6 +3,17 @@
margin-bottom: 0 !important;
padding-bottom: 15px;
border-bottom: 1px solid $border-color;
.control-group {
span {
width: 100%;
}
&.date::after {
margin-top: -13px;
left: 100%;
}
}
}
.page-content {

View File

@ -1,8 +1,8 @@
<?php
return [
'save' => 'Salve ',
'create' => 'Crio',
'save' => 'Salvar',
'create' => 'Criar',
'update' => 'Atualizar',
'delete' => 'Excluir',
'failed' => 'Falhou',
@ -64,7 +64,7 @@ return [
'settings' => 'Opções',
'locales' => 'Idiomas',
'currencies' => 'Moedas',
'exchange-rates' => 'Impostos de Câmbios',
'exchange-rates' => 'Taxas de Câmbios',
'inventory-sources' => 'Fontes de Inventários',
'channels' => 'Canais (Lojas)',
'users' => 'Usuários',
@ -98,7 +98,7 @@ return [
'locales' => 'Idiomas',
'currencies' => 'Moedas',
'exchange-rates' => 'Impostos de Câmbios',
'inventory-sources' => 'Fontes de Inventários',
'inventory-sources' => 'Origens de Estoque',
'channels' => 'Canais (Lojas)',
'users' => 'Usuários',
'roles' => 'Funções',
@ -1248,7 +1248,7 @@ return [
'allow-guest-review' => 'Permitir comentário de convidado',
'inventory' => 'Inventário',
'stock-options' => 'Opções de ações',
'allow-backorders' => 'Permitir atrasos',
'allow-backorders' => 'Permitir Pedidos por Admin',
'customer' => 'Cliente',
'settings' => 'Definições',
'address' => 'Endereço',
@ -1287,29 +1287,30 @@ return [
'locale-options' => 'Opções de unidade',
'weight-unit' => 'Unidade de peso',
'admin-page-limit' => 'Itens padrão por página (administrador)',
'design' => 'Projeto',
'email-settings' => 'Email Settings',
'email-sender-name' => 'Email Sender Name',
'shop-email-from' => 'Shop Email Address [For sending emails]',
'admin-name' => 'Admin Name',
'design' => 'Design',
'email-settings' => 'Configurações de Email',
'email-sender-name' => 'Nome do Email da Loja',
'shop-email-from' => 'Endereço de Email da Loja [Para enviar emails]',
'admin-name' => 'Admin Nome',
'admin-email' => 'Admin Email',
'admin-page-limit' => 'Quantidade Padrão de Itens por Página (Admin)',
'design' => 'Design',
'admin-logo' => 'Admin Logo',
'logo-image' => 'Logo Imagem',
'credit-max' => 'Máximo de crédito do cliente',
'credit-max-value' => 'Valor Máximo de Crédito',
'use-credit-max' => 'Use o máximo de crédito',
'order-settings' => 'Order Settings',
'orderNumber' => 'Order Number Settings',
'order-number-prefix' => 'Order Number Prefix',
'order-number-length' => 'Order Number Length',
'order-number-suffix' => 'Order Number Suffix',
'order-settings' => 'Configurações do Pedido',
'orderNumber' => 'Configuração do Número do Pedido',
'order-number-prefix' => 'Prefixo do Número do Pedido',
'order-number-length' => 'Tamanho do Número do Pedido',
'order-number-suffix' => 'Sufixo do Número de Pedido',
'default' => 'Padrão',
'sandbox' => 'Sandbox',
'all-channels' => 'Todos',
'all-locales' => 'Todos',
'sandbox' => 'Sandbox',
'invoice-slip-design' => 'Invoice Slip Design',
'invoice-slip-design' => 'Design da Nota do Pedido',
'logo' => 'logo'
]
]

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;" v-slugify-target="'slug'"/>
<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;" v-slugify-target="'slug'"/>
<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

@ -148,14 +148,14 @@
<td>
<div class="control-group" :class="[errors.has(variantInputName + '[price]') ? 'has-error' : '']">
<input type="number" v-validate="'required|min_value:0.0001'" v-model="variant.price" :name="[variantInputName + '[price]']" class="control" data-vv-as="&quot;{{ __('admin::app.catalog.products.price') }}&quot;" step="any"/>
<input type="number" v-validate="'required'" v-model="variant.price" :name="[variantInputName + '[price]']" class="control" data-vv-as="&quot;{{ __('admin::app.catalog.products.price') }}&quot;" step="any"/>
<span class="control-error" v-if="errors.has(variantInputName + '[price]')">@{{ errors.first(variantInputName + '[price]') }}</span>
</div>
</td>
<td>
<div class="control-group" :class="[errors.has(variantInputName + '[weight]') ? 'has-error' : '']">
<input type="number" v-validate="'required|min_value:0.0001'" v-model="variant.weight" :name="[variantInputName + '[weight]']" class="control" data-vv-as="&quot;{{ __('admin::app.catalog.products.weight') }}&quot;" step="any"/>
<input type="number" v-validate="'required'" v-model="variant.weight" :name="[variantInputName + '[weight]']" class="control" data-vv-as="&quot;{{ __('admin::app.catalog.products.weight') }}&quot;" step="any"/>
<span class="control-error" v-if="errors.has(variantInputName + '[weight]')">@{{ errors.first(variantInputName + '[weight]') }}</span>
</div>
</td>

View File

@ -87,9 +87,11 @@
<div class="container">
<div class="header">
<div class="image">
<img class="logo" src="{{ Storage::url(core()->getConfigData('sales.orderSettings.invoice_slip_design.logo')) }}"/>
</div>
@if (core()->getConfigData('sales.orderSettings.invoice_slip_design.logo'))
<div class="image">
<img class="logo" src="{{ Storage::url(core()->getConfigData('sales.orderSettings.invoice_slip_design.logo')) }}"/>
</div>
@endif
<div class="address">
<p>
<b> {{ core()->getConfigData('sales.orderSettings.invoice_slip_design.address') }} </b>

View File

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

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
{
"/css/default-booking.css": "/css/default-booking.css?id=3607d6ec4cb93857b42c",
"/css/default-booking.css": "/css/default-booking.css?id=ab5abfabd8e0f6df6466",
"/css/velocity-booking.css": "/css/velocity-booking.css?id=fb0d5b9e37ed77d662d1"
}

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AlterBookingProductsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('booking_products', function (Blueprint $table) {
$table->datetime('available_from')->change();
$table->datetime('available_to')->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}

View File

@ -178,7 +178,7 @@ class Booking
$availableFrom = ! $bookingProduct->available_from && $bookingProduct->available_from
? Carbon::createFromTimeString($bookingProduct->available_from)
: clone $currentTime;
: Carbon::createFromTimeString($currentTime->format('Y-m-d 00:00:00'));
$availableTo = ! $bookingProduct->available_from && $bookingProduct->available_to
? Carbon::createFromTimeString($bookingProduct->available_to)
@ -254,13 +254,13 @@ class Booking
return [];
}
$requestedDate = Carbon::createFromTimeString($date . " 00:00:00");
$currentTime = Carbon::now();
$requestedDate = Carbon::createFromTimeString($date . " 00:00:00");
$availableFrom = ! $bookingProduct->available_every_week && $bookingProduct->available_from
? Carbon::createFromTimeString($bookingProduct->available_from)
: Carbon::createFromTimeString($currentTime);
: Carbon::createFromTimeString($currentTime->format('Y-m-d 00:00:00'));
$availableTo = ! $bookingProduct->available_every_week && $bookingProduct->available_from
? Carbon::createFromTimeString($bookingProduct->available_to)
@ -270,8 +270,7 @@ class Booking
? $bookingProductSlot->slots
: ($bookingProductSlot->slots[$requestedDate->format('w')] ?? []);
if ($requestedDate < $currentTime
|| $requestedDate < $availableFrom
if ($requestedDate < $availableFrom
|| $requestedDate > $availableTo
) {
return [];

View File

@ -32,14 +32,13 @@ class DefaultSlot extends Booking
$availableFrom = $bookingProduct->available_from
? Carbon::createFromTimeString($bookingProduct->available_from)
: clone $currentTime;
: Carbon::createFromTimeString($currentTime->format('Y-m-d 00:00:00'));
$availableTo = $bookingProduct->available_to
? Carbon::createFromTimeString($bookingProduct->available_to)
: Carbon::createFromTimeString('2080-01-01 00:00:00');
if ($requestedDate < $currentTime
|| $requestedDate < $availableFrom
if ($requestedDate < $availableFrom
|| $requestedDate > $availableTo
) {
return [];
@ -101,7 +100,7 @@ class DefaultSlot extends Booking
$availableFrom = $bookingProduct->available_from
? Carbon::createFromTimeString($bookingProduct->available_from)
: clone $currentTime;
: Carbon::createFromTimeString($currentTime->format('Y-m-d 00:00:00'));
$availableTo = $bookingProduct->available_to
? Carbon::createFromTimeString($bookingProduct->available_to)

View File

@ -4,6 +4,7 @@ namespace Webkul\BookingProduct\Helpers;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use Webkul\Checkout\Facades\Cart;
class EventTicket extends Booking
{
@ -124,6 +125,12 @@ class EventTicket extends Booking
$ticket = $bookingProduct->event_tickets()->find($item->additional['booking']['ticket_id']);
if (! $ticket) {
Cart::removeItem($item->id);
return true;
}
$price += $ticket->price;
if ($price == $item->base_price) {

View File

@ -29,7 +29,7 @@ class RentalSlot extends Booking
$availableFrom = ! $bookingProduct->available_every_week && $bookingProduct->available_from
? Carbon::createFromTimeString($bookingProduct->available_from)
: Carbon::createFromTimeString($currentTime);
: Carbon::createFromTimeString($currentTime->format('Y-m-d 00:00:00'));
$availableTo = ! $bookingProduct->available_every_week && $bookingProduct->available_from
? Carbon::createFromTimeString($bookingProduct->available_to)
@ -37,10 +37,9 @@ class RentalSlot extends Booking
$timeDurations = $bookingProductSlot->same_slot_all_days
? $bookingProductSlot->slots
: $bookingProductSlot->slots[$requestedDate->format('w')];
: $bookingProductSlot->slots[$requestedDate->format('w')] ?? [];
if ($requestedDate < $currentTime
|| $requestedDate < $availableFrom
if ($requestedDate < $availableFrom
|| $requestedDate > $availableTo
) {
return [];
@ -141,24 +140,48 @@ class RentalSlot extends Booking
public function isSlotExpired($cartItem)
{
$bookingProduct = $this->bookingProductRepository->findOneByField('product_id', $cartItem['product_id']);
$typeHelper = app($this->typeHelpers[$bookingProduct->type]);
$timeIntervals = $typeHelper->getSlotsByDate($bookingProduct, $cartItem['additional']['booking']['date']);
if (isset($cartItem['additional']['booking']['date'])) {
$timeIntervals = $this->getSlotsByDate($bookingProduct, $cartItem['additional']['booking']['date']);
$isExpired = true;
$isExpired = true;
foreach ($timeIntervals as $timeInterval) {
foreach ($timeInterval['slots'] as $slot) {
if ($slot['from_timestamp'] == $cartItem['additional']['booking']['slot']['from']
&& $slot['to_timestamp'] == $cartItem['additional']['booking']['slot']['to']
) {
$isExpired = false;
foreach ($timeIntervals as $timeInterval) {
foreach ($timeInterval['slots'] as $slot) {
if ($slot['from_timestamp'] == $cartItem['additional']['booking']['slot']['from']
&& $slot['to_timestamp'] == $cartItem['additional']['booking']['slot']['to']
) {
$isExpired = false;
}
}
}
}
return $isExpired;
return $isExpired;
} else {
$currentTime = Carbon::now();
$requestedFromDate = Carbon::createFromTimeString($cartItem['additional']['booking']['date_from'] . " 00:00:00");
$requestedToDate = Carbon::createFromTimeString($cartItem['additional']['booking']['date_to'] . " 23:59:59");
$availableFrom = ! $bookingProduct->available_every_week && $bookingProduct->available_from
? Carbon::createFromTimeString($bookingProduct->available_from->format('Y-m-d') . ' 00:00:00')
: Carbon::createFromTimeString($currentTime->format('Y-m-d 00:00:00'));
$availableTo = ! $bookingProduct->available_every_week && $bookingProduct->available_from
? Carbon::createFromTimeString($bookingProduct->available_to->format('Y-m-d') . ' 23:59:59')
: Carbon::createFromTimeString('2080-01-01 00:00:00');
if ($requestedFromDate < $availableFrom
|| $requestedFromDate > $availableTo
|| $requestedToDate < $availableFrom
|| $requestedToDate > $availableTo
) {
return true;
}
return false;
}
}
/**

View File

@ -22,7 +22,7 @@ class TableSlot extends Booking
$bookedQty *= $bookingProduct->table_slot->guest_limit;
}
if ($bookingProduct->qty - $bookedQty < $requestedQty) {
if ($bookingProduct->qty - $bookedQty < $requestedQty || $this->isSlotExpired($cartItem)) {
return false;
}

View File

@ -174,6 +174,12 @@ class BookingProductRepository extends Repository
$to = Carbon::createFromTimeString($timeInterval['to'])->getTimestamp();
if ($from > $to) {
unset($slots[$key]);
continue;
}
$isOverLapping = false;
foreach ($tempSlots as $slot) {

View File

@ -130,9 +130,8 @@
padding-right: 5px;
&::after {
position: absolute;
top: 14px;
right: 10px;
top: 16px;
left: 100%;
}
}

View File

@ -1,3 +1,12 @@
@section('css')
<style>
.slot-list .control-group.date::after {
margin-top: -13px;
left: 100%;
}
</style>
@stop
{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.booking.before', ['product' => $product]) !!}
<accordian :title="'{{ __('bookingproduct::app.admin.catalog.products.booking') }}'" :active="true">
@ -57,21 +66,21 @@
</div>
<div v-if="! parseInt(booking.available_every_week)">
<div class="control-group" :class="[errors.has('booking[available_from]') ? 'has-error' : '']">
<div class="control-group date" :class="[errors.has('booking[available_from]') ? 'has-error' : '']">
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.available-from') }}</label>
<datetime>
<input type="text" v-validate="'required'" name="booking[available_from]" v-model="booking.available_from" class="control" data-vv-as="&quot;{{ __('bookingproduct::app.admin.catalog.products.available-from') }}&quot;"/>
<input type="text" v-validate="'required|date_format:yyyy-MM-dd HH:mm:ss|after:{{\Carbon\Carbon::yesterday()->format('Y-m-d 23:59:59')}}'" name="booking[available_from]" v-model="booking.available_from" class="control" data-vv-as="&quot;{{ __('bookingproduct::app.admin.catalog.products.available-from') }}&quot;" ref="available_from"/>
</datetime>
<span class="control-error" v-if="errors.has('booking[available_from]')">@{{ errors.first('booking[available_from]') }}</span>
</div>
<div class="control-group" :class="[errors.has('booking[available_to]') ? 'has-error' : '']">
<div class="control-group date" :class="[errors.has('booking[available_to]') ? 'has-error' : '']">
<label class="required">{{ __('bookingproduct::app.admin.catalog.products.available-to') }}</label>
<datetime>
<input type="text" v-validate="'required'" name="booking[available_to]" v-model="booking.available_to" class="control" data-vv-as="&quot;{{ __('bookingproduct::app.admin.catalog.products.available-to') }}&quot;"/>
<input type="text" v-validate="'required|date_format:yyyy-MM-dd HH:mm:ss|after:available_from'" name="booking[available_to]" v-model="booking.available_to" class="control" data-vv-as="&quot;{{ __('bookingproduct::app.admin.catalog.products.available-to') }}&quot;" ref="available_to"/>
</datetime>
<span class="control-error" v-if="errors.has('booking[available_to]')">@{{ errors.first('booking[available_to]') }}</span>

View File

@ -165,7 +165,7 @@
<span class="control-error" v-if="errors.has(controlName + '[from_day]')">@{{ errors.first(controlName + '[from_day]') }}</span>
</div>
<div class="control-group" :class="[errors.has(controlName + '[from]') ? 'has-error' : '']">
<div class="control-group date" :class="[errors.has(controlName + '[from]') ? 'has-error' : '']">
<time-component>
<input type="text" v-validate="'required'" :name="controlName + '[from]'" v-model="slotItem.from" class="control" data-vv-as="&quot;{{ __('bookingproduct::app.admin.catalog.products.from') }}&quot;">
</time-component>
@ -185,7 +185,7 @@
<span class="control-error" v-if="errors.has(controlName + '[to_day]')">@{{ errors.first(controlName + '[to_day]') }}</span>
</div>
<div class="control-group" :class="[errors.has(controlName + '[to]') ? 'has-error' : '']">
<div class="control-group date" :class="[errors.has(controlName + '[to]') ? 'has-error' : '']">
<time-component>
<input type="text" v-validate="'required'" :name="controlName + '[to]'" v-model="slotItem.to" class="control" data-vv-as="&quot;{{ __('bookingproduct::app.admin.catalog.products.to') }}&quot;">
</time-component>

View File

@ -71,7 +71,7 @@
<script type="text/x-template" id="slot-item-template">
<tr>
<td>
<div class="control-group" :class="[errors.has(controlName + '[from]') ? 'has-error' : '']">
<div class="control-group date" :class="[errors.has(controlName + '[from]') ? 'has-error' : '']">
<time-component>
<input type="text" v-validate="'required'" :name="controlName + '[from]'" v-model="slotItem.from" class="control" data-vv-as="&quot;{{ __('bookingproduct::app.admin.catalog.products.from') }}&quot;">
</time-component>
@ -83,7 +83,7 @@
</td>
<td>
<div class="control-group" :class="[errors.has(controlName + '[to]') ? 'has-error' : '']">
<div class="control-group date" :class="[errors.has(controlName + '[to]') ? 'has-error' : '']">
<time-component>
<input type="text" v-validate="'required'" :name="controlName + '[to]'" v-model="slotItem.to" class="control" data-vv-as="&quot;{{ __('bookingproduct::app.admin.catalog.products.to') }}&quot;">
</time-component>

View File

@ -86,7 +86,7 @@
<div class="control-group-container">
<div class="control-group date" :class="[errors.has('booking[date_from]') ? 'has-error' : '']">
<date @onChange="dateSelected($event)">
<input type="text" v-validate="'required'" name="booking[date_from]" v-model="date_from" class="control" data-vv-as="&quot;{{ __('bookingproduct::app.shop.products.from') }}&quot;" placeholder="{{ __('bookingproduct::app.shop.products.from') }}" data-min-date="today"/>
<input type="text" v-validate="'required|date_format:yyyy-MM-dd|before_or_equal:date_to'" name="booking[date_from]" v-model="date_from" class="control" data-vv-as="&quot;{{ __('bookingproduct::app.shop.products.from') }}&quot;" placeholder="{{ __('bookingproduct::app.shop.products.from') }}" ref="date_from" data-min-date="today"/>
</date>
<span class="control-error" v-if="errors.has('booking[date_from]')">@{{ errors.first('booking[date_from]') }}</span>
@ -94,7 +94,7 @@
<div class="control-group date" :class="[errors.has('booking[date_to]') ? 'has-error' : '']">
<date @onChange="dateSelected($event)">
<input type="text" v-validate="'required'" name="booking[date_to]" v-model="date_to" class="control" data-vv-as="&quot;{{ __('bookingproduct::app.shop.products.to') }}&quot;" placeholder="{{ __('bookingproduct::app.shop.products.to') }}"/>
<input type="text" v-validate="'required|date_format:yyyy-MM-dd|after_or_equal:date_from'" name="booking[date_to]" v-model="date_to" class="control" data-vv-as="&quot;{{ __('bookingproduct::app.shop.products.to') }}&quot;" placeholder="{{ __('bookingproduct::app.shop.products.to') }}" ref="date_to" data-min-date="today"/>
</date>
<span class="control-error" v-if="errors.has('booking[date_to]')">@{{ errors.first('booking[date_to]') }}</span>
@ -131,6 +131,46 @@
}
},
created: function() {
var self = this;
this.$validator.extend('after_or_equal', {
getMessage(field, val) {
return 'The "To" must be equal or after "From"';
},
validate(value, field) {
if (! self.date_from) {
return true;
}
var from = new Date(self.date_from);
var to = new Date(self.date_to);
return from <= to;
}
});
this.$validator.extend('before_or_equal', {
getMessage(field, val) {
return 'The "From must be equal or before "To"';
},
validate(value, field) {
if (! self.date_to) {
return true;
}
var from = new Date(self.date_from);
var to = new Date(self.date_to);
return from <= to;
}
});
},
methods: {
dateSelected: function(date) {
var this_this = this;

View File

@ -86,7 +86,7 @@
<div class="control-group-container">
<div class="form-group date" :class="[errors.has('booking[date_from]') ? 'has-error' : '']">
<date @onChange="dateSelected($event)">
<input type="text" v-validate="'required'" name="booking[date_from]" v-model="date_from" class="form-style" data-vv-as="&quot;{{ __('bookingproduct::app.shop.products.from') }}&quot;" placeholder="{{ __('bookingproduct::app.shop.products.from') }}" data-min-date="today"/>
<input type="text" v-validate="'required|date_format:yyyy-MM-dd|before_or_equal:date_to'" name="booking[date_from]" v-model="date_from" class="form-style" data-vv-as="&quot;{{ __('bookingproduct::app.shop.products.from') }}&quot;" placeholder="{{ __('bookingproduct::app.shop.products.from') }}" ref="date_from" data-min-date="today"/>
</date>
<span class="control-error" v-if="errors.has('booking[date_from]')">@{{ errors.first('booking[date_from]') }}</span>
@ -94,7 +94,7 @@
<div class="form-group date" :class="[errors.has('booking[date_to]') ? 'has-error' : '']">
<date @onChange="dateSelected($event)">
<input type="text" v-validate="'required'" name="booking[date_to]" v-model="date_to" class="form-style" data-vv-as="&quot;{{ __('bookingproduct::app.shop.products.to') }}&quot;" placeholder="{{ __('bookingproduct::app.shop.products.to') }}"/>
<input type="text" v-validate="'required|date_format:yyyy-MM-dd|after_or_equal:date_from'" name="booking[date_to]" v-model="date_to" class="form-style" data-vv-as="&quot;{{ __('bookingproduct::app.shop.products.to') }}&quot;" placeholder="{{ __('bookingproduct::app.shop.products.to') }}" ref="date_to" data-min-date="today"/>
</date>
<span class="control-error" v-if="errors.has('booking[date_to]')">@{{ errors.first('booking[date_to]') }}</span>
@ -131,6 +131,46 @@
}
},
created: function() {
var self = this;
this.$validator.extend('after_or_equal', {
getMessage(field, val) {
return 'The "To" must be equal or after "From"';
},
validate(value, field) {
if (! self.date_from) {
return true;
}
var from = new Date(self.date_from);
var to = new Date(self.date_to);
return from <= to;
}
});
this.$validator.extend('before_or_equal', {
getMessage(field, val) {
return 'The "From must be equal or before "To"';
},
validate(value, field) {
if (! self.date_to) {
return true;
}
var from = new Date(self.date_from);
var to = new Date(self.date_to);
return from <= to;
}
});
},
methods: {
dateSelected: function(date) {
var this_this = this;

View File

@ -2,6 +2,7 @@
namespace Webkul\BookingProduct\Type;
use Illuminate\Support\Arr;
use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Product\Repositories\ProductRepository;
use Webkul\Product\Repositories\ProductAttributeValueRepository;
@ -167,6 +168,14 @@ class Booking extends Virtual
$bookingProduct = $this->getBookingProduct($data['product_id']);
if ($bookingProduct->type == 'event') {
$filtered = Arr::where($data['booking']['qty'], function ($qty, $key) {
return $qty != 0;
});
if (! count($filtered)) {
return trans('shop::app.checkout.cart.integrity.missing_options');
}
foreach ($data['booking']['qty'] as $ticketId => $qty) {
if (! $qty) {
continue;
@ -214,7 +223,7 @@ class Booking extends Virtual
}
if (isset($options1['booking']) && isset($options2['booking'])) {
return $options1['booking'] === $options2['booking'];
return $options1['booking'] == $options2['booking'];
} elseif (! isset($options1['booking'])) {
return false;
} elseif (! isset($options2['booking'])) {

View File

@ -165,9 +165,9 @@ class Cart
'cart_id' => $cart->id
]));
} else {
if ($cartItem->product->getTypeInstance()->showQuantityBox() === false) {
return ['warning' => __('shop::app.checkout.cart.integrity.qty_impossible')];
}
// if ($cartItem->product->getTypeInstance()->showQuantityBox() === false) {
// return ['warning' => __('shop::app.checkout.cart.integrity.qty_impossible')];
// }
$cartItem = $this->cartItemRepository->update($cartProduct, $cartItem->id);
}

View File

@ -64,6 +64,9 @@ class Core
*/
protected $coreConfigRepository;
/** @var Channel */
private static $channel;
/**
* Create a new instance.
*
@ -125,23 +128,31 @@ class Core
*/
public function getCurrentChannel()
{
static $channel;
if ($channel) {
return $channel;
if (self::$channel) {
return self::$channel;
}
$channel = $this->channelRepository->findWhereIn('hostname', [
self::$channel = $this->channelRepository->findWhereIn('hostname', [
request()->getHttpHost(),
'http://' . request()->getHttpHost(),
'https://' . request()->getHttpHost(),
])->first();
if (! $channel) {
$channel = $this->channelRepository->first();
if (! self::$channel) {
self::$channel = $this->channelRepository->first();
}
return $channel;
return self::$channel;
}
/**
* Set the current channel
*
* @param Channel $channel
*/
public function setCurrentChannel(Channel $channel): void
{
self::$channel = $channel;
}
/**
@ -471,40 +482,20 @@ class Core
return $formatter->getSymbol(\NumberFormatter::CURRENCY_SYMBOL);
}
/**
* Format and convert price with currency symbol
*
* @param float $price
* @param string $currencyCode
* @return string
*/
/**
* Format and convert price with currency symbol
*
* @param float $price
* @return string
*/
public function formatPrice($price, $currencyCode)
{
$code = $this->getCurrentCurrency()->code;
if (is_null($price)) {
if (is_null($price))
$price = 0;
} else {
if ($code != $currencyCode) {
$price = $this->convertPrice($price, $code, $currencyCode);
}
}
$formater = new \NumberFormatter(app()->getLocale(), \NumberFormatter::CURRENCY);
$formatter = new \NumberFormatter( app()->getLocale(), \NumberFormatter::CURRENCY );
$symbol = $this->getCurrentCurrency()->symbol;
if ($symbol) {
if ($this->currencySymbol($currencyCode) == $symbol) {
return $formater->formatCurrency($price, $currencyCode);
} else {
$formater->setSymbol(\NumberFormatter::CURRENCY_SYMBOL, $symbol);
return $formater->format($price); // $this->convertPrice($price, $code)
}
} else {
return $formater->formatCurrency($price, $currencyCode);
}
return $formatter->formatCurrency($price, $currencyCode);
}
/**
@ -704,7 +695,7 @@ class Core
$fields = explode(".", $field);
array_shift($fields);
$field = implode(".", $fields);
return Config::get($field);
@ -852,9 +843,9 @@ class Core
}
/**
*
*
* @param string $date
* @param int $day
* @param int $day
* @return string
*/
public function xWeekRange($date, $day)
@ -993,7 +984,7 @@ class Core
protected function arrayMerge(array &$array1, array &$array2)
{
$merged = $array1;
foreach ($array2 as $key => &$value) {
if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
$merged[$key] = $this->arrayMerge($merged[$key], $value);
@ -1039,7 +1030,7 @@ class Core
/**
* Returns a string as selector part for identifying elements in views
*
*
* @param float $taxRate
* @return string
*/

View File

@ -0,0 +1,20 @@
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
use Faker\Generator as Faker;
use Webkul\CartRule\Models\CartRule;
use Webkul\CartRule\Models\CartRuleCoupon;
$factory->define(CartRuleCoupon::class, function (Faker $faker) {
return [
'code' => $faker->uuid(),
'usage_limit' => 100,
'usage_per_customer' => 100,
'type' => 0,
'is_primary' => 1,
'cart_rule_id' => static function () {
return factory(CartRule::class)->create()->id;
},
];
});

View File

@ -5,8 +5,13 @@ use Webkul\Core\Models\Locale;
/** @var \Illuminate\Database\Eloquent\Factory $factory */
$factory->define(Locale::class, function (Faker $faker, array $attributes) {
do {
$languageCode = $faker->languageCode;
} while (Locale::query()->where('code', $languageCode)->exists());
return [
'code' => $faker->languageCode,
'code' => $languageCode,
'name' => $faker->country,
'direction' => 'ltr',
];
@ -14,4 +19,4 @@ $factory->define(Locale::class, function (Faker $faker, array $attributes) {
$factory->state(Category::class, 'rtl', [
'direction' => 'rtl',
]);
]);

View File

@ -5,19 +5,27 @@ namespace Webkul\Core\Helpers;
// here you can define custom actions
// all public methods declared in helper class will be available in $I
use Faker\Factory;
use Codeception\Module\Laravel5;
use Webkul\Checkout\Models\Cart;
use Webkul\Customer\Models\Customer;
use Webkul\Checkout\Models\CartItem;
use Illuminate\Support\Facades\Event;
use Webkul\Product\Models\Product;
use Webkul\Attribute\Models\Attribute;
use Webkul\Checkout\Models\CartAddress;
use Webkul\Product\Models\ProductInventory;
use Webkul\Customer\Models\CustomerAddress;
use Webkul\Attribute\Models\AttributeOption;
use Webkul\Product\Models\ProductAttributeValue;
use Webkul\Product\Models\ProductDownloadableLink;
use Webkul\Product\Models\ProductDownloadableLinkTranslation;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
/**
* Class Laravel5Helper
*
* @package Webkul\Core\Helpers
*/
class Laravel5Helper extends Laravel5
{
public const SIMPLE_PRODUCT = 1;
@ -25,62 +33,31 @@ class Laravel5Helper extends Laravel5
public const DOWNLOADABLE_PRODUCT = 3;
/**
* Returns field name of given attribute.
* Returns the field name of the given attribute in which a value should be saved inside
* the 'product_attribute_values' table. Depends on the type.
*
* @param string $attribute
*
* @return string|null
* @part ORM
*/
public static function getAttributeFieldName(string $attribute): ?string
public static function getAttributeFieldName(string $type): ?string
{
$attributes = [
'product_id' => 'integer_value',
'sku' => 'text_value',
'name' => 'text_value',
'url_key' => 'text_value',
'tax_category_id' => 'integer_value',
'new' => 'boolean_value',
'featured' => 'boolean_value',
'visible_individually' => 'boolean_value',
'status' => 'boolean_value',
'short_description' => 'text_value',
'description' => 'text_value',
'price' => 'float_value',
'cost' => 'float_value',
'special_price' => 'float_value',
'special_price_from' => 'date_value',
'special_price_to' => 'date_value',
'meta_title' => 'text_value',
'meta_keywords' => 'text_value',
'meta_description' => 'text_value',
'width' => 'integer_value',
'height' => 'integer_value',
'depth' => 'integer_value',
'weight' => 'integer_value',
'color' => 'integer_value',
'size' => 'integer_value',
'brand' => 'text_value',
'guest_checkout' => 'boolean_value',
$attributes = [];
$possibleTypes = [
'text' => 'text_value',
'select' => 'integer_value',
'boolean' => 'boolean_value',
'textarea' => 'text_value',
'price' => 'float_value',
'date' => 'date_value',
];
if (! array_key_exists($attribute, $attributes)) {
return null;
}
return $attributes[$attribute];
return $possibleTypes[$type];
}
/**
* Generate a cart for the customer. Usually this is necessary to prepare the database
* before testing the checkout.
*
* @param array $options pass some options to configure some of the properties of the cart
*
* @return array the generated mocks as array
*
* @throws \Exception
*/
public function prepareCart(array $options = []): array
{
$faker = \Faker\Factory::create();
@ -96,8 +73,8 @@ class Laravel5Helper extends Laravel5
}
$I->have(CustomerAddress::class, [
'customer_id' => $customer->id,
'default_address' => 1,
'customer_id' => $customer->id,
'first_name' => $customer->first_name,
'last_name' => $customer->last_name,
'company_name' => $faker->company,
@ -117,19 +94,15 @@ class Laravel5Helper extends Laravel5
'customer_first_name' => $customer->first_name,
'customer_last_name' => $customer->last_name,
'customer_email' => $customer->email,
'is_active' => 1,
'channel_id' => 1,
'is_active' => $options['is_active'] ?? 1,
'channel_id' => $options['channel_id'] ?? 1,
'grand_total' => $grand_total,
'base_grand_total' => $base_grand_total,
]);
$cartAddress = $I->have(CartAddress::class, ['cart_id' => $cart->id]);
if (isset($options['product_type'])) {
$type = $options['product_type'];
} else {
$type = 'simple';
}
$type = $options['product_type'] ?? 'simple';
$totalQtyOrdered = 0;
@ -165,37 +138,52 @@ class Laravel5Helper extends Laravel5
'cartItems' => $cartItems,
'totalQtyOrdered' => $totalQtyOrdered,
];
}
/**
* Set all session with the given key and value in the array.
*
* @param array $keyValue
*/
public function setSession(array $keyValue): void
{
session($keyValue);
}
/**
* Flush the session data and regenerate the ID
* A logged in user will be logged off.
*/
public function invalidateSession(): void
{
session()->invalidate();
}
/**
* Helper function to generate products for testing
* Helper function to generate products for testing.
*
* @param int $productType
* By default, the product will be generated as saleable, this means it has a price,
* weight, is active and has a positive inventory stock, if necessary.
*
* @param int $productType see constants in this class for usage
* @param array $configs
* @param array $productStates
*
* @return \Webkul\Product\Models\Product
* @part ORM
*/
public function haveProduct(
int $productType,
array $configs = [],
array $productStates = []
): Product
public function haveProduct(int $productType, array $configs = [], array $productStates = []): Product
{
$I = $this;
switch ($productType) {
case self::DOWNLOADABLE_PRODUCT:
$product = $I->haveDownloadableProduct($configs, $productStates);
break;
case self::VIRTUAL_PRODUCT:
$product = $I->haveVirtualProduct($configs, $productStates);
break;
case self::SIMPLE_PRODUCT:
@ -210,40 +198,9 @@ class Laravel5Helper extends Laravel5
return $product;
}
/**
* Set all session with the given key and value in the array.
*
* @param array $keyValue
*/
public function setSession(array $keyValue)
{
session($keyValue);
}
/**
* Flush the session data and regenerate the ID
* A logged in user will be logged off.
*
*/
public function invalidateSession()
{
session()->invalidate();
}
/**
* @param array $configs
* @param array $productStates
*
* @return \Webkul\Product\Models\Product
*/
private function haveSimpleProduct(
array $configs = [],
array $productStates = []
): Product
private function haveSimpleProduct(array $configs = [], array $productStates = []): Product
{
$I = $this;
if (! in_array('simple', $productStates)) {
$productStates = array_merge($productStates, ['simple']);
}
@ -258,16 +215,9 @@ class Laravel5Helper extends Laravel5
return $product->refresh();
}
/**
* @param array $configs
* @param array $productStates
*
* @return \Webkul\Product\Contracts\Product
*/
private function haveVirtualProduct(array $configs = [], array $productStates = []): Product
{
$I = $this;
if (! in_array('virtual', $productStates)) {
$productStates = array_merge($productStates, ['virtual']);
}
@ -282,16 +232,9 @@ class Laravel5Helper extends Laravel5
return $product->refresh();
}
/**
* @param array $configs
* @param array $productStates
*
* @return \Webkul\Product\Contracts\Product
*/
private function haveDownloadableProduct(array $configs = [], array $productStates = []): Product
{
$I = $this;
if (! in_array('downloadable', $productStates)) {
$productStates = array_merge($productStates, ['downloadable']);
}
@ -306,44 +249,23 @@ class Laravel5Helper extends Laravel5
return $product->refresh();
}
/**
* @param array $attributes
* @param array $states
*
* @return \Webkul\Product\Models\Product
*/
private function createProduct(array $attributes = [], array $states = []): Product
{
return factory(Product::class)->states($states)->create($attributes);
}
/**
* @param int $productId
* @param array $inventoryConfig
*
* @return void
*/
private function createInventory(int $productId, array $inventoryConfig = []): void
{
$I = $this;
$I->have(ProductInventory::class, array_merge($inventoryConfig, [
'product_id' => $productId,
'inventory_source_id' => 1,
'qty' => random_int(100, 666),
]));
}
/**
* @param int $productId
*
* @return void
*/
private function createDownloadableLink(int $productId): void
{
$I = $this;
$link = $I->have(ProductDownloadableLink::class, [
'product_id' => $productId,
]);
@ -353,50 +275,67 @@ class Laravel5Helper extends Laravel5
]);
}
/**
* @param int $productId
* @param array $attributeValues
*
* @return void
*/
private function createAttributeValues(int $productId, array $attributeValues = []): void
{
$I = $this;
$productAttributeValues = [
'sku',
'url_key',
'tax_category_id',
'price',
'cost',
'name',
'new',
'visible_individually',
'featured',
'status',
'guest_checkout',
'short_description',
'description',
'meta_title',
'meta_keywords',
'meta_description',
'weight',
$faker = Factory::create();
$brand = Attribute::query()
->where(['code' => 'brand'])
->first(); // usually 25
if (! AttributeOption::query()
->where(['attribute_id' => $brand->id])
->exists()) {
AttributeOption::create([
'admin_name' => 'Webkul Demo Brand (c) 2020',
'attribute_id' => $brand->id,
]);
}
/** @var array $defaultAttributeValues
* Some defaults that should apply to all generated products.
* By defaults products will be generated as saleable.
* If you do not want this, this defaults can be overriden by $attributeValues.
*/
$defaultAttributeValues = [
'name' => $faker->word,
'description' => $faker->sentence,
'short_description' => $faker->sentence,
'sku' => $faker->word,
'url_key' => $faker->slug,
'status' => true,
'guest_checkout' => true,
'visible_individually' => true,
'special_price_from' => null,
'special_price_to' => null,
'special_price' => null,
'price' => $faker->randomFloat(4, 1, 1000),
'weight' => '1.00', // necessary for shipping
'brand' => AttributeOption::firstWhere('attribute_id', $brand->id)->id,
];
foreach ($productAttributeValues as $attribute) {
$data = ['product_id' => $productId];
$attributeValues = array_merge($defaultAttributeValues, $attributeValues);
if (array_key_exists($attribute, $attributeValues)) {
$fieldName = self::getAttributeFieldName($attribute);
/** @var array $possibleAttributeValues list of the possible attributes a product can have */
$possibleAttributeValues = DB::table('attributes')
->select('id', 'code', 'type')
->get()
->toArray();
if (! array_key_exists($fieldName, $data)) {
$data[$fieldName] = $attributeValues[$attribute];
} else {
$data = [$fieldName => $attributeValues[$attribute]];
}
}
foreach ($possibleAttributeValues as $attributeSet) {
$data = [
'product_id' => $productId,
'attribute_id' => $attributeSet->id,
];
$I->have(ProductAttributeValue::class, $data, $attribute);
$fieldName = self::getAttributeFieldName($attributeSet->type);
$data[$fieldName] = $attributeValues[$attributeSet->code] ?? null;
$I->have(ProductAttributeValue::class, $data);
}
}
}

View File

@ -64,6 +64,10 @@ class ForgotPasswordController extends Controller
->withErrors([
'email' => trans($response),
]);
} catch (\Swift_RfcComplianceException $e) {
session()->flash('success', trans('customer::app.forget_password.reset_link_sent'));
return redirect()->back();
} catch (\Exception $e) {
report($e);
session()->flash('error', trans($e->getMessage()));

View File

@ -13,5 +13,8 @@ return [
],
'reviews' => [
'empty' => 'You have not reviewed any of product yet'
],
'forget_password' => [
'reset_link_sent' => 'We have e-mailed your reset password link.'
]
];

View File

@ -5,282 +5,13 @@
use Faker\Generator as Faker;
use Webkul\Product\Models\Product;
use Webkul\Product\Models\ProductAttributeValue;
use Webkul\Attribute\Models\AttributeOption;
$factory->defineAs(ProductAttributeValue::class, 'sku', function (Faker $faker) {
$factory->define(ProductAttributeValue::class, function (Faker $faker) {
return [
'product_id' => function () {
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'text_value' => $faker->uuid,
'attribute_id' => 1,
'locale' => 'en',
'channel' => 'default',
];
});
$factory->defineAs(ProductAttributeValue::class, 'name', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'locale' => 'en', //$faker->languageCode,
'channel' => 'default',
'text_value' => $faker->words(2, true),
'attribute_id' => 2,
];
});
$factory->defineAs(ProductAttributeValue::class, 'url_key', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'text_value' => $faker->unique()->slug,
'attribute_id' => 3,
];
});
$factory->defineAs(ProductAttributeValue::class, 'tax_category_id', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'channel' => 'default',
'integer_value' => null,
'attribute_id' => 4,
];
});
$factory->defineAs(ProductAttributeValue::class, 'new', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'boolean_value' => 1,
'attribute_id' => 5,
];
});
$factory->defineAs(ProductAttributeValue::class, 'featured', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'boolean_value' => 1,
'attribute_id' => 6,
];
});
$factory->defineAs(ProductAttributeValue::class, 'visible_individually', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'boolean_value' => 1,
'attribute_id' => 7,
];
});
$factory->defineAs(ProductAttributeValue::class, 'status', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'boolean_value' => 1,
'attribute_id' => 8,
];
});
$factory->defineAs(ProductAttributeValue::class, 'short_description', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'locale' => 'en', //$faker->languageCode,
'channel' => 'default',
'text_value' => $faker->sentence,
'attribute_id' => 9,
];
});
$factory->defineAs(ProductAttributeValue::class, 'description', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'locale' => 'en', //$faker->languageCode,
'channel' => 'default',
'text_value' => $faker->sentences(3, true),
'attribute_id' => 10,
];
});
$factory->defineAs(ProductAttributeValue::class, 'price', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'float_value' => $faker->randomFloat(4, 0, 1000),
'attribute_id' => 11,
];
});
$factory->defineAs(ProductAttributeValue::class, 'cost', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'channel' => 'default',
'float_value' => $faker->randomFloat(4, 0, 10),
'attribute_id' => 12,
];
});
$factory->defineAs(ProductAttributeValue::class, 'special_price', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'float_value' => $faker->randomFloat(4, 0, 100),
'attribute_id' => 13,
];
});
$factory->defineAs(ProductAttributeValue::class, 'special_price_from', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'channel' => 'default',
'date_value' => $faker->dateTimeBetween('-5 days', 'now', 'Europe/Berlin'),
'attribute_id' => 14,
];
});
$factory->defineAs(ProductAttributeValue::class, 'special_price_to', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'channel' => 'default',
'date_value' => $faker->dateTimeBetween('now', '+ 5 days', 'Europe/Berlin'),
'attribute_id' => 15,
];
});
$factory->defineAs(ProductAttributeValue::class, 'meta_title', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'locale' => 'en', //$faker->languageCode,
'channel' => 'default',
'text_value' => $faker->words(2, true),
'attribute_id' => 16,
];
});
$factory->defineAs(ProductAttributeValue::class, 'meta_keywords', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'locale' => 'en', //$faker->languageCode,
'channel' => 'default',
'text_value' => $faker->words(5, true),
'attribute_id' => 17,
];
});
$factory->defineAs(ProductAttributeValue::class, 'meta_description', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'locale' => 'en', //$faker->languageCode,
'channel' => 'default',
'text_value' => $faker->sentence,
'attribute_id' => 18,
];
});
$factory->defineAs(ProductAttributeValue::class, 'width', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'integer_value' => $faker->numberBetween(1, 50),
'attribute_id' => 19,
];
});
$factory->defineAs(ProductAttributeValue::class, 'height', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'integer_value' => $faker->numberBetween(1, 50),
'attribute_id' => 20,
];
});
$factory->defineAs(ProductAttributeValue::class, 'depth', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'integer_value' => $faker->numberBetween(1, 50),
'attribute_id' => 21,
];
});
$factory->defineAs(ProductAttributeValue::class, 'weight', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'integer_value' => $faker->numberBetween(1, 50),
'attribute_id' => 22,
];
});
$factory->defineAs(ProductAttributeValue::class, 'color', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'integer_value' => $faker->numberBetween(1, 5),
'attribute_id' => 23,
];
});
$factory->defineAs(ProductAttributeValue::class, 'size', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'integer_value' => $faker->numberBetween(1, 5),
'attribute_id' => 24,
];
});
$factory->defineAs(ProductAttributeValue::class, 'brand', function (Faker $faker) {
return [
'product_id' => function () {
return factory(Product::class)->create()->id;
},
'attribute_id' => 25,
'integer_value' => function () {
return factory(AttributeOption::class)->create()->id;
},
];
});
$factory->defineAs(ProductAttributeValue::class, 'guest_checkout', function ( Faker $faker) {
return [
'product_id' => function() {
return factory(Product::class)->create()->id;
},
'boolean_value' => 1,
'attribute_id' => 26,
];
});

View File

@ -9,7 +9,7 @@ use Webkul\Product\Models\ProductInventory;
$factory->define(ProductInventory::class, function (Faker $faker) {
return [
'qty' => $faker->numberBetween(1, 20),
'qty' => $faker->numberBetween(100, 200),
'product_id' => function () {
return factory(Product::class)->create()->id;
},

View File

@ -100,4 +100,34 @@ class BundleOption extends AbstractProduct
return $products;
}
/**
* Get formed data from bundle option product
*
* @return array
*/
public function getProductOptions($product)
{
$products = [];
$products[$product->id] = [
'id' => $product->id,
'qty' => $product->qty,
'price' => $product->product->getTypeInstance()->getProductPrices(),
'name' => $product->product->name,
'product_id' => $product->product_id,
'is_default' => $product->is_default,
'sort_order' => $product->sort_order,
];
usort ($products, function($a, $b) {
if ($a['sort_order'] == $b['sort_order']) {
return 0;
}
return ($a['sort_order'] < $b['sort_order']) ? -1 : 1;
});
return $products;
}
}

View File

@ -84,7 +84,7 @@ class Toolbar extends AbstractProduct
if (isset($params['sort']) && $key == $params['sort'] . '-' . $params['order']) {
return true;
} elseif (! isset($params['sort']) && $key == 'created_at-desc') {
} elseif (! isset($params['sort']) && $key == 'created_at-asc') {
return true;
}

View File

@ -113,6 +113,11 @@ abstract class AbstractType
*/
protected $isChildrenCalculated = false;
/**
* product options
*/
protected $productOptions = [];
/**
* Create a new product type instance.
*
@ -226,10 +231,12 @@ abstract class AbstractType
$route = request()->route() ? request()->route()->getName() : "";
if ($route != 'admin.catalog.products.massupdate') {
if (isset($data['categories'])) {
$product->categories()->sync($data['categories']);
if (! isset($data['categories'])) {
$data['categories'] = [];
}
$product->categories()->sync($data['categories']);
$product->up_sells()->sync($data['up_sell'] ?? []);
$product->cross_sells()->sync($data['cross_sell'] ?? []);
@ -692,4 +699,10 @@ abstract class AbstractType
$item->save();
}
//get product options
public function getProductOptions()
{
return $this->productOptions;
}
}

View File

@ -69,6 +69,11 @@ class Bundle extends AbstractType
*/
protected $isChildrenCalculated = true;
/**
* Product Options
*/
protected $productOptions = [];
/**
* Create a new product type instance.
*
@ -633,4 +638,15 @@ class Bundle extends AbstractType
$item->save();
}
/**
* get product options
*/
public function getProductOptions($product = "")
{
$bundleOption = app('Webkul\Product\Helpers\BundleOption');
$options = $bundleOption->getProductOptions($product);
return $options;
}
}

View File

@ -49,6 +49,11 @@ class Configurable extends AbstractType
*/
protected $hasVariants = true;
/**
* product options
*/
protected $productOptions = [];
/**
* @param array $data
* @return \Webkul\Product\Contracts\Product
@ -546,4 +551,55 @@ class Configurable extends AbstractType
$item->save();
}
//product options
public function getProductOptions($product = "")
{
$configurableOption = app('Webkul\Product\Helpers\ConfigurableOption');
$options = $configurableOption->getConfigurationConfig($product);
return $options;
}
/**
* @param int $qty
* @return bool
*/
public function haveSufficientQuantity($qty)
{
$backorders = core()->getConfigData('catalog.inventory.stock_options.backorders');
return $qty <= $this->totalQuantity() ? true : $backorders;
}
/**
* @return int
*/
public function totalQuantity()
{
$total = 0;
$channelInventorySourceIds = core()->getCurrentChannel()
->inventory_sources()
->where('status', 1)
->pluck('id');
foreach ($this->product->variants as $variant) {
foreach ($variant->inventories as $inventory) {
if (is_numeric($index = $channelInventorySourceIds->search($inventory->inventory_source_id))) {
$total += $inventory->qty;
}
}
$orderedInventory = $variant->ordered_inventories()
->where('channel_id', core()->getCurrentChannel()->id)
->first();
if ($orderedInventory) {
$total -= $orderedInventory->qty;
}
}
return $total;
}
}

View File

@ -55,6 +55,11 @@ class Downloadable extends AbstractType
*/
protected $isStockable = false;
/**
* getProductOptions
*/
protected $getProductOptions = [];
/**
* Create a new product type instance.
*

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

View File

@ -1,4 +1,4 @@
{
"/js/shop.js": "/js/shop.js?id=6bb928c2e527b045a56b",
"/css/shop.css": "/css/shop.css?id=ccf417b825955d8bd301"
"/css/shop.css": "/css/shop.css?id=d1c42d10589004fac3f8"
}

View File

@ -26,16 +26,21 @@ return [
'name' => 'shop::app.layouts.wishlist',
'route' =>'customer.wishlist.index',
'sort' => 4,
], [
'key' => 'account.compare',
'name' => 'velocity::app.customer.compare.text',
'route' =>'velocity.customer.product.compare',
'sort' => 5,
], [
'key' => 'account.orders',
'name' => 'shop::app.layouts.orders',
'route' =>'customer.orders.index',
'sort' => 5,
'sort' => 6,
], [
'key' => 'account.downloadables',
'name' => 'shop::app.layouts.downloadable-products',
'route' =>'customer.downloadable_products.index',
'sort' => 6,
'sort' => 7,
]
];

View File

@ -785,6 +785,7 @@ section.slider-block {
border-bottom-right-radius: 0px;
padding-left: 12px;
font-size: 14px;
-webkit-appearance: none;
}
.search-icon-wrapper {
@ -794,11 +795,13 @@ section.slider-block {
border: 2px solid $border-color;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
margin-left: -2px;
button {
background: $btn-background-color;
border: 0;
padding: 3px 5px;
margin: 0px;
}
}
}
@ -3832,6 +3835,7 @@ section.review {
border-radius: 2px;
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
-webkit-appearance: none;
}
.search-icon-wrapper {
@ -3840,6 +3844,7 @@ section.review {
border-radius: 2px;
border-top-right-radius: 0px;
border-bottom-right-radius: 0px;
margin-left: -2px;
}
}
}

View File

@ -411,6 +411,7 @@ return [
'your-customization' => 'التخصيص الخاص بك',
'total-amount' => 'المبلغ الإجمالي',
'none' => 'لا شيء',
'available' => 'Available'
],
// 'reviews' => [

View File

@ -410,7 +410,8 @@ return [
'choose-selection' => 'Choose a selection',
'your-customization' => 'Your Customization',
'total-amount' => 'Total Amount',
'none' => 'None'
'none' => 'None',
'available' => 'Available'
],
// 'reviews' => [

View File

@ -381,7 +381,8 @@ return [
'out-of-stock' => 'Sin estoc',
'view-all' => 'Ver todo',
'select-above-options' => 'Primero selecciona las opciones de arriba.',
'less-quantity' => 'La cantidad no debe ser inferior a uno.'
'less-quantity' => 'La cantidad no debe ser inferior a uno.',
'available' => 'Available'
],
// 'reviews' => [

View File

@ -410,7 +410,8 @@ return [
'choose-selection' => 'انتخابی را انتخاب کنید',
'your-customization' => 'شخصی سازی شما',
'total-amount' => 'مقدار کل',
'none' => 'هیچ یک'
'none' => 'هیچ یک',
'available' => 'Available'
],
// 'reviews' => [

View File

@ -415,7 +415,8 @@ return [
'choose-selection' => 'Kies een selectie',
'your-customization' => 'Uw maatwerk',
'total-amount' => 'Totale hoeveelheid',
'none' => 'Geen'
'none' => 'Geen',
'available' => 'Available'
],
// 'reviews' => [

View File

@ -1,6 +1,10 @@
<?php
return [
'invalid_vat_format' => 'The given vat id has a wrong format',
'security-warning' => 'Suspicious activity found!!!',
'nothing-to-delete' => 'Nothing to delete',
'layouts' => [
'my-account' => 'Minha Conta',
'profile' => 'Perfil',
@ -113,8 +117,9 @@ return [
'verification-not-sent' => 'Erro! Problema ao enviar e-mail de verificação, tente novamente mais tarde',
'verification-sent' => 'E-mail de verificação enviado',
'verified' => 'Sua Conta Foi Verificada, Tente Entrar Agora',
'verify-failed' => 'Não podemos verificar sua conta de e-mail',
'verify-failed' => 'Não podemos verificar sua conta de e-mail.',
'dont-have-account' => 'Você não tem conta conosco',
'customer-registration' => 'Cliente Cadastrado com Sucesso'
],
'login-text' => [
@ -245,13 +250,14 @@ return [
'date' => 'Data',
'status' => 'Status',
'total' => 'Total',
'processing' => 'Processing',
'completed' => 'Completed',
'canceled' => 'Canceled',
'closed' => 'Closed',
'pending' => 'Pending',
'pending-payment' => 'Pending Payment',
'fraud' => 'Fraud'
'order_number' => 'Número do Pedido',
'processing' => 'Precessando',
'completed' => 'Completo',
'canceled' => 'Cancelado',
'closed' => 'Fechado',
'pending' => 'Pendente',
'pending-payment' => 'Pagamento Pendente',
'fraud' => 'Fraude'
],
'view' => [
@ -304,7 +310,7 @@ return [
],
'wishlist' => [
'page-title' => 'Customer - Wishlist',
'page-title' => 'Lista de Desejos',
'title' => 'Lista de Desejos',
'deleteall' => 'Excluir Tudo',
'moveall' => 'Adicionar todos ao Carrinho',
@ -313,6 +319,7 @@ return [
'add' => 'Item adicionado com sucesso a Lista de Desejos',
'remove' => 'Item removido com sucesso da Lista de Desejos',
'moved' => 'Item movido com sucesso para Lista de Desejos',
'option-missing' => 'As opções do produto estão ausentes, portanto, o item não pode ser movido para a lista de desejos.',
'move-error' => 'Item não pode ser movido para Lista de Desejos, por favor, tente novamente mais tarde',
'success' => 'Item adicionado com sucesso a Lista de Desejos',
'failure' => 'Item não pode ser adicionado à Lista de Desejos, por favor, tente novamente mais tarde',
@ -391,7 +398,8 @@ return [
'choose-selection' => 'Escolha uma seleção',
'your-customization' => 'Sua personalização',
'total-amount' => 'Valor total',
'none' => 'Nenhum'
'none' => 'Nenhum',
'available' => 'Available'
],
// 'reviews' => [
@ -408,8 +416,9 @@ return [
'integrity' => [
'missing_fields' =>'Violação de integridade do sistema de carrinho, alguns campos obrigatórios ausentes',
'missing_options' =>'Violação de Integridade do Sistema de Carrinho, Faltam Opções para o Produto Configurável',
'missing_links' => 'Downloadable links are missing for this product.',
'qty_missing' => 'Atleast one product should have more than 1 quantity.'
'missing_links' => 'Faltam links para download para este produto.',
'qty_missing' => 'Pelo menos um produto deve ter mais de 1 quantidade.',
'qty_impossible' => 'Não é possível adicionar mais do que um desse produto ao carrinho.'
],
'create-error' => 'Encontrou algum problema ao fazer a instância do carrinho',
@ -438,11 +447,11 @@ return [
'success-remove' => 'Item foi removido com sucesso do carrinho',
'error-add' => 'Item não pode ser adicionado ao carrinho, por favor, tente novamente mais tarde',
],
'quantity-error' => 'Quantidade solicitada não está disponível',
'cart-subtotal' => 'Subtotal do carrinho',
'cart-remove-action' => 'Você realmente quer fazer isso ?',
'partial-cart-update' => 'Only some of the product(s) were updated'
'partial-cart-update' => 'Only some of the product(s) were updated',
'link-missing' => ''
],
'onepage' => [
@ -466,7 +475,7 @@ return [
'country' => 'País',
'order-summary' => 'Resumo do Pedido',
'shipping-address' => 'Endereço de Entrega',
'use_for_shipping' => 'Enviar para esse endereçõ',
'use_for_shipping' => 'Enviar para esse endereço',
'continue' => 'Continuar',
'shipping-method' => 'Selecione o Método de Entrega',
'payment-methods' => 'Selecione o Método de Pagamento',
@ -479,7 +488,9 @@ return [
'contact' => 'Contato',
'place-order' => 'Enviar Pedido',
'new-address' => 'Add Novo Endereço',
'save_as_address' => 'Salvar Endereço'
'save_as_address' => 'Salvar Endereço',
'apply-coupon' => 'Aplicar Cupom',
'enter-coupon-code' => 'Digite aqui o seu Cupom'
],
'total' => [
@ -488,8 +499,17 @@ return [
'grand-total' => 'Total',
'delivery-charges' => 'Taxas de Entrega',
'tax' => 'Imposto',
'discount' => 'Discount',
'price' => 'preço'
'discount' => 'Desconto',
'price' => 'preço',
'disc-amount' => 'Valor descontado',
'new-grand-total' => 'Novo Total',
'coupon' => 'Cupom',
'coupon-applied' => 'Cupom Aplicado',
'remove-coupon' => 'Remover Cupom',
'cannot-apply-coupon' => 'Não foi possível aplicar esse Cupom',
'invalid-coupon' => 'Código do Cupom é inválido.',
'success-coupon' => 'Cupom aplicado com sucesso.',
'coupon-apply-issue' => 'Não foi possível aplicar esse Cupom'
],
'success' => [
@ -505,6 +525,7 @@ return [
'subject' => 'Confirmação de Novo Pedido',
'heading' => 'Confirmação de Pedido!',
'dear' => 'Caro :customer_name',
'dear-admin' => 'Caro :admin_name',
'greeting' => 'Obrigado pelo seu Pedido :order_id realizado em :created_at',
'summary' => 'Resumo do Pedido',
'shipping-address' => 'Endereço de Entrega',
@ -521,7 +542,27 @@ return [
'grand-total' => 'Total',
'final-summary' => 'Obrigado por mostrar o seu interesse em nossa loja nós lhe enviaremos o número de rastreamento assim que for despachado',
'help' => 'Se você precisar de algum tipo de ajuda, por favor entre em contato conosco :support_email',
'thanks' => 'Muito Obrigado!'
'thanks' => 'Muito Obrigado!',
'cancel' => [
'subject' => 'Confirmação de Cancelamento de Pedido',
'heading' => 'Pedido Cancelado',
'dear' => 'Caro :customer_name',
'greeting' => 'Seu Pedido com o ID #:order_id finalizado em :created_at foi cancelado',
'summary' => 'Resumo do Pedido',
'shipping-address' => 'Endereço de Entrega',
'billing-address' => 'Endereço de Faturamento',
'contact' => 'Contato',
'shipping' => 'Método de Envio',
'payment' => 'Método de Pagamento',
'subtotal' => 'Subtotal',
'shipping-handling' => 'Entrega & Manuseio',
'tax' => 'Taxa',
'discount' => 'Desconto',
'grand-total' => 'Total',
'final-summary' => 'Obrigado por mostrar interesse em nosa Loja',
'help' => 'Caso precise de qualquer tipo de ajuda entre em contato conosco :support_email',
'thanks' => 'Obrigado!',
]
],
'invoice' => [
@ -547,11 +588,49 @@ return [
],
'forget-password' => [
'subject' => 'Recuperação de Senha',
'dear' => 'Caro :name',
'info' => 'Você está recebendo este e-mail porque recebemos uma solicitação de redefinição de senha para sua conta',
'reset-password' => 'Redefinir Senha',
'final-summary' => 'Se você não solicitou uma redefinição de senha, nenhuma ação adicional é necessária',
'thanks' => 'Muito Obrigado!'
'thanks' => 'Obrigado!'
],
'customer' => [
'new' => [
'dear' => 'Caro :customer_name',
'username-email' => 'Nome de usuário/Email',
'subject' => 'Nova Conta',
'password' => 'Senha',
'summary' => 'Sua conta foi criada.
Abaixo está suas informaços: ',
'thanks' => 'Obrigado!',
],
'registration' => [
'subject' => 'Novo Cliente',
'customer-registration' => 'Cliente cadastrado com Sucesso',
'dear' => 'Caro :customer_name',
'greeting' => 'Bem vindo e obrigado por se cadastrar conosco!',
'summary' => 'Sua conta foi criada com sucesso e agora você pode entrar utilizando seu endereço de email e senha. Ao fazer login, você poderá acessar outros serviços, incluindo a revisão de pedidos anteriores, listas de desejos e a edição das informações da sua conta..',
'thanks' => 'Obrigado!',
],
'verification' => [
'heading' => config('app.name') . ' - Verificação de Email',
'subject' => 'Verificação de Email',
'verify' => 'Confirme sua conta',
'summary' => 'Esse email é para confirmar que esse endereço de e-mail é válido e pertence a você.
Por favor, clique no botão Confirme sua conta abaixo para verificar sua conta. '
],
'subscription' => [
'subject' => 'Email de Inscrição',
'greeting' => ' Bem vindo a ' . config('app.name') . ' - Incrição de Email',
'unsubscribe' => 'Unsubscribe',
'summary' => 'Obrigado por me colocar na sua caixa de entrada. Já faz um tempo desde que você leu ' . config('app.name') . ' e-mail e não queremos sobrecarregar sua caixa de entrada. Se você ainda não deseja receber
as últimas notícias de email marketing e, com certeza, clique no botão abaixo.'
]
]
],

View File

@ -289,6 +289,18 @@
this.disable_button = true;
if (this.allAddress.length > 0) {
let address = this.allAddress.forEach(address => {
if (address.id == this.address.billing.address_id) {
this.address.billing.address1 = [address.address1];
}
if (address.id == this.address.shipping.address_id) {
this.address.shipping.address1 = [address.address1];
}
});
}
this.$http.post("{{ route('shop.checkout.save-address') }}", this.address)
.then(function(response) {
this_this.disable_button = false;

View File

@ -0,0 +1,29 @@
@extends('shop::layouts.master')
@include('shop::guest.compare.compare-products')
@section('page_title')
{{ __('velocity::app.customer.compare.compare_similar_items') }}
@endsection
@section('content-wrapper')
<div class="account-content">
@include('shop::customers.account.partials.sidemenu')
<div class="account-layout">
{!! view_render_event('bagisto.shop.customers.account.comparison.list.before') !!}
<div class="account-items-list">
<div class="account-table-content">
<compare-product></compare-product>
</div>
</div>
{!! view_render_event('bagisto.shop.customers.account.comparison.list.after') !!}
</div>
</div>
@endsection

View File

@ -91,9 +91,12 @@
<div class="container">
<div class="header">
<div class="image">
<img class="logo" src="{{ Storage::url(core()->getConfigData('sales.orderSettings.invoice_slip_design.logo')) }}"/>
</div>
@if (core()->getConfigData('sales.orderSettings.invoice_slip_design.logo'))
<div class="image">
<img class="logo" src="{{ Storage::url(core()->getConfigData('sales.orderSettings.invoice_slip_design.logo')) }}"/>
</div>
@endif
<div class="address">
<p>
<b> {{ core()->getConfigData('sales.orderSettings.invoice_slip_design.address') }} </b>

View File

@ -0,0 +1,295 @@
@php
$attributeRepository = app('\Webkul\Attribute\Repositories\AttributeRepository');
$comparableAttributes = $attributeRepository->findByField('is_comparable', 1);
@endphp
@push('css')
<style>
body {
overflow-x: hidden;
}
.comparison-component {
width: 100%;
padding-top: 20px;
}
.comparison-component > h1 {
display: inline-block;
}
td {
padding: 15px;
min-width: 250px;
max-width: 250px;
line-height: 30px;
vertical-align: top;
word-break: break-word;
}
.icon.remove-product {
top: 15px;
float: right;
cursor: pointer;
position: relative;
background-color: black;
}
.action > div {
display: inline-block;
}
</style>
@endpush
@push('scripts')
<script type="text/x-template" id="compare-product-template">
<section class="comparison-component">
<h1>
{{ __('velocity::app.customer.compare.compare_similar_items') }}
</h1>
<button
v-if="products.length > 0"
class="btn btn-primary btn-md pull-right"
@click="removeProductCompare('all')">
{{ __('shop::app.customer.account.wishlist.deleteall') }}
</button>
{!! view_render_event('bagisto.shop.customers.account.compare.view.before') !!}
<table class="compare-products">
<template v-if="isProductListLoaded && products.length > 0">
@php
$comparableAttributes = $comparableAttributes->toArray();
array_splice($comparableAttributes, 1, 0, [[
'code' => 'image',
'admin_name' => 'Product Image'
]]);
array_splice($comparableAttributes, 2, 0, [[
'code' => 'addToCartHtml',
'admin_name' => 'Actions'
]]);
@endphp
@foreach ($comparableAttributes as $attribute)
<tr>
<td>
<span class="fs16">{{ $attribute['admin_name'] }}</span>
</td>
<td :key="`title-${index}`" v-for="(product, index) in products">
@switch ($attribute['code'])
@case('name')
<a :href="`${baseUrl}/${product.url_key}`" class="unset remove-decoration active-hover">
<h3 class="fw6 fs18" v-text="product['{{ $attribute['code'] }}']"></h3>
</a>
@break
@case('image')
<a :href="`${baseUrl}/${product.url_key}`" class="unset">
<img
class="image-wrapper"
:src="product['{{ $attribute['code'] }}']"
:onerror="`this.src='${baseUrl}/vendor/webkul/ui/assets/images/product/large-product-placeholder.png'`" />
</a>
@break
@case('price')
<span v-html="product['priceHTML']"></span>
@break
@case('addToCartHtml')
<div class="action">
<div v-html="product.defaultAddToCart"></div>
<span class="icon white-cross-sm-icon remove-product" @click="removeProductCompare(product.id)"></span>
</div>
@break
@case('color')
<span v-html="product.color_label" class="fs16"></span>
@break
@case('size')
<span v-html="product.size_label" class="fs16"></span>
@break
@case('description')
<span v-html="product.description"></span>
@break
@default
@switch ($attribute['type'])
@case('boolean')
<span
v-text="product.product['{{ $attribute['code'] }}']
? '{{ __('velocity::app.shop.general.yes') }}'
: '{{ __('velocity::app.shop.general.no') }}'"
></span>
@break;
@default
<span v-html="product['{{ $attribute['code'] }}'] ? product['{{ $attribute['code'] }}'] : product.product['{{ $attribute['code'] }}'] ? product.product['{{ $attribute['code'] }}'] : '__'" class="fs16"></span>
@break;
@endswitch
@break
@endswitch
</td>
</tr>
@endforeach
</template>
<span v-else-if="isProductListLoaded && products.length == 0">
{{ __('velocity::app.customer.compare.empty-text') }}
</span>
</table>
{!! view_render_event('bagisto.shop.customers.account.compare.view.after') !!}
</section>
</script>
<script>
Vue.component('compare-product', {
template: '#compare-product-template',
data: function () {
return {
'products': [],
'isProductListLoaded': false,
'baseUrl': "{{ url()->to('/') }}",
'isCustomer': '{{ auth()->guard('customer')->user() ? "true" : "false" }}' == "true",
}
},
mounted: function () {
this.getComparedProducts();
},
methods: {
'getComparedProducts': function () {
let items = '';
let url = `${this.baseUrl}/${this.isCustomer ? 'comparison' : 'detailed-products'}`;
let data = {
params: {'data': true}
}
if (! this.isCustomer) {
items = this.getStorageValue('compared_product');
items = items ? items.join('&') : '';
data = {
params: {
items
}
};
}
if (this.isCustomer || (! this.isCustomer && items != "")) {
this.$http.get(url, data)
.then(response => {
this.isProductListLoaded = true;
if (response.data.products.length > 2) {
$('.comparison-component').css('overflow-x', 'scroll');
}
this.products = response.data.products;
})
.catch(error => {
this.isProductListLoaded = true;
console.log("{{ __('velocity::app.error.something_went_wrong') }}");
});
} else {
this.isProductListLoaded = true;
}
},
'removeProductCompare': function (productId) {
if (this.isCustomer) {
this.$http.delete(`${this.baseUrl}/comparison?productId=${productId}`)
.then(response => {
if (productId == 'all') {
this.$set(this, 'products', this.products.filter(product => false));
} else {
this.$set(this, 'products', this.products.filter(product => product.id != productId));
}
// window.showAlert(`alert-${response.data.status}`, response.data.label, response.data.message);
})
.catch(error => {
console.log("{{ __('velocity::app.error.something_went_wrong') }}");
});
} else {
let existingItems = this.getStorageValue('compared_product');
if (productId == "all") {
updatedItems = [];
this.$set(this, 'products', []);
} else {
updatedItems = existingItems.filter(item => item != productId);
this.$set(this, 'products', this.products.filter(product => product.id != productId));
}
this.setStorageValue('compared_product', updatedItems);
// window.showAlert(
// `alert-success`,
// "{{ __('velocity::app.shop.general.alert.success') }}",
// `${this.__('customer.compare.removed')}`
// );
}
},
'getDynamicHTML': function (input) {
var _staticRenderFns;
const { render, staticRenderFns } = Vue.compile(input);
if (this.$options.staticRenderFns.length > 0) {
_staticRenderFns = this.$options.staticRenderFns;
} else {
_staticRenderFns = this.$options.staticRenderFns = staticRenderFns;
}
try {
var output = render.call(this, this.$createElement);
} catch (exception) {
console.log(this.__('error.something_went_wrong'));
}
this.$options.staticRenderFns = _staticRenderFns;
return output;
},
'isMobile': function () {
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
return true
} else {
return false
}
},
'getStorageValue': function (key) {
let value = window.localStorage.getItem(key);
if (value) {
value = JSON.parse(value);
}
return value;
},
'setStorageValue': function (key, value) {
window.localStorage.setItem(key, JSON.stringify(value));
return true;
},
}
});
</script>
@endpush

View File

@ -1,3 +1,11 @@
<script>
window.location.href = window.location.href.replace('/comparison', '');
</script>
@extends('shop::layouts.master')
@include('shop::guest.compare.compare-products')
@section('page_title')
{{ __('velocity::app.customer.compare.compare_similar_items') }}
@endsection
@section('content-wrapper')
<compare-product></compare-product>
@endsection

View File

@ -42,6 +42,26 @@
<ul class="right-content-menu">
{!! view_render_event('bagisto.shop.layout.header.comppare-item.before') !!}
<li class="compare-dropdown-container">
<a
@auth('customer')
href="{{ route('velocity.customer.product.compare') }}"
@endauth
@guest('customer')
href="{{ route('velocity.product.compare') }}"
@endguest
style="color: #242424;"
>
<span class="name">{{ __('velocity::app.customer.compare.text') }}</span>
</a>
</li>
{!! view_render_event('bagisto.shop.layout.header.compare-item.after') !!}
{!! view_render_event('bagisto.shop.layout.header.currency-item.before') !!}
@if (core()->getCurrentChannel()->currencies->count() > 1)

View File

@ -8,5 +8,7 @@
@include('shop::products.wishlist')
@include('shop::products.compare')
@include('shop::products.compare', [
'productId' => $product->id
])
</div>

View File

@ -1,11 +1,101 @@
{{-- @inject ('wishListHelper', 'Webkul\Customer\Helpers\Wishlist')
<compare-component product-id="{{ $productId }}"></compare-component>
@auth('customer')
{!! view_render_event('bagisto.shop.products.wishlist.before') !!}
@push('scripts')
<a @if ($wishListHelper->getWishlistProduct($product)) class="add-to-wishlist already" @else class="add-to-wishlist" @endif href="{{ route('customer.wishlist.add', $product->product_id) }}" id="wishlist-changer">
<span class="icon wishlist-icon"></span>
</a>
<script type="text/x-template" id="compare-component-template">
<a class="unset compare-icon text-right" @click="addProductToCompare" style="cursor: pointer">
<img src="{{ asset('themes/default/assets/images/compare_arrows.png') }}" />
</a>
</script>
{!! view_render_event('bagisto.shop.products.wishlist.after') !!}
@endauth --}}
<script>
Vue.component('compare-component', {
props: ['productId'],
template: '#compare-component-template',
data: function () {
return {
'baseUrl': "{{ url()->to('/') }}",
'customer': '{{ auth()->guard('customer')->user() ? "true" : "false" }}' == "true",
}
},
methods: {
'addProductToCompare': function () {
if (this.customer == "true" || this.customer == true) {
this.$http.put(
`${this.baseUrl}/comparison`, {
productId: this.productId,
}
).then(response => {
window.flashMessages = [{
'type': `alert-${response.data.status}`,
'message': response.data.message
}];
this.$root.addFlashMessages()
}).catch(error => {
window.flashMessages = [{
'type': `alert-danger`,
'message': "{{ __('velocity::app.error.something_went_wrong') }}"
}];
this.$root.addFlashMessages()
});
} else {
let updatedItems = [this.productId];
let existingItems = this.getStorageValue('compared_product');
if (existingItems) {
if (existingItems.indexOf(this.productId) == -1) {
updatedItems = existingItems.concat(updatedItems);
this.setStorageValue('compared_product', updatedItems);
window.flashMessages = [{
'type': `alert-success`,
'message': "{{ __('velocity::app.customer.compare.added') }}"
}];
this.$root.addFlashMessages()
} else {
window.flashMessages = [{
'type': `alert-success`,
'message': "{{ __('velocity::app.customer.compare.already_added') }}"
}];
this.$root.addFlashMessages()
}
} else {
this.setStorageValue('compared_product', updatedItems);
window.flashMessages = [{
'type': `alert-success`,
'message': "{{ __('velocity::app.customer.compare.added') }}"
}];
this.$root.addFlashMessages()
}
}
},
'getStorageValue': function (key) {
let value = window.localStorage.getItem(key);
if (value) {
value = JSON.parse(value);
}
return value;
},
'setStorageValue': function (key, value) {
window.localStorage.setItem(key, JSON.stringify(value));
return true;
},
}
});
</script>
@endpush

View File

@ -163,7 +163,7 @@
data: function() {
let maxPrice = '{{ core()->convertPrice($productFlatRepository->getCategoryProductMaximumPrice($category)) }}';
maxPrice = (parseInt(maxPrice) !== 0) ? parseInt(maxPrice) : 500;
maxPrice = maxPrice ? ((parseInt(maxPrice) !== 0 || maxPrice) ? parseInt(maxPrice) : 500) : 500;
return {
appliedFilters: [],

View File

@ -1,7 +1,13 @@
{!! view_render_event('bagisto.shop.products.view.stock.before', ['product' => $product]) !!}
<div class="stock-status {{! $product->haveSufficientQuantity(1) ? '' : 'active' }}">
{{ $product->haveSufficientQuantity(1) ? __('shop::app.products.in-stock') : __('shop::app.products.out-of-stock') }}
@if ( $product->haveSufficientQuantity(1) === true )
{{ __('shop::app.products.in-stock') }}
@elseif ( $product->haveSufficientQuantity(1) > 0 )
{{ __('shop::app.products.available') }}
@else
{{ __('shop::app.products.out-of-stock') }}
@endif
</div>
{!! view_render_event('bagisto.shop.products.view.stock.after', ['product' => $product]) !!}

View File

@ -3,7 +3,15 @@
@auth('customer')
{!! view_render_event('bagisto.shop.products.wishlist.before') !!}
<a @if ($wishListHelper->getWishlistProduct($product)) class="add-to-wishlist already" @else class="add-to-wishlist" @endif href="{{ route('customer.wishlist.add', $product->product_id) }}" id="wishlist-changer">
<a
@if ($wishListHelper->getWishlistProduct($product))
class="add-to-wishlist already"
@else
class="add-to-wishlist"
@endif
id="wishlist-changer"
style="margin-right: 15px;"
href="{{ route('customer.wishlist.add', $product->product_id) }}">
<span class="icon wishlist-icon"></span>
</a>

View File

@ -7,7 +7,8 @@ class Tax
/**
* @var int
*/
public const TAX_PRECISION = 4;
private const TAX_RATE_PRECISION = 4;
private const TAX_AMOUNT_PRECISION = 2;
/**
* Returns an array with tax rates and tax amount
@ -20,7 +21,7 @@ class Tax
$taxes = [];
foreach ($that->items as $item) {
$taxRate = (string) round((float) $item->tax_percent, self::TAX_PRECISION);
$taxRate = (string) round((float) $item->tax_percent, self::TAX_RATE_PRECISION);
if (! array_key_exists($taxRate, $taxes)) {
$taxes[$taxRate] = 0;
@ -29,6 +30,11 @@ class Tax
$taxes[$taxRate] += $asBase ? $item->base_tax_amount : $item->tax_amount;
}
// finally round tax amounts now (to reduce rounding differences)
foreach ($taxes as $taxRate => $taxAmount) {
$taxes[$taxRate] = round($taxAmount, self::TAX_AMOUNT_PRECISION);
}
return $taxes;
}
@ -45,7 +51,7 @@ class Tax
$result = 0;
foreach ($taxes as $taxRate => $taxAmount) {
$result += round($taxAmount, 2);
$result += $taxAmount;
}
return $result;

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/ui.js": "/js/ui.js?id=f4734f49f2e95bf51c83",
"/css/ui.css": "/css/ui.css?id=0895b560bbc19259cee8"
"/js/ui.js": "/js/ui.js?id=5c5ae91d95c2c0668124",
"/css/ui.css": "/css/ui.css?id=b87eb840235219138c2c"
}

View File

@ -67,10 +67,20 @@
var this_this = this;
if(this.multiple) {
if(this.images.length) {
if (this.images.length) {
this.images.forEach(function(image) {
this_this.items.push(image)
this_this.imageCount++;
});
} else if (this.images.length == undefined && typeof this.images == 'object') {
var images = Object.keys(this.images).map(key => {
return this.images[key];
});
images.forEach(function(image) {
this_this.items.push(image)
this_this.imageCount++;
});
} else {

View File

@ -645,8 +645,10 @@ h5 {
display: inline-block;
vertical-align: middle;
margin-left: -34px;
margin-top: 2px;
pointer-events: none;
position: absolute;
left: 70%;
top: 50%;
}
}

View File

@ -49,6 +49,7 @@
height: 36px;
width: 280px;
padding-left: 10px;
-webkit-appearance: none;
}
.contorl:focus {

View File

@ -23,7 +23,7 @@
"bootstrap-sass": "^3.4.1",
"font-awesome": "^4.7.0",
"material-icons": "^0.3.1",
"vee-validate": "2.0.0-rc.26",
"vee-validate": "^2.2.15",
"vue-slider-component": "^3.1.0",
"vue-toast-notification": "0.0.2"
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
{
"/js/velocity.js": "/js/velocity.js?id=973edd4336993fd9b95a",
"/js/velocity.js": "/js/velocity.js?id=08fbd43328947b542230",
"/css/velocity-admin.css": "/css/velocity-admin.css?id=612d35e452446366eef7",
"/css/velocity.css": "/css/velocity.css?id=3e8619277d84a8bde711"
"/css/velocity.css": "/css/velocity.css?id=ff0f7ac77c597ee277cb"
}

View File

@ -252,9 +252,13 @@ class Helper extends Review
if (is_string($path) && is_readable($path)) {
return include $path;
}
} else {
$currentLocale = "en";
return [];
$path = __DIR__ . "/../Resources/lang/$currentLocale/app.php";
return include $path;
}
}
/**
@ -279,7 +283,8 @@ class Helper extends Review
/**
* @param \Webkul\Product\Contracts\Product $product
* @param bool $list
* @param bool $list
* @param array $metaInformation
* @return array
*/
public function formatProduct($product, $list = false, $metaInformation = [])
@ -317,16 +322,15 @@ class Helper extends Review
'shortDescription' => $product->short_description,
'firstReviewText' => trans('velocity::app.products.be-first-review'),
'priceHTML' => view('shop::products.price', ['product' => $product])->render(),
'defaultAddToCart' => view('shop::products.add-buttons', ['product' => $product])->render(),
'addToCartHtml' => view('shop::products.add-to-cart', [
'showCompare' => true,
'product' => $product,
'addWishlistClass' => ! (isset($list) && $list) ? '' : '',
'btnText' => (isset($metaInformation['btnText']) && $metaInformation['btnText'])
? $metaInformation['btnText']
: null,
'moveToCart' => (isset($metaInformation['moveToCart']) && $metaInformation['moveToCart'])
? $metaInformation['moveToCart']
: null,
? $metaInformation['btnText'] : null,
'moveToCart' => (isset($metaInformation['moveToCart']) && $metaInformation['moveToCart'])
? $metaInformation['moveToCart'] : null,
'addToCartBtnClass' => ! (isset($list) && $list) ? 'small-padding' : '',
])->render(),
];
@ -364,6 +368,7 @@ class Helper extends Review
$productMetaDetails['priceHTML'] = $formattedProduct['priceHTML'];
$productMetaDetails['addToCartHtml'] = $formattedProduct['addToCartHtml'];
$productMetaDetails['galleryImages'] = $formattedProduct['galleryImages'];
$productMetaDetails['defaultAddToCart'] = $formattedProduct['defaultAddToCart'];
$product = array_merge($productFlat->toArray(), $productMetaDetails);

View File

@ -120,33 +120,49 @@ class ConfigurationController extends Controller
$saveImage = [];
$saveData = $advertisement;
foreach ($data as $imageId => $image) {
$file = 'images.' . $index . '.' . $imageId;
$dir = 'velocity/images';
if (Str::contains($imageId, 'image_')) {
if (request()->hasFile($file) && $image) {
$filter_index = substr($imageId, 6, 1);
if ( isset($data[$filter_index]) ) {
$size = array_key_last($saveData[$index]);
$saveImage[$size + 1] = request()->file($file)->store($dir);
} else {
$saveImage[substr($imageId, 6, 1)] = request()->file($file)->store($dir);
foreach ($data as $imageId => $image) {
if ($image != "") {
$file = 'images.' . $index . '.' . $imageId;
$dir = 'velocity/images';
if (Str::contains($imageId, 'image_')) {
if (request()->hasFile($file) && $image) {
$filter_index = substr($imageId, 6, 1);
if ( isset($data[$filter_index]) ) {
$size = array_key_last($saveData[$index]);
$saveImage[$size + 1] = request()->file($file)->store($dir);
} else {
$saveImage[substr($imageId, 6, 1)] = request()->file($file)->store($dir);
}
}
} else {
if ( isset($advertisement[$index][$imageId]) && $advertisement[$index][$imageId] && !request()->hasFile($file)) {
$saveImage[$imageId] = $advertisement[$index][$imageId];
unset($advertisement[$index][$imageId]);
}
if (request()->hasFile($file) && isset($advertisement[$index][$imageId])) {
Storage::delete($advertisement[$index][$imageId]);
$saveImage[$imageId] = request()->file($file)->store($dir);
}
}
} else {
if ( isset($advertisement[$index][$imageId]) && $advertisement[$index][$imageId] && !request()->hasFile($file)) {
$saveImage[$imageId] = $advertisement[$index][$imageId];
if ($saveData) {
$subIndex = substr($imageId, -1);
unset($advertisement[$index][$imageId]);
}
if (isset($advertisement[$index][$subIndex])) {
$saveImage[$subIndex] = $advertisement[$index][$subIndex];
if (request()->hasFile($file) && isset($advertisement[$index][$imageId])) {
Storage::delete($advertisement[$index][$imageId]);
$saveImage[$imageId] = request()->file($file)->store($dir);
if (sizeof($advertisement[$index]) == 1) {
unset($advertisement[$index]);
} else {
unset($advertisement[$index][$subIndex]);
}
}
}
}
}

View File

@ -31,14 +31,15 @@ class ComparisonController extends Controller
->get()
->toArray();
foreach ($productCollection as $index => $customerCompare) {
$product = $this->productRepository->find($customerCompare['product_id']);
$formattedProduct = $this->velocityHelper->formatProduct($product);
$items = [];
$productCollection[$index]['image'] = $formattedProduct['image'];
$productCollection[$index]['priceHTML'] = $formattedProduct['priceHTML'];
$productCollection[$index]['addToCartHtml'] = $formattedProduct['addToCartHtml'];
foreach ($productCollection as $index => $customerCompare) {
array_push($items, $customerCompare['id']);
}
$items = implode('&', $items);
$productCollection = $this->velocityHelper->fetchProductCollection($items);
} else {
// for product details
if ($items = request()->get('items')) {

View File

@ -5,6 +5,7 @@ namespace Webkul\Velocity\Http\Controllers\Shop;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Webkul\Velocity\Helpers\Helper;
use Webkul\Product\Helpers\ProductImage;
use Webkul\Product\Repositories\SearchRepository;
@ -85,13 +86,15 @@ class Controller extends BaseController
/**
* Create a new controller instance.
*
* @param \Webkul\Velocity\Helpers\Helper $velocityHelper
* @param \Webkul\Product\Helpers\ProductImage $productImageHelper
* @param \Webkul\Product\Repositories\SearchRepository $searchRepository
* @param \Webkul\Product\Repositories\ProductRepository $productRepository
* @param \Webkul\Category\Repositories\CategoryRepository $categoryRepository
* @param \Webkul\Velocity\Repositories\Product\ProductRepository $velocityProductRepository
* @param \Webkul\Velocity\Helpers\Helper $velocityHelper
* @param \Webkul\Product\Helpers\ProductImage $productImageHelper
* @param \Webkul\Product\Repositories\SearchRepository $searchRepository
* @param \Webkul\Product\Repositories\ProductRepository $productRepository
* @param \Webkul\Category\Repositories\CategoryRepository $categoryRepository
* @param \Webkul\Velocity\Repositories\Product\ProductRepository $velocityProductRepository
* @param \Webkul\Velocity\Repositories\VelocityCustomerCompareProductRepository $compareProductsRepository
* @param \Webkul\Velocity\Repositories\VelocityCustomerCompareProductRepository $compareProductsRepository
*
* @return void
*/
public function __construct(

View File

@ -231,4 +231,26 @@ class ShopController extends Controller
'status' => false
]);
}
public function getCategoryProducts($categoryId)
{
$products = $this->productRepository->getAll($categoryId);
$productItems = $products->items();
if ($productItems) {
$formattedProducts =[];
foreach ($productItems as $product) {
array_push($formattedProducts, $this->velocityHelper->formatProduct($product));
}
$productsArray = $products->toArray();
$productsArray['data'] = $formattedProducts;
}
return response()->json($response ?? [
'products' => $productsArray,
'paginationHTML' => $products->appends(request()->input())->links()->toHtml(),
]);
}
}

View File

@ -34,11 +34,13 @@ Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function
'view' => 'shop::guest.compare.index'
]);
Route::get('/customer/account/comparison', 'ComparisonController@getComparisonList')
->name('velocity.customer.product.compare')
->defaults('_config', [
'view' => 'shop::customers.account.compare.index'
]);
Route::group(['middleware' => ['customer']], function () {
Route::get('/customer/account/comparison', 'ComparisonController@getComparisonList')
->name('velocity.customer.product.compare')
->defaults('_config', [
'view' => 'shop::customers.account.compare.index'
]);
});
Route::put('/comparison', 'ComparisonController@addCompareProduct')
->name('customer.product.add.compare');
@ -57,5 +59,8 @@ Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function
Route::get('/detailed-products', 'ShopController@getDetailedProducts')
->name('velocity.product.details');
Route::get('/category-products/{categoryId}', 'ShopController@getCategoryProducts')
->name('velocity.category.products');
});
});

View File

@ -20,6 +20,7 @@
'isEnable',
'csrfToken',
'productId',
'reloadPage',
'moveToCart',
'showCartIcon',
'addClassToBtn',
@ -59,6 +60,10 @@
}
window.showAlert(`alert-success`, this.__('shop.general.alert.success'), response.data.message);
if (this.reloadPage == "1") {
window.location.reload();
}
} else {
window.showAlert(`alert-${response.data.status}`, response.data.label ? response.data.label : this.__('shop.general.alert.error'), response.data.message);

View File

@ -1,16 +1,18 @@
<template>
<div class="modal-container" v-if="isModalOpen">
<div class="modal-header">
<slot name="header">
Default header
</slot>
<i class="icon remove-icon" @click="closeModal"></i>
</div>
<div class="modal-parent scrollable" v-if="isModalOpen">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
Default header
</slot>
<i class="icon remove-icon" @click="closeModal"></i>
</div>
<div class="modal-body">
<slot name="body">
Default body
</slot>
<div class="modal-body">
<slot name="body">
Default body
</slot>
</div>
</div>
</div>
</template>
@ -23,12 +25,8 @@
return {}
},
created () {
this.closeModal();
},
computed: {
isModalOpen () {
isModalOpen: function () {
this.addClassToBody();
return this.isOpen;
@ -36,12 +34,13 @@
},
methods: {
closeModal () {
this.$root.$set(this.$root.modalIds, this.id, true);
closeModal: function () {
this.$root.$set(this.$root.modalIds, this.id, false);
},
addClassToBody () {
addClassToBody: function () {
var body = document.querySelector("body");
if(this.isOpen) {
body.classList.add("modal-open");
} else {

View File

@ -2,7 +2,11 @@
<div class="col-12 lg-card-container list-card product-card row" v-if="list">
<div class="product-image">
<a :title="product.name" :href="`${baseUrl}/${product.slug}`">
<img :src="product.image" />
<img
:src="product.image"
:onerror="`this.src='${this.$root.baseUrl}/vendor/webkul/ui/assets/images/product/large-product-placeholder.png'`" />
<product-quick-view-btn :quick-view-details="product"></product-quick-view-btn>
</a>
</div>
@ -18,14 +22,14 @@
<div class="product-rating" v-if="product.totalReviews && product.totalReviews > 0">
<star-ratings :ratings="product.avgRating"></star-ratings>
<span>{{ product.totalReviews }}</span>
<span>{{ __('products.reviews-count', {'totalReviews': product.totalReviews}) }}</span>
</div>
<div class="product-rating" v-else>
<span class="fs14" v-text="product.firstReviewText"></span>
</div>
<div class="cart-wish-wrap row mt5" v-html="product.addToCartHtml"></div>
<vnode-injector :nodes="getDynamicHTML(product.addToCartHtml)"></vnode-injector>
</div>
</div>
</div>
@ -37,7 +41,8 @@
:alt="product.name"
:src="product.image"
:data-src="product.image"
class="card-img-top lzy_img" />
class="card-img-top lzy_img"
:onerror="`this.src='${this.$root.baseUrl}/vendor/webkul/ui/assets/images/product/large-product-placeholder.png'`" />
<!-- :src="`${$root.baseUrl}/vendor/webkul/ui/assets/images/product/meduim-product-placeholder.png`" /> -->
<product-quick-view-btn :quick-view-details="product"></product-quick-view-btn>
@ -76,7 +81,6 @@
</template>
<script type="text/javascript">
// compile add to cart html (it contains wishlist component)
export default {
props: [
'list',

View File

@ -10,7 +10,7 @@
methods: {
addProductToCompare: function () {
if (this.customer == "true") {
if (this.customer == "true" || this.customer == true) {
this.$http.put(
`${this.$root.baseUrl}/comparison`, {
productId: this.productId,

View File

@ -4,13 +4,13 @@
id="shimmer-carousel"
navigation-enabled="hide"
pagination-enabled="hide"
:slides-count="shimmerCount + 1"
:slides-per-page="shimmerCount">
:slides-count="shimmerCountInt + 1"
:slides-per-page="shimmerCountInt">
<slide
:key="count"
:slot="`slide-${count}`"
v-for="count in shimmerCount">
v-for="count in shimmerCountInt">
<div class="shimmer-card">
<div class="shimmer-wrapper">
@ -30,9 +30,14 @@
props: {
'shimmerCount': {
default: 6,
type: Number,
},
},
data: function () {
return {
shimmerCountInt: parseInt(this.shimmerCount),
}
}
}
</script>

View File

@ -20,12 +20,15 @@
{{ isActive ? 'favorite' : 'favorite_border' }}
</i>
<span style="vertical-align: super;" v-html="text"></span>
</a>
</template>
<script type="text/javascript">
export default {
props: [
'text',
'active',
'addClass',
'addedText',
@ -33,6 +36,7 @@
'removeText',
'isCustomer',
'productSlug',
'moveToWishlist',
],
data: function () {
@ -54,7 +58,7 @@
let existingValue = this.getStorageValue('wishlist_product');
if (existingValue) {
let valueIndex = existingValue.indexOf(productId);
var valueIndex = existingValue.indexOf(productId);
if (valueIndex == -1) {
this.isActive = true;
@ -78,6 +82,10 @@
this.isActive ? this.addedText : this.removeText
);
if (this.moveToWishlist && valueIndex == -1) {
window.location.href = this.moveToWishlist;
}
return true;
},

View File

@ -58,13 +58,13 @@ $(document).ready(function () {
Vue.mixin({
data: function () {
return {
'baseUrl': document.querySelector("script[src$='velocity.js']").getAttribute('baseUrl'),
'imageObserver': null,
'navContainer': false,
'headerItemsCount': 0,
'sharedRootCategories': [],
'responsiveSidebarTemplate': '',
'responsiveSidebarKey': Math.random(),
'sharedRootCategories': [],
'imageObserver': null,
'baseUrl': document.querySelector("script[src$='velocity.js']").getAttribute('baseUrl'),
}
},

View File

@ -26,6 +26,7 @@
::-webkit-scrollbar {
width: 3px;
height: 5px;
}
/* Track */
::-webkit-scrollbar-track {
@ -196,6 +197,8 @@ body {
min-width: 150px;
cursor: pointer;
text-align: right;
padding-top: 5px;
* {
display: table-cell;
@ -246,9 +249,12 @@ body {
> div:last-child {
height: 32px;
}
* {
height: 100%;
> div {
.default {
padding: 5px;
font-size: 14px;
}
}
@ -278,7 +284,6 @@ body {
}
}
.dropdown-menu {
border-top: 3px solid $border-primary;
border-radius: 0px;
@ -971,3 +976,5 @@ i.within-circle {
border: 1px #E5E5E5;
margin: 0 auto;
}
.row:before, .row:after {display: none !important;}

View File

@ -174,23 +174,25 @@
}
.modal-container {
background: #ffffff;
left: 50%;
top: 100px;
z-index: 11;
width: 600px;
max-width: 80%;
left: 50%;
margin-left: -300px;
max-height: 80%;
position: fixed;
z-index: 11;
font-size: 14px;
overflow-y: auto;
margin-left: -300px;
background: #ffffff;
animation: jelly 0.5s ease-in-out;
animation: fade-in-white 0.3s ease-in-out;
@include border-radius(5px);
@include box-shadow(
0px 15px 25px 0px rgba(0, 0, 0, 0.03),
0px 20px 45px 5px rgba(0, 0, 0, 0.2)
);
animation: fade-in-white 0.3s ease-in-out;
animation: jelly 0.5s ease-in-out;
@include border-radius(5px);
overflow-y: auto;
max-height: 80%;
.modal-header {
padding: 20px;
@ -205,6 +207,15 @@
.icon {
float: right;
cursor: pointer;
&.remove-icon {
width: 24px;
right: 20px;
height: 24px;
margin-right: 0;
position: absolute;
background-image: url(/themes/velocity/assets/images/Icon-remove.svg);
}
}
}
@ -491,9 +502,8 @@
.customer-options{
top: 40px;
float: right;
height: 100%;
padding: 20px;
height: 150px;
overflow-y: scroll;
width: 200px !important;
@ -510,6 +520,11 @@
li {
padding: 3px 0;
height: unset !important;
a {
display: block;
padding: 0 20px !important;
}
}
a {
@ -861,7 +876,8 @@
}
input,
select {
select,
textarea {
width: 100%;
resize: none;
font-size: 16px;
@ -873,6 +889,8 @@
input:active,
input:focus,
textarea:active,
textarea:focus,
select:focus,
select:active {
border-color: $theme-color;
@ -1066,6 +1084,57 @@
padding: 6px 12px;
}
}
.accordian .accordian-header {
padding: 10px 0;
font-weight: 600;
}
.image-wrapper {
width: 100%;
margin-top: 10px;
margin-bottom: 20px;
display: inline-block;
.image-item {
width: 200px;
height: 200px;
position: relative;
border-radius: 3px;
margin-right: 20px;
background: #f8f9fa;
margin-bottom: 20px;
display: inline-block;
background-position: 50%;
background-repeat: no-repeat;
background-image: url(/vendor/webkul/ui/assets/images/placeholder-icon.svg);
.remove-image {
left: 0;
bottom: 0;
width: 100%;
color: #fff;
padding: 10px;
cursor: pointer;
margin-bottom: 0;
text-align: center;
position: absolute;
margin-right: 20px;
border-radius: 0 0 4px 4px;
text-shadow: 0 1px 2px rgba(0,0,0,.24);
background-image: linear-gradient(-180deg,rgba(0,0,0,.08),rgba(0,0,0,.24));
}
input {
display: none;
}
img.preview {
width: 100%;
height: 100%;
}
}
}
}
.account-items-list {
@ -1272,18 +1341,15 @@
i {
color: $black-color;
}
i:hover::before {
// content: "\E93D";
}
}
.checkout-process {
padding: 40px 20px;
.col-7 {
> div {
width: 100%;
.col-lg-7 {
.coupon-container,
> div:not(:first-child) {
margin-top: 20px;
}
}
@ -2219,6 +2285,37 @@
.pagination {
.page-item {
padding: 0 10px;
&.active {
font-weight: 600;
color: $theme-color !important;
border-bottom: 2px solid $theme-color;
}
&.next,
&.previous {
.angle-right-icon,
.angle-left-icon {
@extend .rango-default;
margin: 0;
font-size: 24px;
background: unset;
text-align: center;
}
}
&.next {
.angle-right-icon::before {
content: "\E908";
}
}
&.previous {
.angle-left-icon::before {
content: "\E907";
}
}
}
a {
@ -2274,14 +2371,21 @@
.compare-products {
// overflow-x: scroll;
// padding-bottom: 30px;
width: 100%;
padding-bottom: 20px;
word-break: break-word;
margin-left: 0 !important;
margin-right: 10px !important;
.col,
.col-2 {
max-width: 20%;
padding-left: 0;
word-break: break-word;
tr {
width: 100%;
}
td {
padding: 15px;
min-width: 250px;
max-width: 250px;
vertical-align: top;
}
.image-wrapper {

View File

@ -717,6 +717,8 @@
.rango-arrow-right {
float: right;
font-size: 20px;
padding-top: 5px;
padding-right: 15px;
}

View File

@ -448,7 +448,14 @@
height: 270px;
max-width: 200px;
max-height: 200px;
position: relative;
background: #f2f2f2;
.quick-view-btn-container {
button {
left: calc(50% - 40px);
}
}
}
.product-information {
@ -485,7 +492,8 @@
.wishlist-icon {
height: 40px;
display: table;
vertical-align: top;
display: inline-table;
padding-left: 0 !important;
i {
@ -497,10 +505,13 @@
.compare-icon {
padding-left: 0;
display: inline-table;
}
.add-to-cart-btn {
float: left;
max-width: 150px;
display: inline-block;
}
}

View File

@ -255,6 +255,8 @@ return [
'female' => 'أنثى',
],
'general' => [
'no' => 'No',
'yes' => 'Yes',
'view' => 'رأي',
'filter' => 'منقي',
'update' => 'تحديث',

View File

@ -1,8 +1,8 @@
<?php
return [
'admin' => [
'system' => [
'admin' => [
'system' => [
'velocity' => [
'general' => 'General',
'category' => 'Category',
@ -39,14 +39,14 @@ return [
'num-sub-category' => 'Number Of Sub Category',
]
],
'layouts' => [
'layouts' => [
'velocity' => 'Velocity',
'cms-pages' => 'CMS Pages',
'meta-data' => 'Meta Data',
'category-menu' => 'Category Menu',
'header-content' => 'Header Content',
],
'contents' => [
'contents' => [
'self' => 'Self',
'active' => 'Active',
'new-tab' => 'New Tab',
@ -112,7 +112,7 @@ return [
'general' => 'General',
'add-image-btn-title' => 'Add Image'
],
'category' => [
'category' => [
'save-btn-title' => 'Save Menu',
'title' => 'Category Menu List',
'add-title' => 'Add Menu Content',
@ -136,153 +136,156 @@ return [
'tooltip-content' => 'Tooltip Content',
'mass-delete-success' => 'Selected categories menu deleted successfully.',
],
'general' => [
'general' => [
'locale_logo' => 'Locale Logo',
],
],
'home' => [
'view-all' => 'View All',
'add-to-cart' => 'Add To Cart',
'hot-categories' => 'Hot Categories',
'payment-methods' => 'Payment Methods',
'customer-reviews' => 'Customer Reviews',
'shipping-methods' => 'Shipping Methods',
'home' => [
'view-all' => 'View All',
'add-to-cart' => 'Add To Cart',
'hot-categories' => 'Hot Categories',
'payment-methods' => 'Payment Methods',
'customer-reviews' => 'Customer Reviews',
'shipping-methods' => 'Shipping Methods',
'popular-categories' => 'Popular Categories',
],
'header' => [
'cart' => 'Cart',
'cart' => 'Cart',
'guest' => 'Guest',
'logout' => 'Logout',
'title' => 'Account',
'account' => 'Account',
'profile' => 'Profile',
'wishlist' => 'Wishlist',
'all-categories' => 'All Categories',
'search-text' => 'Search products here',
'welcome-message' => 'Welcome, :customer_name',
'dropdown-text' => 'Manage Cart, Orders & Wishlist',
'header' => [
'cart' => 'Cart',
'cart' => 'Cart',
'guest' => 'Guest',
'logout' => 'Logout',
'title' => 'Account',
'account' => 'Account',
'profile' => 'Profile',
'wishlist' => 'Wishlist',
'all-categories' => 'All Categories',
'search-text' => 'Search products here',
'welcome-message' => 'Welcome, :customer_name',
'dropdown-text' => 'Manage Cart, Orders & Wishlist',
],
'menu-navbar' => [
'text-more' => 'More',
'menu-navbar' => [
'text-more' => 'More',
'text-category' => 'Shop by Category',
],
'minicart' => [
'cart' => 'Cart',
'minicart' => [
'cart' => 'Cart',
'view-cart' => 'View Cart',
],
'checkout' => [
'qty' => 'Qty',
'checkout' => 'Checkout',
'cart' => [
'view-cart' => 'View Cart',
'cart-summary' => 'Cart Summary',
'checkout' => [
'qty' => 'Qty',
'checkout' => 'Checkout',
'cart' => [
'view-cart' => 'View Cart',
'cart-summary' => 'Cart Summary',
],
'qty' => 'Qty',
'items' => 'Items',
'subtotal' => 'Subtotal',
'qty' => 'Qty',
'items' => 'Items',
'subtotal' => 'Subtotal',
'sub-total' => 'Sub Total',
'proceed' => 'Proceed to checkout',
'proceed' => 'Proceed to checkout',
],
'customer' => [
'compare' => [
'text' => 'Compare',
'customer' => [
'compare' => [
'text' => 'Compare',
'compare_similar_items' => 'Compare Similar Items',
'added' => 'Item successfully added to compare list',
'already_added' => 'Item already added to compare list',
'removed' => 'Item successfully removed from compare list',
'empty-text' => "You don't have any items in your compare list",
'added' => 'Item successfully added to compare list',
'already_added' => 'Item already added to compare list',
'removed' => 'Item successfully removed from compare list',
'empty-text' => "You don't have any items in your compare list",
],
'login-form' => [
'sign-up' => 'Sign up',
'new-customer' => 'New Customer',
'customer-login' => 'Customer Login',
'registered-user' => 'Registered User',
'your-email-address' => 'Your email address',
'form-login-text' => 'If you have an account, sign in with your email address.',
'login-form' => [
'sign-up' => 'Sign up',
'new-customer' => 'New Customer',
'customer-login' => 'Customer Login',
'registered-user' => 'Registered User',
'your-email-address' => 'Your email address',
'form-login-text' => 'If you have an account, sign in with your email address.',
],
'signup-form' => [
'login' => 'Login',
'become-user' => 'Become User',
'signup-form' => [
'login' => 'Login',
'become-user' => 'Become User',
'user-registration' => 'User Registration',
'form-sginup-text' => 'If you are new to our store, we glab to have you as member.',
'form-sginup-text' => 'If you are new to our store, we glad to have you as member.',
],
'forget-password' => [
'login' => 'Login',
'forgot-password' => 'Forgot Password',
'recover-password' => 'Recover Password',
'forget-password' => [
'login' => 'Login',
'forgot-password' => 'Forgot Password',
'recover-password' => 'Recover Password',
'recover-password-text' => 'If you forgot your password, recover it by entering your email address.',
]
],
'error' => [
'go-to-home' => 'Go to home',
'page-lost-short' => 'Page lost content',
'something_went_wrong' => 'something went wrong',
'error' => [
'go-to-home' => 'Go to home',
'page-lost-short' => 'Page lost content',
'something_went_wrong' => 'something went wrong',
'page-lost-description' => "The page you're looking for isn't available. Try to search again or use the Go Back button below.",
],
'products' => [
'text' => 'Products',
'details' => 'Details',
'reviews-title' => 'Reviews',
'reviewed' => 'Reviewed',
'review-by' => 'Review by',
'quick-view' => 'Quick View',
'not-available' => 'Not Available',
'submit-review' => 'Submit Review',
'ratings' => ':totalRatings Ratings',
'reviews-count' => ':totalReviews Reviews',
'customer-rating' => 'Customer Rating',
'more-infomation' => 'More Information',
'view-all-reviews' => 'View All Reviews',
'products' => [
'text' => 'Products',
'details' => 'Details',
'reviews-title' => 'Reviews',
'reviewed' => 'Reviewed',
'review-by' => 'Review by',
'quick-view' => 'Quick View',
'not-available' => 'Not Available',
'submit-review' => 'Submit Review',
'ratings' => ':totalRatings Ratings',
'reviews-count' => ':totalReviews Reviews',
'customer-rating' => 'Customer Rating',
'more-infomation' => 'More Information',
'view-all-reviews' => 'View All Reviews',
'write-your-review' => 'Write Your Review',
'short-description' => 'Short Descriptions',
'recently-viewed' => 'Recently Viewed Products',
'be-first-review' => 'Be the first to write a review',
'recently-viewed' => 'Recently Viewed Products',
'be-first-review' => 'Be the first to write a review',
],
'shop' => [
'gender' => [
'male' => 'Male',
'other' => 'Other',
'shop' => [
'gender' => [
'male' => 'Male',
'other' => 'Other',
'female' => 'Female',
],
'general' => [
'view' => 'View',
'filter' => 'Filter',
'orders' => 'Orders',
'update' => 'Update',
'reviews' => 'Reviews',
'addresses' => 'Addresses',
'top-brands' => 'Top Brands',
'new-password' => 'New password',
'downloadables' => 'Downloadable Products',
'confirm-new-password' => 'Confirm new password',
'general' => [
'no' => 'No',
'yes' => 'Yes',
'view' => 'View',
'filter' => 'Filter',
'orders' => 'Orders',
'update' => 'Update',
'reviews' => 'Reviews',
'addresses' => 'Addresses',
'top-brands' => 'Top Brands',
'new-password' => 'New password',
'downloadables' => 'Downloadable Products',
'confirm-new-password' => 'Confirm new password',
'enter-current-password' => 'Enter your current password',
'alert' => [
'info' => 'Info',
'error' => 'Error',
'success' => 'Success',
'warning' => 'Warning',
'info' => 'Info',
'error' => 'Error',
'success' => 'Success',
'warning' => 'Warning',
],
],
'wishlist' => [
'add-wishlist-text' => 'Add product to wishlist',
'remove-wishlist-text' => 'Remove product from wishlist'
'wishlist' => [
'add-wishlist-text' => 'Add product to wishlist',
'remove-wishlist-text' => 'Remove product from wishlist'
]
],
'responsive' => [
'responsive' => [
'header' => [
'greeting' => 'Welcome, :customer !',
'languages' => 'Languages',
'greeting' => 'Welcome, :customer !',
]
],
]

View File

@ -255,6 +255,8 @@ return [
'female' => 'زن',
],
'general' => [
'no' => 'No',
'yes' => 'Yes',
'view' => 'چشم انداز',
'filter' => 'فیلتر',
'orders' => 'سفارشات',

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