resolve conflicts

This commit is contained in:
Steffen Mahler 2020-08-20 09:28:33 +02:00
commit 1b5c3bca93
107 changed files with 4288 additions and 2770 deletions

View File

@ -1,6 +1,6 @@
APP_NAME=Bagisto
APP_ENV=local
APP_VERSION=1.1.2
APP_VERSION=1.2.0-BETA1
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost

View File

@ -1,6 +1,6 @@
APP_NAME=Laravel
APP_ENV=local
APP_VERSION=1.1.2
APP_VERSION=1.2.0-BETA1
APP_KEY=base64:G4KY3tUsTaY9ONo1n/QyJvVLQZdJDgbIkSJswFK01HE=
APP_DEBUG=true
APP_URL=http://localhost

View File

@ -2,7 +2,7 @@
#### This changelog consists the bug & security fixes and new features being included in the releases listed below.
## **v1.1.3 (19th of June 2020)** - *Release*
## **v1.2.0-BETA1 (18th of August 2020)** - *Release*
* [feature] - Customer group price for products implemented
@ -12,6 +12,23 @@
* [feature] - Search engine optimization with rich snippet
* [feature] - Blade file tracer
* [feature] - Search with Elastic and Algolia
* [feature] - Support for admin multi theme
* [feature] - One click upgrade
* [feature] - Social login (Facebook, Twitter, Google, Linkedin, Github)
* [feature] - Social share
* [feature] - Store configuration added
* [feature] - Feature to disable compare option
* [feature] - Store configuration added for product listing
* #343 [fixed] - Translation strings are missing from awful amount of controllers when returning responses with flash. And optimise translation strings for faster static translations.
@ -21,6 +38,8 @@
* #985 [fixed] - Dynamically insert products
* #1246 [fixed] - Implement a feature to import product through csv file.
* #1258 [fixed] - If payment is done through paypal then invoice should generate automatically and status of Order should be processing.
* #1362 [fixed] - Site logo and Category Image are broken
@ -37,6 +56,8 @@
* #2060 [fixed] - auto generate coupon accordion not getting hidden while selecting no specific coupons
* #2141 [fixed] - SQLSTATE[42S02]: Base table or view not found: 1146 Table '[DB_PREFIX].category_translations' doesn't exist
* #2159 [fixed] - Taking more time to load product details in shopping cart.
* #2415 [fixed] - Add TO CART button should replace by “BOOk NOW” button for booking product.
@ -81,6 +102,8 @@
* #2936 [fixed] - change the admin route for another
* #2937 [fixed] - Checkout old theme
* #2942 [fixed] - Randomize New and Featured Products
* #2949 [fixed] - failed to migrate with new database using installer
@ -91,10 +114,16 @@
* #2969 [fixed] - Cancel icon is not visible in velocity theme for customer order detail
* #2971 [fixed] - Need to add the possibility to translate velocity metadata
* #2972 [fixed] - can add to homescreen on mobile device in velocity theme
* #2973 [fixed] - force the execution of the shipping methods trigger
* #2974 [fixed] - Thumbnails are not generating on mobile ifproduct has more than 4 photos
* #2981 [fixed] - When paying with Paypal the user can change the amounts of the products
* #2886 [fixed] - Configuration option for Compare
* #2985 [fixed] - Product category is not saving
@ -143,6 +172,8 @@
* #3029 [fixed] - velocity theme not fully responsive
* #3030 [fixed] - Api for coupons..
* #3032 [fixed] - [Critical] Onecheckout preventing to continue to shipping method after selecting address
* #3035 [fixed] - Please update pwa for bagisto
@ -205,6 +236,8 @@
* #3120 [fixed] - admin panel multi locale
* #3131 [fixed] - Velocity theme responsiveness issue after changing the language to Arabic RTL
* #3135 [fixed] - How can I cad comment box in checkout form.
* #3136 [fixed] - configurable product variant name gets removed from the catalog list
@ -267,6 +300,8 @@
* #3222 [fixed] - UI issue in event ticket booking special price date field
* #3231 [fixed] - "error!options are missing alert" on home page shouldn't be shown
* #3232 [fixed] - homepage is showing 404 error page in both theme
* #3234 [fixed] - UI Issue for cart, wishlist, compare icon number indicator in RTL
@ -283,6 +318,8 @@
* #3241 [fixed] - login fields(email,passwords) are in the center when in RTL
* #3243 [fixed] - Email settings are empty in backend
* #3246 [fixed] - fix icon layout in edit booking product page for RTL
* #3248 [fixed] - fix css for cancel icon on success alert RTL
@ -313,6 +350,320 @@
* #3298 [fixed] - Header content category always redirect to 404 error page
* #3301 [fixed] - fix search keys in search bar for analysed keywords in velocity
* #3303 [fixed] - Getting exception on changing locale when customer has opened downloadable products grid from his account
* #3304 [fixed] - Getting incorrect message on delete all from wishlist in case of guest user only
* #3307 [fixed] - Getting exception on changing locale when customer has opened order grid from his account
* #3309 [fixed] - 500 error when loading /search with "term" in query string
* #3310 [fixed] - Editing product title should not change URL if it has already been set
* #3311 [fixed] - Mobile Bug - Filters disappear when no products match filters
* #3313 [fixed] - In cart, in place of only qty, quantity and price both are coming in ar.
* #3314 [fixed] - admin back to sign in link always redirects to same page after admin login
* #3315 [fixed] - compare option should be remove from customer profile options list if the compare is disable
* #3316 [fixed] - layout issues in checkout page while placing order of booking product
* #3317 [fixed] - Pagination layout should be implemented at customer end
* #3319 [fixed] - Issue in validation message while placing order of booking type product if customer did not fill select rent time
* #3320 [fixed] - Getting exception on frontend when opening a category in which brand is selected as filterable attribute.
* #3321 [fixed] - Comapre button should come between wishlist and cart in arabic also.
* #3322 [fixed] - Title and url both are coming same on layered navigation page in velocity theme
* #3323 [fixed] - text written in search page(for invalid search) should be properly aligned
* #3328 [fixed] - velocity logo and shop by category override
* #3330 [fixed] - Layout issue while adding configurable product to cart in velocity theme
* #3331 [fixed] - layout issue while using filter at any grid(admin end) in ar locale
* #3335 [fixed] - New Label is missing in VelocityTheme
* #3338 [fixed] - bundle option should be marked as mandatory if it's required
* #3339 [fixed] - category display mode options are not working
* #3340 [fixed] - mobile view not able to updated currency
* #3341 [fixed] - filter option should be remove from the search page in mobile view
* #3354 [fixed] - error when upload invalid image/file type in search
* #3356 [fixed] - search term removed from the search bar in default theme
* #3357 [fixed] - Image search feature is not available in mobile view default theme
* #3358 [fixed] - New and sale icon lable on product issue in RTL
* #3360 [fixed] - filter and items per page is getting collapsed in ar
* #3363 [fixed] - null value accepted in filter option at customer end
* #3365 [fixed] - On mobile responsive on ios sign up button is missing
* #3369 [fixed] - getting exception when clicking on any social login icon
* #3371 [fixed] - Easy bug: incorrect PL lang file
* #3373 [fixed] - New Error migration Bagisto Install MySQL/MariaDB
* #3374 [fixed] - Social Login Error
* #3377 [fixed] - error when click to twitter social login
* #3379 [fixed] - Getting error on migration command.
* #3380 [fixed] - Layout issues on mobile view in ar locale
* #3381 [fixed] - Customer city name does not allow hyphen
* #3392 [fixed] - Translation key is not added in order settings
* #3393 [fixed] - Getting broken image link for locales in mobile view.
* #3394 [fixed] - Not able to open menu in mobile view having locale arabic.
* #3395 [fixed] - default group should be set for the social login customer
* #3396 [fixed] - getting error when admin view order placed by social customers
* #3399 [fixed] - Remove from wishlist button is displaying as 1 when mouse not hover on product, this occur in all locale except English.
* #3400 [fixed] - fix UI for the compare page in default theme
* #3409 [fixed] - Wrong validation when remove variant(s) of configurable product
* #3411 [fixed] - Sale level is displaying even if special price date has been already expired
* #3417 [fixed] - social login icons in RTL
* #3422 [fixed] - getting exception when view order of deleted customer
* #3423 [fixed] - Cannot change account password
* #3425 [fixed] - Impossible to connect, please check your Algolia Application Id.
* #3443 [fixed] - customer group price functionality is not working
* #3444 [fixed] - Layout issue on review page
* #3445 [fixed] - filter tag is out of box in search key term for long product name
* #3447 [fixed] - By default social login should be enabled
* #3451 [fixed] - Change request regarding shipments
* #3453 [fixed] - Invoice state is always set to paid
* #3457 [fixed] - number indicator are hidden on wishlist or compare icon RTL format
* #3458 [fixed] - not able to add (virtual,booking etc.) product to compare list by logged in user
* #3460 [fixed] - Add address option should come below in velocity theme
* #3465 [fixed] - When I update the folder name from bagisto to new name, the logo image doesn't appear, why?
* #3467 [fixed] - layout issue at shop end in ar
* #3469 [fixed] - Cannot remove a layered navigation attribute from product
* #3472 [fixed] - layout issue in order and downloadable grid at customer end in mobile view
* #3478 [fixed] - Getting exception on putting limit =0 in url
* #3484 [fixed] - missing product quick view icon on search page
* #3485 [fixed] - layout issue on category page for filterable attributes
* #3486 [fixed] - Compare feature shows wrong attribute value
* #3487 [fixed] - Velocity RTL product image zoom floats right - not showing
* #3488 [fixed] - color attribute default swatch value should be selected as dropdown swatch
* #3489 [fixed] - Sale icon is not showing even if catalog rule is applied for grouped and bundle type products
* #3490 [fixed] - Back icon is not working in catalog and cart rule grid
* #3491 [fixed] - broken image for color image swatch type
* #3494 [fixed] - compare feature is not working properly if admin creates a image type attribute and give attribute code and name "image"
* #3495 [fixed] - image is not coming in compare list for any image type attribute
* #3496 [fixed] - showing values in compare list of those attribute which has been removed from attribute family
* #3498 [fixed] - No.of items in compare should be displayed with compare tab in default theme
* #3501 [fixed] - unable to download files while comparing products
* #3502 [fixed] - Side bar menu is getting removed while editing/adding customer address at admin end
* #3505 [fixed] - No message on removing products or deleting all from compare list in default theme
* #3506 [fixed] - Uploaded image is not showing while editing Advertisement 4,3,2 Images for arabic locale
* #3507 [fixed] - locale filter is not working properly in product grid
* #3508 [fixed] - Error on PL lang file
* #3514 [fixed] - Use "has been" in place of "had been" in mail to warehouse
* #3515 [fixed] - Order id is missing in mail which customer get when admin add any comment in order
* #3519 [fixed] - Customer is getting mails in Arabic for order information and rest mails in English for same order which was placed in ar locale.
* #3520 [fixed] - Admin should get mail according to admin's default locale not customer's locale
* #3521 [fixed] - layout issue in order information in default theme at customer end
* #3522 [fixed] - Admin is not getting mail when customer cancels order
* #3526 [fixed] - On changing current password admin/customer should get mail
* #3530 [fixed] - mobile view sortBy functionality in category page is not working
* #3531 [fixed] - In price filter, allow comma(,) for price in filter as in french locale float values used to be separated by , in stead of .
* #3532 [fixed] - (Mobile view) getting product image issue when set grid as List type in category page
* #3533 [fixed] - Products Per Page configuration is not working properly
* #3534 [fixed] - Add validation for products per page field otherwise if admin entered string value then customer gets exception on category page
* #3535 [fixed] - Sort By configuration from admin end is not working properly
* #3546 [fixed] - Shipping charge is not getting calculated properly in case customer removes the product just before clicking on place order
* #3547 [fixed] - checkout country null issue
* #3548 [fixed] - filter is not working properly in attribute grid at admin end
* #3550 [fixed] - there should be tooltip text on mouse hover on compare icon on product
* #3554 [fixed] - Cart Rule Issue
* #3558 [fixed] - Incorrect price showing for configurable product on front end
* #3561 [fixed] - Customer Revenue is not getting minus after refund
* #3562 [fixed] - getting exception when view category page in frontend
* #3564 [fixed] - getting exception if admin uploads higher size image in image swatch while editing/adding attribute
* #3570 [fixed] - Translation issue on uploading high size image
* #3574 [fixed] - One page Checkout loader hits on adding single digit in phone number
* #3575 [fixed] - Inactive child product shouldn't visible in grouped product
* #3577 [fixed] - Customer is able to place order of more than available qty of any bundle option product
* #3580 [fixed] - Incorrect error message while adding bundle product in cart if no.of bundles contains more qty than available qty
* #3591 [fixed] - Getting exception while using layered navigation filters on category page
* #3595 [fixed] - I would like like to change the admin route or url
* #3604 [fixed] - show percentage in place count number in review in velocity theme
* #3606 [fixed] - showing different number of star in velocity and default theme for same rating
* #3611 [fixed] - The content of CMS page is cropped
* #3615 [fixed] - Getting exception while uploading favicon image if image is of high size
* #3617 [fixed] - Add feature to set the category header content limit in velocity
* #3621 [fixed] - Ui issue when applying filter in mobile view
* #3622 [fixed] - channel filter is not working in cart rule
* #3628 [fixed] - Correct the Success message after updating content in velocity meta data.
* #3629 [fixed] - Filter is not working properly in content list grid for content type column
* #3631 [fixed] - Category slug should not accept values in capital letters while adding content for Header content
* #3636 [fixed] - Correct the Ui of profile in mobile view,there is no difference in field name test and field data.
* #3637 [fixed] - No records founds text in downloadable product section of customer should display in centre, in mobile view.
* #3638 [fixed] - Promotion, combine "percentage" & "fixed amount to whole cart" cart rules get wrong discount amount
* #3642 [fixed] - getting exception when creating configurable product in case of DB_Prefix
* #3649 [fixed] - product datagrid filter layout issue
* #3648 [fixed] - custom file type attribute is not visible in PDP
* #3656 [fixed] - Product name gets blank each time we refresh the product page.
* #3657 [fixed] - Auth user can see all users info by id
* #3674 [fixed] - Bugs on category page for list mode
* #3675 [fixed] - Address icon is overlapping on side bar menu in mobile view
* #3676 [fixed] - all cross selling products are not visible in cart page of velocity theme
* #3678 [fixed] - Customer is able to access downloadable products even when invoice state is pending
* #3688 [fixed] - Select icons should be in right side in RTL on payment page in default theme
* #3689 [fixed] - There should not be sale icon in shopping cart in velocity theme
* #3692 [fixed] - Channel filter is not working properly in product grid
* #3693 [fixed] - There should not be any success message while trying to delete system attributes
* #3700 [fixed] - getting exception while creating refund of order placed by deleted customer
* #3702 [fixed] - On deleting customer their invoice and shipment records are getting disappeared.
* #3704 [fixed] - No alert message while deleting customer with pending or processing order from admin end.
* #3717 [fixed] - Layout issue in order grid at customer end
* #3720 [fixed] - Velocity theme option is missing in channel
* #3723 [fixed] - getting exception when download uploaded file from backend
* #3725 [fixed] - getting exception on comparison page of default theme
* #3727 [fixed] - compare page layout issue for logged in user
* #3735 [fixed] - Make Velocity Meta Data section Channel wise.
* #3740 [fixed] - translation of alert when remove compare item in default theme
* #3742 [fixed] - Invoice, ship and cancel buttons are missing in order placed by guest user
* #3745 [fixed] - getting exception in backend when having DB_PREFIX
* #3747 [fixed] - velocity content header route throwing an exception in spanish locale
* #3751 [fixed] - shipping tab is missing in order details for deleted customer
* #3755 [fixed] - Webinstall - SMTP port is not set
* #3757 [fixed] - broken image on guest wishlist
* #3767 [fixed] - Header-nav on mobile view seem buggy on search item
## **v1.1.2 (24th of March 2020)** - *Release*

View File

@ -21,12 +21,10 @@
"astrotomic/laravel-translatable": "^11.0.0",
"babenkoivan/elastic-scout-driver": "^1.1",
"bagistobrasil/bagisto-product-social-share": "^0.1.2",
"barryvdh/laravel-debugbar": "^3.1",
"barryvdh/laravel-dompdf": "0.8.6",
"doctrine/dbal": "2.9.2",
"fideloper/proxy": "^4.2",
"flynsarmy/db-blade-compiler": "^5.5",
"fzaninotto/faker": "^1.9.1",
"guzzlehttp/guzzle": "~6.3",
"intervention/image": "^2.4",
"intervention/imagecache": "^2.3",

474
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": "3332479a65fc6c67057c2946a27fe95e",
"content-hash": "b02e22c84c5b91a32e9d1f50e8d14b7f",
"packages": [
{
"name": "algolia/algoliasearch-client-php",
@ -342,74 +342,6 @@
],
"time": "2020-08-04T12:36:28+00:00"
},
{
"name": "barryvdh/laravel-debugbar",
"version": "v3.3.3",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git",
"reference": "57f2219f6d9efe41ed1bc880d86701c52f261bf5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/57f2219f6d9efe41ed1bc880d86701c52f261bf5",
"reference": "57f2219f6d9efe41ed1bc880d86701c52f261bf5",
"shasum": ""
},
"require": {
"illuminate/routing": "^5.5|^6|^7",
"illuminate/session": "^5.5|^6|^7",
"illuminate/support": "^5.5|^6|^7",
"maximebf/debugbar": "^1.15.1",
"php": ">=7.0",
"symfony/debug": "^3|^4|^5",
"symfony/finder": "^3|^4|^5"
},
"require-dev": {
"laravel/framework": "5.5.x"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
},
"laravel": {
"providers": [
"Barryvdh\\Debugbar\\ServiceProvider"
],
"aliases": {
"Debugbar": "Barryvdh\\Debugbar\\Facade"
}
}
},
"autoload": {
"psr-4": {
"Barryvdh\\Debugbar\\": "src/"
},
"files": [
"src/helpers.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "PHP Debugbar integration for Laravel",
"keywords": [
"debug",
"debugbar",
"laravel",
"profiler",
"webprofiler"
],
"time": "2020-05-05T10:53:32+00:00"
},
{
"name": "barryvdh/laravel-dompdf",
"version": "v0.8.6",
@ -1378,56 +1310,6 @@
],
"time": "2019-07-28T22:19:29+00:00"
},
{
"name": "fzaninotto/faker",
"version": "v1.9.1",
"source": {
"type": "git",
"url": "https://github.com/fzaninotto/Faker.git",
"reference": "fc10d778e4b84d5bd315dad194661e091d307c6f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fzaninotto/Faker/zipball/fc10d778e4b84d5bd315dad194661e091d307c6f",
"reference": "fc10d778e4b84d5bd315dad194661e091d307c6f",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0"
},
"require-dev": {
"ext-intl": "*",
"phpunit/phpunit": "^4.8.35 || ^5.7",
"squizlabs/php_codesniffer": "^2.9.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
}
},
"autoload": {
"psr-4": {
"Faker\\": "src/Faker/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "François Zaninotto"
}
],
"description": "Faker is a PHP library that generates fake data for you.",
"keywords": [
"data",
"faker",
"fixtures"
],
"time": "2019-12-12T13:22:17+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "6.5.4",
@ -3005,67 +2887,6 @@
],
"time": "2019-10-06T11:29:25+00:00"
},
{
"name": "maximebf/debugbar",
"version": "v1.16.3",
"source": {
"type": "git",
"url": "https://github.com/maximebf/php-debugbar.git",
"reference": "1a1605b8e9bacb34cc0c6278206d699772e1d372"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/1a1605b8e9bacb34cc0c6278206d699772e1d372",
"reference": "1a1605b8e9bacb34cc0c6278206d699772e1d372",
"shasum": ""
},
"require": {
"php": "^7.1",
"psr/log": "^1.0",
"symfony/var-dumper": "^2.6|^3|^4|^5"
},
"require-dev": {
"phpunit/phpunit": "^5"
},
"suggest": {
"kriswallsmith/assetic": "The best way to manage assets",
"monolog/monolog": "Log using Monolog",
"predis/predis": "Redis storage"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.16-dev"
}
},
"autoload": {
"psr-4": {
"DebugBar\\": "src/DebugBar/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Maxime Bouroumeau-Fuseau",
"email": "maxime.bouroumeau@gmail.com",
"homepage": "http://maximebf.com"
},
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "Debug bar in the browser for php application",
"homepage": "https://github.com/maximebf/php-debugbar",
"keywords": [
"debug",
"debugbar"
],
"time": "2020-05-06T07:06:27+00:00"
},
{
"name": "monolog/monolog",
"version": "2.1.0",
@ -4556,63 +4377,6 @@
"homepage": "https://symfony.com",
"time": "2020-05-20T17:43:50+00:00"
},
{
"name": "symfony/debug",
"version": "v4.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "28f92d08bb6d1fddf8158e02c194ad43870007e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/28f92d08bb6d1fddf8158e02c194ad43870007e6",
"reference": "28f92d08bb6d1fddf8158e02c194ad43870007e6",
"shasum": ""
},
"require": {
"php": ">=7.1.3",
"psr/log": "~1.0",
"symfony/polyfill-php80": "^1.15"
},
"conflict": {
"symfony/http-kernel": "<3.4"
},
"require-dev": {
"symfony/http-kernel": "^3.4|^4.0|^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.4-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Debug\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
"time": "2020-05-24T08:33:35+00:00"
},
{
"name": "symfony/deprecation-contracts",
"version": "v2.1.2",
@ -6467,6 +6231,74 @@
}
],
"packages-dev": [
{
"name": "barryvdh/laravel-debugbar",
"version": "v3.3.3",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git",
"reference": "57f2219f6d9efe41ed1bc880d86701c52f261bf5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/57f2219f6d9efe41ed1bc880d86701c52f261bf5",
"reference": "57f2219f6d9efe41ed1bc880d86701c52f261bf5",
"shasum": ""
},
"require": {
"illuminate/routing": "^5.5|^6|^7",
"illuminate/session": "^5.5|^6|^7",
"illuminate/support": "^5.5|^6|^7",
"maximebf/debugbar": "^1.15.1",
"php": ">=7.0",
"symfony/debug": "^3|^4|^5",
"symfony/finder": "^3|^4|^5"
},
"require-dev": {
"laravel/framework": "5.5.x"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.2-dev"
},
"laravel": {
"providers": [
"Barryvdh\\Debugbar\\ServiceProvider"
],
"aliases": {
"Debugbar": "Barryvdh\\Debugbar\\Facade"
}
}
},
"autoload": {
"psr-4": {
"Barryvdh\\Debugbar\\": "src/"
},
"files": [
"src/helpers.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "PHP Debugbar integration for Laravel",
"keywords": [
"debug",
"debugbar",
"laravel",
"profiler",
"webprofiler"
],
"time": "2020-05-05T10:53:32+00:00"
},
{
"name": "behat/gherkin",
"version": "v4.6.2",
@ -7152,6 +6984,56 @@
],
"time": "2020-05-05T12:28:07+00:00"
},
{
"name": "fzaninotto/faker",
"version": "v1.9.1",
"source": {
"type": "git",
"url": "https://github.com/fzaninotto/Faker.git",
"reference": "fc10d778e4b84d5bd315dad194661e091d307c6f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fzaninotto/Faker/zipball/fc10d778e4b84d5bd315dad194661e091d307c6f",
"reference": "fc10d778e4b84d5bd315dad194661e091d307c6f",
"shasum": ""
},
"require": {
"php": "^5.3.3 || ^7.0"
},
"require-dev": {
"ext-intl": "*",
"phpunit/phpunit": "^4.8.35 || ^5.7",
"squizlabs/php_codesniffer": "^2.9.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
}
},
"autoload": {
"psr-4": {
"Faker\\": "src/Faker/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "François Zaninotto"
}
],
"description": "Faker is a PHP library that generates fake data for you.",
"keywords": [
"data",
"faker",
"fixtures"
],
"time": "2019-12-12T13:22:17+00:00"
},
{
"name": "hamcrest/hamcrest-php",
"version": "v2.0.0",
@ -7200,6 +7082,67 @@
],
"time": "2016-01-20T08:20:44+00:00"
},
{
"name": "maximebf/debugbar",
"version": "v1.16.3",
"source": {
"type": "git",
"url": "https://github.com/maximebf/php-debugbar.git",
"reference": "1a1605b8e9bacb34cc0c6278206d699772e1d372"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/1a1605b8e9bacb34cc0c6278206d699772e1d372",
"reference": "1a1605b8e9bacb34cc0c6278206d699772e1d372",
"shasum": ""
},
"require": {
"php": "^7.1",
"psr/log": "^1.0",
"symfony/var-dumper": "^2.6|^3|^4|^5"
},
"require-dev": {
"phpunit/phpunit": "^5"
},
"suggest": {
"kriswallsmith/assetic": "The best way to manage assets",
"monolog/monolog": "Log using Monolog",
"predis/predis": "Redis storage"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.16-dev"
}
},
"autoload": {
"psr-4": {
"DebugBar\\": "src/DebugBar/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Maxime Bouroumeau-Fuseau",
"email": "maxime.bouroumeau@gmail.com",
"homepage": "http://maximebf.com"
},
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "Debug bar in the browser for php application",
"homepage": "https://github.com/maximebf/php-debugbar",
"keywords": [
"debug",
"debugbar"
],
"time": "2020-05-06T07:06:27+00:00"
},
{
"name": "mockery/mockery",
"version": "1.4.0",
@ -8773,6 +8716,63 @@
"homepage": "https://symfony.com",
"time": "2020-05-23T13:13:03+00:00"
},
{
"name": "symfony/debug",
"version": "v4.4.9",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "28f92d08bb6d1fddf8158e02c194ad43870007e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/28f92d08bb6d1fddf8158e02c194ad43870007e6",
"reference": "28f92d08bb6d1fddf8158e02c194ad43870007e6",
"shasum": ""
},
"require": {
"php": ">=7.1.3",
"psr/log": "~1.0",
"symfony/polyfill-php80": "^1.15"
},
"conflict": {
"symfony/http-kernel": "<3.4"
},
"require-dev": {
"symfony/http-kernel": "^3.4|^4.0|^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.4-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Debug\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
"time": "2020-05-24T08:33:35+00:00"
},
{
"name": "symfony/dom-crawler",
"version": "v5.1.0",

View File

@ -1,188 +0,0 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Module Namespace
|--------------------------------------------------------------------------
|
| Default module namespace.
|
*/
'namespace' => 'Modules',
/*
|--------------------------------------------------------------------------
| Module Stubs
|--------------------------------------------------------------------------
|
| Default module stubs.
|
*/
'stubs' => [
'enabled' => false,
'path' => base_path() . '/vendor/nwidart/laravel-modules/src/Commands/stubs',
'files' => [
'start' => 'start.php',
'routes' => 'Http/routes.php',
'views/index' => 'Resources/views/index.blade.php',
'views/master' => 'Resources/views/layouts/master.blade.php',
'scaffold/config' => 'Config/config.php',
'composer' => 'composer.json',
'assets/js/app' => 'Resources/assets/js/app.js',
'assets/sass/app' => 'Resources/assets/sass/app.scss',
'webpack' => 'webpack.mix.js',
'package' => 'package.json',
],
'replacements' => [
'start' => ['LOWER_NAME', 'ROUTES_LOCATION'],
'routes' => ['LOWER_NAME', 'STUDLY_NAME', 'MODULE_NAMESPACE'],
'webpack' => ['LOWER_NAME'],
'json' => ['LOWER_NAME', 'STUDLY_NAME', 'MODULE_NAMESPACE'],
'views/index' => ['LOWER_NAME'],
'views/master' => ['LOWER_NAME', 'STUDLY_NAME'],
'scaffold/config' => ['STUDLY_NAME'],
'composer' => [
'LOWER_NAME',
'STUDLY_NAME',
'VENDOR',
'AUTHOR_NAME',
'AUTHOR_EMAIL',
'MODULE_NAMESPACE',
],
],
'gitkeep' => true,
],
'paths' => [
/*
|--------------------------------------------------------------------------
| Modules path
|--------------------------------------------------------------------------
|
| This path used for save the generated module. This path also will be added
| automatically to list of scanned folders.
|
*/
'modules' => base_path('Modules'),
/*
|--------------------------------------------------------------------------
| Modules assets path
|--------------------------------------------------------------------------
|
| Here you may update the modules assets path.
|
*/
'assets' => public_path('modules'),
/*
|--------------------------------------------------------------------------
| The migrations path
|--------------------------------------------------------------------------
|
| Where you run 'module:publish-migration' command, where do you publish the
| the migration files?
|
*/
'migration' => base_path('database/migrations'),
/*
|--------------------------------------------------------------------------
| Generator path
|--------------------------------------------------------------------------
| Customise the paths where the folders will be generated.
| Set the generate key to false to not generate that folder
*/
'generator' => [
'config' => ['path' => 'Config', 'generate' => true],
'command' => ['path' => 'Console', 'generate' => true],
'migration' => ['path' => 'Database/Migrations', 'generate' => true],
'seeder' => ['path' => 'Database/Seeders', 'generate' => true],
'factory' => ['path' => 'Database/factories', 'generate' => true],
'model' => ['path' => 'Entities', 'generate' => true],
'controller' => ['path' => 'Http/Controllers', 'generate' => true],
'filter' => ['path' => 'Http/Middleware', 'generate' => true],
'request' => ['path' => 'Http/Requests', 'generate' => true],
'provider' => ['path' => 'Providers', 'generate' => true],
'assets' => ['path' => 'Resources/assets', 'generate' => true],
'lang' => ['path' => 'Resources/lang', 'generate' => true],
'views' => ['path' => 'Resources/views', 'generate' => true],
'test' => ['path' => 'Tests', 'generate' => true],
'repository' => ['path' => 'Repositories', 'generate' => false],
'event' => ['path' => 'Events', 'generate' => false],
'listener' => ['path' => 'Listeners', 'generate' => false],
'policies' => ['path' => 'Policies', 'generate' => false],
'rules' => ['path' => 'Rules', 'generate' => false],
'jobs' => ['path' => 'Jobs', 'generate' => false],
'emails' => ['path' => 'Emails', 'generate' => false],
'notifications' => ['path' => 'Notifications', 'generate' => false],
'resource' => ['path' => 'Transformers', 'generate' => false],
],
],
/*
|--------------------------------------------------------------------------
| Scan Path
|--------------------------------------------------------------------------
|
| Here you define which folder will be scanned. By default will scan vendor
| directory. This is useful if you host the package in packagist website.
|
*/
'scan' => [
'enabled' => false,
'paths' => [
base_path('vendor/*/*'),
],
],
/*
|--------------------------------------------------------------------------
| Composer File Template
|--------------------------------------------------------------------------
|
| Here is the config for composer.json file, generated by this package
|
*/
'composer' => [
'vendor' => 'nwidart',
'author' => [
'name' => 'Nicolas Widart',
'email' => 'n.widart@gmail.com',
],
],
/*
|--------------------------------------------------------------------------
| Caching
|--------------------------------------------------------------------------
|
| Here is the config for setting up caching feature.
|
*/
'cache' => [
'enabled' => false,
'key' => 'laravel-modules',
'lifetime' => 60,
],
/*
|--------------------------------------------------------------------------
| Choose what laravel-modules will register as custom namespaces.
| Setting one to false will require you to register that part
| in your own Service Provider class.
|--------------------------------------------------------------------------
*/
'register' => [
'translations' => true,
/**
* load files on boot or register method
*
* Note: boot not compatible with asgardcms
*
* @example boot|register
*/
'files' => 'register',
],
];

14
config/products.php Normal file
View File

@ -0,0 +1,14 @@
<?php
return [
// use the 'code' of the 'attributes' table here to be able to control which attributes
// should be skipped when doing a copy (admin->catalog->products->copy product).
// you can also add every relation that should not be copied here to skip them.
// defaults to none (which means everything is copied).
'skipAttributesOnCopy' => [
],
// Make the original and source product 'related' via the 'product_relations' table
'linkProductsOnCopy' => false,
];

View File

@ -2,15 +2,15 @@
namespace Webkul\API\Http\Controllers\Shop;
use Cart;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Event;
use Webkul\Checkout\Repositories\CartRepository;
use Webkul\Checkout\Repositories\CartItemRepository;
use Webkul\API\Http\Resources\Checkout\Cart as CartResource;
use Cart;
use Webkul\Customer\Repositories\WishlistRepository;
use Webkul\API\Http\Resources\Checkout\Cart as CartResource;
class CartController extends Controller
{
@ -70,7 +70,7 @@ class CartController extends Controller
}
/**
* Get customer cart
* Get customer cart.
*
* @return \Illuminate\Http\JsonResponse
*/
@ -242,4 +242,55 @@ class CartController extends Controller
'data' => $cart ? new CartResource($cart) : null,
]);
}
/**
* Apply coupon code.
*
* @return \Illuminate\Http\JsonResponse
*/
public function applyCoupon()
{
$couponCode = request()->get('code');
try {
if (strlen($couponCode)) {
Cart::setCouponCode($couponCode)->collectTotals();
if (Cart::getCart()->coupon_code == $couponCode) {
return response()->json([
'success' => true,
'message' => trans('shop::app.checkout.total.success-coupon'),
]);
}
}
return response()->json([
'success' => false,
'message' => trans('shop::app.checkout.total.invalid-coupon'),
]);
} catch (\Exception $e) {
report($e);
return response()->json([
'success' => false,
'message' => trans('shop::app.checkout.total.coupon-apply-issue'),
]);
}
}
/**
* Remove coupon code.
*
* @return \Illuminate\Http\JsonResponse
*/
public function removeCoupon()
{
Cart::removeCouponCode()->collectTotals();
return response()->json([
'success' => true,
'message' => trans('shop::app.checkout.total.remove-coupon'),
]);
}
}

View File

@ -2,12 +2,20 @@
namespace Webkul\API\Http\Controllers\Shop;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Event;
use Webkul\Customer\Repositories\CustomerRepository;
use Webkul\Customer\Repositories\CustomerGroupRepository;
class CustomerController extends Controller
{
/**
* Contains current guard
*
* @var array
*/
protected $guard;
/**
* Contains route related configuration
*
@ -40,8 +48,17 @@ class CustomerController extends Controller
CustomerRepository $customerRepository,
CustomerGroupRepository $customerGroupRepository
) {
$this->guard = request()->has('token') ? 'api' : 'customer';
$this->_config = request('_config');
if (isset($this->_config['authorization_required']) && $this->_config['authorization_required']) {
auth()->setDefaultDriver($this->guard);
$this->middleware('auth:' . $this->guard);
}
$this->customerRepository = $customerRepository;
$this->customerGroupRepository = $customerGroupRepository;
@ -81,4 +98,23 @@ class CustomerController extends Controller
'message' => 'Your account has been created successfully.',
]);
}
/**
* Returns a current user data.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function get($id)
{
if (Auth::user($this->guard)->id === (int) $id) {
return new $this->_config['resource'](
$this->customerRepository->findOrFail($id)
);
}
return response()->json([
'message' => 'Invalid Request.',
], 403);
}
}

View File

@ -75,7 +75,7 @@ Route::group(['prefix' => 'api'], function ($router) {
'resource' => 'Webkul\API\Http\Resources\Catalog\ProductReview',
'authorization_required' => true
]);
//Channel routes
Route::get('channels', 'ResourceController@index')->defaults('_config', [
@ -154,7 +154,7 @@ Route::group(['prefix' => 'api'], function ($router) {
Route::post('customer/register', 'CustomerController@create');
Route::get('customers/{id}', 'ResourceController@get')->defaults('_config', [
Route::get('customers/{id}', 'CustomerController@get')->defaults('_config', [
'repository' => 'Webkul\Customer\Repositories\CustomerRepository',
'resource' => 'Webkul\API\Http\Resources\Customer\Customer',
'authorization_required' => true
@ -246,7 +246,6 @@ Route::group(['prefix' => 'api'], function ($router) {
Route::get('wishlist/add/{id}', 'WishlistController@create');
//Checkout routes
Route::group(['prefix' => 'checkout'], function ($router) {
Route::post('cart/add/{id}', 'CartController@store');
@ -259,6 +258,10 @@ Route::group(['prefix' => 'api'], function ($router) {
Route::get('cart/remove-item/{id}', 'CartController@destroyItem');
Route::post('cart/coupon', 'CartController@applyCoupon');
Route::delete('cart/coupon', 'CartController@removeCoupon');
Route::get('cart/move-to-wishlist/{id}', 'CartController@moveToWishlist');
Route::post('save-address', 'CheckoutController@saveAddress');

View File

@ -1,5 +1,5 @@
{
"name": "webkul/laravel-api",
"name": "bagisto/laravel-api",
"license": "MIT",
"authors": [
{
@ -8,14 +8,14 @@
}
],
"require": {
"webkul/laravel-user": "dev-master",
"webkul/laravel-core": "dev-master",
"webkul/laravel-product": "dev-master",
"webkul/laravel-shop": "dev-master",
"webkul/laravel-category": "dev-master",
"webkul/laravel-tax": "dev-master",
"webkul/laravel-inventory": "dev-master",
"webkul/laravel-checkout": "dev-master"
"bagisto/laravel-user": "dev-master",
"bagisto/laravel-core": "dev-master",
"bagisto/laravel-product": "dev-master",
"bagisto/laravel-shop": "dev-master",
"bagisto/laravel-category": "dev-master",
"bagisto/laravel-tax": "dev-master",
"bagisto/laravel-inventory": "dev-master",
"bagisto/laravel-checkout": "dev-master"
},
"autoload": {
"psr-4": {

View File

@ -194,6 +194,21 @@ return [
'type' => 'boolean',
],
],
], [
'key' => 'catalog.products.attribute',
'name' => 'admin::app.admin.system.attribute',
'sort' => 4,
'fields' => [
[
'name' => 'image_attribute_upload_size',
'title' => 'admin::app.admin.system.image-upload-size',
'type' => 'text',
], [
'name' => 'file_attribute_upload_size',
'title' => 'admin::app.admin.system.file-upload-size',
'type' => 'text',
]
],
], [
'key' => 'catalog.inventory',
'name' => 'admin::app.admin.system.inventory',

View File

@ -187,6 +187,13 @@ class ProductDataGrid extends DataGrid
public function prepareMassActions()
{
$this->addAction([
'title' => trans('admin::app.datagrid.copy'),
'method' => 'GET',
'route' => 'admin.catalog.products.copy',
'icon' => 'icon note-icon',
]);
$this->addMassAction([
'type' => 'delete',
'label' => trans('admin::app.datagrid.delete'),

View File

@ -206,6 +206,7 @@ class CustomerController extends Controller
$this->customerRepository->delete($id);
} else {
session()->flash('error', trans('admin::app.response.order-pending', ['name' => 'Customer']));
return response()->json(['message' => false], 400);
}

View File

@ -211,7 +211,7 @@ class DashboardController extends Controller
/**
* Returns top selling products
*
*
* @return \Illuminate\Support\Collection
*/
public function getTopSellingProducts()
@ -235,10 +235,13 @@ class DashboardController extends Controller
*/
public function getCustomerWithMostSales()
{
$dbPrefix = DB::getTablePrefix();
return $this->orderRepository->getModel()
->select(DB::raw('SUM(base_grand_total) as total_base_grand_total'))
->addSelect(DB::raw('COUNT(id) as total_orders'))
->addSelect('id', 'customer_id', 'customer_email', 'customer_first_name', 'customer_last_name')
->leftJoin('refunds', 'orders.id', 'refunds.order_id')
->select(DB::raw("(SUM({$dbPrefix}orders.base_grand_total) - SUM(IFNULL({$dbPrefix}refunds.base_grand_total, 0))) as total_base_grand_total"))
->addSelect(DB::raw("COUNT({$dbPrefix}orders.id) as total_orders"))
->addSelect('orders.id', 'customer_id', 'customer_email', 'customer_first_name', 'customer_last_name')
->where('orders.created_at', '>=', $this->startDate)
->where('orders.created_at', '<=', $this->endDate)
->where('orders.status', '<>', 'closed')

View File

@ -160,11 +160,6 @@ class InvoiceController extends Controller
$invoice = $this->invoiceRepository->findOrFail($id);
$task = $this->invoiceRepository->updateInvoiceState($invoice, $request->state);
if($request->state == 'paid'){
$order = $this->orderRepository->findOrFail($invoice->order->id);
$this->orderRepository->updateOrderStatus($order);
}
if ($task){
session()->flash('success', trans('admin::app.sales.orders.invoice-status-confirmed'));
} else {

View File

@ -273,6 +273,10 @@ Route::group(['middleware' => ['web']], function () {
'redirect' => 'admin.catalog.products.edit',
])->name('admin.catalog.products.store');
Route::get('products/copy/{id}', 'Webkul\Product\Http\Controllers\ProductController@copy')->defaults('_config', [
'view' => 'admin::catalog.products.edit',
])->name('admin.catalog.products.copy');
Route::get('/products/edit/{id}', 'Webkul\Product\Http\Controllers\ProductController@edit')->defaults('_config', [
'view' => 'admin::catalog.products.edit',
])->name('admin.catalog.products.edit');

View File

@ -1,20 +1,22 @@
<?php
return [
'save' => 'حفظ',
'create' => 'خلق',
'update' => 'تحديث',
'delete' => 'حذف',
'failed' => 'فشل',
'store' => 'متجر',
'image' => 'صورة',
'no result' => 'لا نتيجة',
'product' => 'المنتج',
'attribute' => 'ينسب',
'actions' => 'أجراءات',
'id' => 'ID',
'action' => 'عمل',
'yes' => 'نعم',
'save' => 'حفظ',
'create' => 'خلق',
'update' => 'تحديث',
'delete' => 'حذف',
'copy-of' => 'نسخة من ',
'copy-of-slug' => 'نسخة-من-',
'failed' => 'فشل',
'store' => 'متجر',
'image' => 'صورة',
'no result' => 'لا نتيجة',
'product' => 'المنتج',
'attribute' => 'ينسب',
'actions' => 'أجراءات',
'id' => 'ID',
'action' => 'عمل',
'yes' => 'نعم',
'no' => 'لا',
'true' => 'صحيح',
'false' => 'خاطئة',
@ -138,27 +140,28 @@ return [
'datagrid' => [
'mass-ops' => [
'method-error' => 'خطأ! تم اكتشاف طريقة خاطئة ، الرجاء التحقق من تشكيل حركة الكتلة',
'method-error' => 'خطأ! تم اكتشاف طريقة خاطئة ، الرجاء التحقق من تشكيل حركة الكتلة',
'delete-success' => "تم حذف المورد بنجاح :Selected",
'partial-action' => 'ولم تنفذ بعض الإجراءات بسبب القيود المفروضة على النظام :resource',
'update-success' => "تم تحديث المورد بنجاح :Selected",
'no-resource' => 'المورد المقدم غير كاف للعمل'
'no-resource' => 'المورد المقدم غير كاف للعمل',
],
'id' => 'ID',
'status' => 'الحالة',
'code' => 'رمز',
'admin-name' => 'اسم',
'name' => 'اسم',
'direction' => 'اتجاه',
'fullname' => 'الاسم الكامل',
'type' => 'النوع',
'required' => 'مطلوب',
'unique' => 'فريد',
'per-locale' => 'على أساس اللغة',
'per-channel' => 'قائم على القناة',
'position' => 'موضع',
'locale' => 'لغة',
'id' => 'ID',
'status' => 'الحالة',
'code' => 'رمز',
'admin-name' => 'اسم',
'copy' => 'نسخ',
'name' => 'اسم',
'direction' => 'اتجاه',
'fullname' => 'الاسم الكامل',
'type' => 'النوع',
'required' => 'مطلوب',
'unique' => 'فريد',
'per-locale' => 'على أساس اللغة',
'per-channel' => 'قائم على القناة',
'position' => 'موضع',
'locale' => 'لغة',
'hostname' => 'اسم المضيف',
'email' => 'البريد الإلكتروني',
'group' => 'المجموعة',
@ -1201,17 +1204,20 @@ return [
],
'response' => [
'being-used' => ':source في :name يتم استخدام هذا المورد',
'cannot-delete-default' => 'لا يمكن حذف القناة الافتراضية',
'create-success' => 'إنشاء الاسم بنجاح:name',
'update-success' => 'تحديث الاسم بنجاح :name ',
'delete-success' => 'حذف الاسم بنجاح :name',
'delete-failed' => ':name حدث خطأ أثناء حذف',
'last-delete-error' => 'مطلوب name: واحد على الأقل',
'user-define-error' => 'لا يستطيع حذف نظام :name',
'attribute-error' => 'في المنتجات القابلة للتكوين :name يستخدم ' ,
'attribute-product-error' => 'في المنتجات :name يستخدم ' ,
'customer-associate' => 'لا يمكن حذف :name لأن العميل مرتبط بهذه المجموعة.',
'being-used' => ':source في :name يتم استخدام هذا المورد',
'product-copied' => 'تم نسخ المنتج',
'error-while-copying' => 'خطأ في نسخ المنتج',
'product-can-not-be-copied' => 'لا يمكن نسخ منتجات الحجز',
'cannot-delete-default' => 'لا يمكن حذف القناة الافتراضية',
'create-success' => 'إنشاء الاسم بنجاح:name',
'update-success' => 'تحديث الاسم بنجاح :name ',
'delete-success' => 'حذف الاسم بنجاح :name',
'delete-failed' => ':name حدث خطأ أثناء حذف',
'last-delete-error' => 'مطلوب name: واحد على الأقل',
'user-define-error' => 'لا يستطيع حذف نظام :name',
'attribute-error' => 'في المنتجات القابلة للتكوين :name يستخدم ',
'attribute-product-error' => 'في المنتجات :name يستخدم ',
'customer-associate' => 'لا يمكن حذف :name لأن العميل مرتبط بهذه المجموعة.',
'currency-delete-error' => 'يتم تعيين هذه العملة كعملة أساسية القناة لذلك لا يمكن حذفها.',
'upload-success' => 'بنجاح :name تم تحميل',
'delete-category-root' => 'لا يستطيع حذف الجذر الفئة',

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,19 @@
<?php
return [
'save' => 'Save',
'copy-of' => 'Copy of',
'create' => 'Create',
'update' => 'Update',
'delete' => 'Delete',
'failed' => 'Failed',
'store' => 'Store',
'image' => 'Image',
'no result' => 'No result',
'product' => 'Product',
'attribute' => 'Attribute',
'actions' => 'Actions',
'save' => 'Save',
'copy-of' => 'Copy of ',
'copy-of-slug' => 'copy-of-',
'create' => 'Create',
'update' => 'Update',
'delete' => 'Delete',
'failed' => 'Failed',
'store' => 'Store',
'image' => 'Image',
'no result' => 'No result',
'product' => 'Product',
'attribute' => 'Attribute',
'actions' => 'Actions',
'id' => 'ID',
'action' => 'action',
'yes' => 'Yes',
@ -1209,17 +1210,20 @@ return [
],
'response' => [
'being-used' => 'This resource :name is getting used in :source',
'cannot-delete-default' => 'Cannot delete the default channel',
'create-success' => ':name created successfully.',
'update-success' => ':name updated successfully.',
'delete-success' => ':name deleted successfully.',
'delete-failed' => 'Error encountered while deleting :name.',
'last-delete-error' => 'At least one :name is required.',
'user-define-error' => 'Can not delete system :name',
'attribute-error' => ':name is used in configurable products.',
'attribute-product-error' => ':name is used in products.',
'customer-associate' => ':name can not be deleted because customer is associated with this group.',
'being-used' => 'This resource :name is getting used in :source',
'product-copied' => 'The Product has been copied',
'error-while-copying' => 'Something went wrong while trying to copy the product',
'product-can-not-be-copied' => 'Products of type :type can not be copied',
'cannot-delete-default' => 'Cannot delete the default channel',
'create-success' => ':name created successfully.',
'update-success' => ':name updated successfully.',
'delete-success' => ':name deleted successfully.',
'delete-failed' => 'Error encountered while deleting :name.',
'last-delete-error' => 'At least one :name is required.',
'user-define-error' => 'Can not delete system :name',
'attribute-error' => ':name is used in configurable products.',
'attribute-product-error' => ':name is used in products.',
'customer-associate' => ':name can not be deleted because customer is associated with this group.',
'currency-delete-error' => 'This currency is set as channel base currency so it can not be deleted.',
'upload-success' => ':name uploaded successfully.',
'delete-category-root' => 'Cannot delete the root category',
@ -1258,6 +1262,9 @@ return [
'guest-checkout' => 'Guest Checkout',
'allow-guest-checkout' => 'Allow Guest Checkout',
'allow-guest-checkout-hint' => 'Hint: If turned on, this option can be configured for each product specifically.',
'attribute' => 'Attribute',
'image-upload-size' => 'Allowed Image Upload Size (in Kb)',
'file-upload-size' => 'Allowed File Upload Size (in Kb)',
'review' => 'Review',
'allow-guest-review' => 'Allow Guest Review',
'inventory' => 'Inventory',

View File

@ -146,24 +146,25 @@ return [
'no-resource' => 'The resource provided for insufficient for the action'
],
'id' => 'ID',
'status' => 'Stato',
'code' => 'Codice',
'admin-name' => 'Nome',
'name' => 'Nome',
'direction' => 'Direzione',
'fullname' => 'Nome completo',
'type' => 'Tipo',
'required' => 'Richiesto',
'unique' => 'Unico',
'per-locale' => 'Basato su localizzazione',
'per-channel' => 'Basato sul canale',
'position' => 'Posizione',
'locale' => 'Locale',
'hostname' => 'Hostname',
'email' => 'Email',
'group' => 'Gruppo',
'phone' => 'Telefono',
'id' => 'ID',
'status' => 'Stato',
'code' => 'Codice',
'admin-name' => 'Nome',
'name' => 'Nome',
'direction' => 'Direzione',
'fullname' => 'Nome completo',
'type' => 'Tipo',
'copy' => 'Copia',
'required' => 'Richiesto',
'unique' => 'Unico',
'per-locale' => 'Basato su localizzazione',
'per-channel' => 'Basato sul canale',
'position' => 'Posizione',
'locale' => 'Locale',
'hostname' => 'Hostname',
'email' => 'Email',
'group' => 'Gruppo',
'phone' => 'Telefono',
'gender' => 'Sesso',
'title' => 'Titolo',
'layout' => 'Layout',

View File

@ -146,24 +146,25 @@ return [
'no-resource' => 'The resource provided for insufficient for the action'
],
'id' => 'ID',
'status' => 'Status',
'code' => 'Code',
'admin-name' => 'Naam',
'name' => 'Naam',
'direction' => 'Richting',
'fullname' => 'Volledige naam',
'type' => 'Type',
'required' => 'Verplicht',
'unique' => 'Uniek',
'per-locale' => 'Lokaal gebaseerd',
'per-channel' => 'Kanaal gebaseerd',
'position' => 'Position',
'locale' => 'Locale',
'hostname' => 'Hostnaam',
'email' => 'Email',
'group' => 'Groep',
'phone' => 'Telefoon',
'id' => 'ID',
'status' => 'Status',
'code' => 'Code',
'admin-name' => 'Naam',
'name' => 'Naam',
'direction' => 'Richting',
'fullname' => 'Volledige naam',
'type' => 'Type',
'copy' => 'kopiëren',
'required' => 'Verplicht',
'unique' => 'Uniek',
'per-locale' => 'Lokaal gebaseerd',
'per-channel' => 'Kanaal gebaseerd',
'position' => 'Position',
'locale' => 'Locale',
'hostname' => 'Hostnaam',
'email' => 'Email',
'group' => 'Groep',
'phone' => 'Telefoon',
'gender' => 'Geslacht',
'title' => 'Titel',
'layout' => 'Layout',

View File

@ -4,12 +4,15 @@
.table th.price, .table th.weight {
width: 100px;
}
.table th.actions {
width: 85px;
}
.table td.actions .icon {
margin-top: 8px;
}
.table td.actions .icon.pencil-lg-icon {
margin-right: 10px;
}
@ -48,17 +51,31 @@
@parent
<script type="text/x-template" id="variant-form-template">
<form method="POST" action="{{ route('admin.catalog.products.store') }}" data-vv-scope="add-variant-form" @submit.prevent="addVariant('add-variant-form')">
<form method="POST" action="{{ route('admin.catalog.products.store') }}"
data-vv-scope="add-variant-form" @submit.prevent="addVariant('add-variant-form')">
<div class="page-content">
<div class="form-container">
<div v-for='(attribute, index) in super_attributes' class="control-group" :class="[errors.has('add-variant-form.' + attribute.code) ? 'has-error' : '']">
<label :for="attribute.code" class="required">@{{ attribute.admin_name }}</label>
<select v-validate="'required'" v-model="variant[attribute.code]" class="control" :id="attribute.code" :name="attribute.code" :data-vv-as="'&quot;' + attribute.admin_name + '&quot;'">
<option v-for='(option, index) in attribute.options' :value="option.id">@{{ option.admin_name }}</option>
<div v-for='(attribute, index) in super_attributes' class="control-group"
:class="[errors.has('add-variant-form.' + attribute.code) ? 'has-error' : '']"
>
<label :for="attribute.code" class="required">@{{ attribute.admin_name
}}</label>
<select
v-validate="'required'"
v-model="variant[attribute.code]"
class="control"
:id="attribute.code"
:name="attribute.code"
:data-vv-as="'&quot;' + attribute.admin_name + '&quot;'"
>
<option v-for='(option, index) in attribute.options' :value="option.id">
@{{ option.admin_name }}
</option>
</select>
<span class="control-error" v-if="errors.has('add-variant-form.' + attribute.code)">@{{ errors.first('add-variant-form.' + attribute.code) }}</span>
<span class="control-error"
v-if="errors.has('add-variant-form.' + attribute.code)">@{{ errors.first('add-variant-form.' + attribute.code) }}</span>
</div>
<button type="submit" class="btn btn-lg btn-primary">
@ -76,25 +93,28 @@
<table>
<thead>
<tr>
<th class="sku">{{ __('admin::app.catalog.products.sku') }}</th>
<th>{{ __('admin::app.catalog.products.name') }}</th>
<tr>
<th class="sku">{{ __('admin::app.catalog.products.sku') }}</th>
<th>{{ __('admin::app.catalog.products.name') }}</th>
@foreach ($product->super_attributes as $attribute)
<th class="{{ $attribute->code }}" style="width: 150px">{{ $attribute->admin_name }}</th>
@endforeach
@foreach ($product->super_attributes as $attribute)
<th class="{{ $attribute->code }}"
style="width: 150px">{{ $attribute->admin_name }}</th>
@endforeach
<th class="qty">{{ __('admin::app.catalog.products.qty') }}</th>
<th class="price">{{ __('admin::app.catalog.products.price') }}</th>
<th class="weight">{{ __('admin::app.catalog.products.weight') }}</th>
<th class="status">{{ __('admin::app.catalog.products.status') }}</th>
<th class="actions"></th>
</tr>
<th class="qty">{{ __('admin::app.catalog.products.qty') }}</th>
<th class="price">{{ __('admin::app.catalog.products.price') }}</th>
<th class="weight">{{ __('admin::app.catalog.products.weight') }}</th>
<th class="status">{{ __('admin::app.catalog.products.status') }}</th>
<th class="actions"></th>
</tr>
</thead>
<tbody>
<variant-item v-for='(variant, index) in variants' :variant="variant" :key="index" :index="variant.id" @onRemoveVariant="removeVariant($event)"></variant-item>
<variant-item v-for='(variant, index) in variants' :variant="variant" :key="index"
:index="variant.id"
@onRemoveVariant="removeVariant($event)"></variant-item>
</tbody>
@ -105,23 +125,32 @@
<script type="text/x-template" id="variant-item-template">
<tr>
<td>
<div class="control-group" :class="[errors.has(variantInputName + '[sku]') ? 'has-error' : '']">
<input type="text" v-validate="'required'" v-model="variant.sku" :name="[variantInputName + '[sku]']" class="control" data-vv-as="&quot;{{ __('admin::app.catalog.products.sku') }}&quot;" v-slugify/>
<div class="control-group"
:class="[errors.has(variantInputName + '[sku]') ? 'has-error' : '']">
<input type="text" v-validate="'required'" v-model="variant.sku"
:name="[variantInputName + '[sku]']" class="control"
data-vv-as="&quot;{{ __('admin::app.catalog.products.sku') }}&quot;"
v-slugify/>
<span class="control-error" v-if="errors.has(variantInputName + '[sku]')">@{{ errors.first(variantInputName + '[sku]') }}</span>
</div>
</td>
<td>
<div class="control-group" :class="[errors.has(variantInputName + '[name]') ? 'has-error' : '']">
<input type="text" v-validate="'required'" v-model="variant.name" :name="[variantInputName + '[name]']" class="control" data-vv-as="&quot;{{ __('admin::app.catalog.products.name') }}&quot;"/>
<div class="control-group"
:class="[errors.has(variantInputName + '[name]') ? 'has-error' : '']">
<input type="text" v-validate="'required'" v-model="variant.name"
:name="[variantInputName + '[name]']" class="control"
data-vv-as="&quot;{{ __('admin::app.catalog.products.name') }}&quot;"/>
<span class="control-error" v-if="errors.has(variantInputName + '[name]')">@{{ errors.first(variantInputName + '[name]') }}</span>
</div>
</td>
<td v-for='(attribute, index) in superAttributes'>
<div class="control-group">
<input type="hidden" :name="[variantInputName + '[' + attribute.code + ']']" :value="variant[attribute.code]"/>
<input type="text" class="control" :value="optionName(variant[attribute.code])" readonly/>
<input type="hidden" :name="[variantInputName + '[' + attribute.code + ']']"
:value="variant[attribute.code]"/>
<input type="text" class="control" :value="optionName(variant[attribute.code])"
readonly/>
</div>
</td>
@ -135,10 +164,16 @@
<div class="dropdown-container">
<ul>
<li v-for='(inventorySource, index) in inventorySources'>
<div class="control-group" :class="[errors.has(variantInputName + '[inventories][' + inventorySource.id + ']') ? 'has-error' : '']">
<div class="control-group"
:class="[errors.has(variantInputName + '[inventories][' + inventorySource.id + ']') ? 'has-error' : '']">
<label>@{{ inventorySource.name }}</label>
<input type="text" v-validate="'numeric|min:0'" :name="[variantInputName + '[inventories][' + inventorySource.id + ']']" v-model="inventories[inventorySource.id]" class="control" v-on:keyup="updateTotalQty()" :data-vv-as="'&quot;' + inventorySource.name + '&quot;'"/>
<span class="control-error" v-if="errors.has(variantInputName + '[inventories][' + inventorySource.id + ']')">@{{ errors.first(variantInputName + '[inventories][' + inventorySource.id + ']') }}</span>
<input type="text" v-validate="'numeric|min:0'"
:name="[variantInputName + '[inventories][' + inventorySource.id + ']']"
v-model="inventories[inventorySource.id]" class="control"
v-on:keyup="updateTotalQty()"
:data-vv-as="'&quot;' + inventorySource.name + '&quot;'"/>
<span class="control-error"
v-if="errors.has(variantInputName + '[inventories][' + inventorySource.id + ']')">@{{ errors.first(variantInputName + '[inventories][' + inventorySource.id + ']') }}</span>
</div>
</li>
</ul>
@ -147,30 +182,42 @@
</td>
<td>
<div class="control-group" :class="[errors.has(variantInputName + '[price]') ? 'has-error' : '']">
<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"/>
<div class="control-group"
:class="[errors.has(variantInputName + '[price]') ? 'has-error' : '']">
<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'" v-model="variant.weight" :name="[variantInputName + '[weight]']" class="control" data-vv-as="&quot;{{ __('admin::app.catalog.products.weight') }}&quot;" step="any"/>
<div class="control-group"
:class="[errors.has(variantInputName + '[weight]') ? 'has-error' : '']">
<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>
<td>
<div class="control-group">
<select type="text" v-model="variant.status" :name="[variantInputName + '[status]']" class="control">
<option value="1" :selected="variant.status">{{ __('admin::app.catalog.products.enabled') }}</option>
<option value="0" :selected="!variant.status">{{ __('admin::app.catalog.products.disabled') }}</option>
<select type="text" v-model="variant.status"
:name="[variantInputName + '[status]']" class="control">
<option value="1"
:selected="variant.status">{{ __('admin::app.catalog.products.enabled') }}</option>
<option value="0"
:selected="!variant.status">{{ __('admin::app.catalog.products.disabled') }}</option>
</select>
</div>
</td>
<td class="actions">
<a :href="['{{ route('admin.catalog.products.index') }}/edit/' + variant.id]"><i class="icon pencil-lg-icon"></i></a>
<a :href="['{{ route('admin.catalog.products.index') }}/edit/' + variant.id]"><i
class="icon pencil-lg-icon"></i></a>
<i class="icon remove-icon" @click="removeVariant()"></i>
</td>
</tr>
@ -190,7 +237,7 @@
Vue.component('variant-form', {
data: function() {
data: function () {
return {
variant: {},
super_attributes: super_attributes
@ -209,7 +256,7 @@
if (result) {
var this_this = this;
var filteredVariants = variants.filter(function(variant) {
var filteredVariants = variants.filter(function (variant) {
var matchCount = 0;
for (var key in this_this.variant) {
@ -224,7 +271,10 @@
if (filteredVariants.length) {
this.$parent.closeModal();
window.flashMessages = [{'type': 'alert-error', 'message': "{{ __('admin::app.catalog.products.variant-already-exist-message') }}" }];
window.flashMessages = [{
'type': 'alert-error',
'message': "{{ __('admin::app.catalog.products.variant-already-exist-message') }}"
}];
this.$root.addFlashMessages()
} else {
@ -234,12 +284,12 @@
}
variants.push(Object.assign({
sku: '{{ $product->sku }}' + '-variant-' + optionIds.join('-'),
name: '',
price: 0,
weight: 0,
status: 1
}, this.variant));
sku: '{{ $product->sku }}' + '-variant-' + optionIds.join('-'),
name: '',
price: 0,
weight: 0,
status: 1
}, this.variant));
this.resetModel();
@ -252,7 +302,7 @@
resetModel: function () {
var this_this = this;
this.super_attributes.forEach(function(attribute) {
this.super_attributes.forEach(function (attribute) {
this_this.variant[attribute.code] = '';
})
}
@ -265,7 +315,7 @@
inject: ['$validator'],
data: function() {
data: function () {
return {
variants: variants,
@ -285,7 +335,10 @@
var inventories = [];
for (var inventorySourceId in variant['inventories']) {
inventories.push({'qty': variant['inventories'][inventorySourceId], 'inventory_source_id': inventorySourceId})
inventories.push({
'qty': variant['inventories'][inventorySourceId],
'inventory_source_id': inventorySourceId
})
}
variant['inventories'] = inventories;
@ -299,7 +352,10 @@
variants[index][code] = [];
for (var inventorySourceId in variant[code]) {
variants[index][code].push({'qty': variant[code][inventorySourceId], 'inventory_source_id': inventorySourceId})
variants[index][code].push({
'qty': variant[code][inventorySourceId],
'inventory_source_id': inventorySourceId
})
}
}
}
@ -310,7 +366,7 @@
},
methods: {
removeVariant: function(variant) {
removeVariant: function (variant) {
let index = this.variants.indexOf(variant)
this.variants.splice(index, 1)
@ -327,7 +383,7 @@
inject: ['$validator'],
data: function() {
data: function () {
return {
inventorySources: @json($inventorySources),
inventories: {},
@ -339,7 +395,7 @@
created: function () {
var this_this = this;
this.inventorySources.forEach(function(inventorySource) {
this.inventorySources.forEach(function (inventorySource) {
this_this.inventories[inventorySource.id] = this_this.sourceInventoryQty(inventorySource.id)
this_this.totalQty += parseInt(this_this.inventories[inventorySource.id]);
})
@ -362,8 +418,8 @@
optionName: function (optionId) {
var optionName = '';
this.superAttributes.forEach(function(attribute) {
attribute.options.forEach(function(option) {
this.superAttributes.forEach(function (attribute) {
attribute.options.forEach(function (option) {
if (optionId == option.id) {
optionName = option.admin_name;
}
@ -374,10 +430,10 @@
},
sourceInventoryQty: function (inventorySourceId) {
if (! Array.isArray(this.variant.inventories))
if (!Array.isArray(this.variant.inventories))
return 0;
var inventories = this.variant.inventories.filter(function(inventory) {
var inventories = this.variant.inventories.filter(function (inventory) {
return inventorySourceId === parseInt(inventory.inventory_source_id);
})

View File

@ -91,6 +91,16 @@
array_push($validations, 'decimal');
}
if ($attribute->type == 'file') {
$retVal = (core()->getConfigData('catalog.products.attribute.file_attribute_upload_size')) ? core()->getConfigData('catalog.products.attribute.file_attribute_upload_size') : '2048' ;
array_push($validations, 'size:' . $retVal);
}
if ($attribute->type == 'image') {
$retVal = (core()->getConfigData('catalog.products.attribute.image_attribute_upload_size')) ? core()->getConfigData('catalog.products.attribute.image_attribute_upload_size') : '2048' ;
array_push($validations, 'size:' . $retVal . '|mimes:jpeg, bmp, png, jpg');
}
array_push($validations, $attribute->validation);
$validations = implode('|', array_filter($validations));

View File

@ -129,15 +129,17 @@
<tbody>
<tr>
<td>
<p>{{ $invoice->order->billing_address->company_name ?? '' }}</p>
<p>{{ $invoice->order->billing_address->name }}</p>
<p>{{ $invoice->order->billing_address->address1 }}</p>
<p>{{ $invoice->order->billing_address->city }}</p>
<p>{{ $invoice->order->billing_address->state }}</p>
<p>{{ core()->country_name($invoice->order->billing_address->country) }} {{ $invoice->order->billing_address->postcode }}</p>
{{ __('shop::app.checkout.onepage.contact') }} : {{ $invoice->order->billing_address->phone }}
</td>
@if ($invoice->order->billing_address)
<td>
<p>{{ $invoice->order->billing_address->company_name ?? '' }}</p>
<p>{{ $invoice->order->billing_address->name }}</p>
<p>{{ $invoice->order->billing_address->address1 }}</p>
<p>{{ $invoice->order->billing_address->city }}</p>
<p>{{ $invoice->order->billing_address->state }}</p>
<p>{{ core()->country_name($invoice->order->billing_address->country) }} {{ $invoice->order->billing_address->postcode }}</p>
{{ __('shop::app.checkout.onepage.contact') }} : {{ $invoice->order->billing_address->phone }}
</td>
@endif
@if ($invoice->order->shipping_address)
<td>

View File

@ -107,14 +107,14 @@
<div class="section-content">
<div class="row">
<span class="title">{{ __('admin::app.sales.orders.customer-name') }}</span>
<span class="value">{{ $invoice->address->name }}</span>
<span class="value">{{ $invoice->order->customer_full_name }}</span>
</div>
{!! view_render_event('sales.invoice.customer_name.after', ['order' => $order]) !!}
<div class="row">
<span class="title">{{ __('admin::app.sales.orders.email') }}</span>
<span class="value">{{ $invoice->address->email }}</span>
<span class="value">{{ $invoice->order->customer_email }}</span>
</div>
{!! view_render_event('sales.invoice.customer_email.after', ['order' => $order]) !!}
@ -124,36 +124,40 @@
</div>
</accordian>
<accordian :title="'{{ __('admin::app.sales.orders.address') }}'" :active="true">
<div slot="body" style="display: flex; overflow:auto;">
@if ($order->billing_address || $order->shipping_address)
<accordian :title="'{{ __('admin::app.sales.orders.address') }}'" :active="true">
<div slot="body" style="display: flex; overflow:auto;">
<div class="sale-section">
<div class="secton-title" style="width: 380px;">
<span>{{ __('admin::app.sales.orders.billing-address') }}</span>
</div>
@if ($order->billing_address)
<div class="sale-section">
<div class="secton-title" style="width: 380px;">
<span>{{ __('admin::app.sales.orders.billing-address') }}</span>
</div>
<div class="section-content" style="width: 380px;">
@include ('admin::sales.address', ['address' => $order->billing_address])
<div class="section-content" style="width: 380px;">
@include ('admin::sales.address', ['address' => $order->billing_address])
{!! view_render_event('sales.invoice.billing_address.after', ['order' => $order]) !!}
</div>
{!! view_render_event('sales.invoice.billing_address.after', ['order' => $order]) !!}
</div>
</div>
@endif
@if ($order->shipping_address)
<div class="sale-section" style="margin: 0 0 0 300px;">
<div class="secton-title" style="width: 400px;">
<span>{{ __('admin::app.sales.orders.shipping-address') }}</span>
</div>
<div class="section-content" style="width: 400px;">
@include ('admin::sales.address', ['address' => $order->shipping_address])
{!! view_render_event('sales.invoice.shipping_address.after', ['order' => $order]) !!}
</div>
</div>
@endif
</div>
@if ($order->shipping_address)
<div class="sale-section" style="margin: 0 0 0 300px;">
<div class="secton-title" style="width: 400px;">
<span>{{ __('admin::app.sales.orders.shipping-address') }}</span>
</div>
<div class="section-content" style="width: 400px;">
@include ('admin::sales.address', ['address' => $order->shipping_address])
{!! view_render_event('sales.invoice.shipping_address.after', ['order' => $order]) !!}
</div>
</div>
@endif
</div>
</accordian>
</accordian>
@endif
<accordian :title="'{{ __('admin::app.sales.orders.products-ordered') }}'" :active="true">
<div slot="body">

View File

@ -284,6 +284,7 @@
<tbody>
@foreach ($order->items as $item)
<tr>
<td>
{{ $item->getTypeInstance()->getOrderedItem($item)->sku }}
@ -467,13 +468,12 @@
</thead>
<tbody>
@foreach ($order->invoices as $invoice)
<tr>
<td>#{{ $invoice->id }}</td>
<td>{{ $invoice->created_at }}</td>
<td>#{{ $invoice->order->increment_id }}</td>
<td>{{ $invoice->address->name }}</td>
<td>{{ $invoice->order->customer_full_name }}</td>
<td>
@if($invoice->state == "paid")
{{ __('admin::app.sales.orders.invoice-status-paid') }}
@ -502,49 +502,47 @@
</tab>
@if ($order->shipping_address)
<tab name="{{ __('admin::app.sales.orders.shipments') }}">
<tab name="{{ __('admin::app.sales.orders.shipments') }}">
<div class="table" style="padding: 20px 0">
<table>
<thead>
<div class="table" style="padding: 20px 0">
<table>
<thead>
<tr>
<th>{{ __('admin::app.sales.shipments.id') }}</th>
<th>{{ __('admin::app.sales.shipments.date') }}</th>
<th>{{ __('admin::app.sales.shipments.carrier-title') }}</th>
<th>{{ __('admin::app.sales.shipments.tracking-number') }}</th>
<th>{{ __('admin::app.sales.shipments.total-qty') }}</th>
<th>{{ __('admin::app.sales.shipments.action') }}</th>
</tr>
</thead>
<tbody>
@foreach ($order->shipments as $shipment)
<tr>
<th>{{ __('admin::app.sales.shipments.id') }}</th>
<th>{{ __('admin::app.sales.shipments.date') }}</th>
<th>{{ __('admin::app.sales.shipments.carrier-title') }}</th>
<th>{{ __('admin::app.sales.shipments.tracking-number') }}</th>
<th>{{ __('admin::app.sales.shipments.total-qty') }}</th>
<th>{{ __('admin::app.sales.shipments.action') }}</th>
<td>#{{ $shipment->id }}</td>
<td>{{ $shipment->created_at }}</td>
<td>{{ $shipment->carrier_title }}</td>
<td>{{ $shipment->track_number }}</td>
<td>{{ $shipment->total_qty }}</td>
<td class="action">
<a href="{{ route('admin.sales.shipments.view', $shipment->id) }}">
<i class="icon eye-icon"></i>
</a>
</td>
</tr>
</thead>
@endforeach
<tbody>
@if (! $order->shipments->count())
<tr>
<td class="empty" colspan="7">{{ __('admin::app.common.no-result-found') }}</td>
<tr>
@endif
</table>
</div>
@foreach ($order->shipments as $shipment)
<tr>
<td>#{{ $shipment->id }}</td>
<td>{{ $shipment->created_at }}</td>
<td>{{ $shipment->carrier_title }}</td>
<td>{{ $shipment->track_number }}</td>
<td>{{ $shipment->total_qty }}</td>
<td class="action">
<a href="{{ route('admin.sales.shipments.view', $shipment->id) }}">
<i class="icon eye-icon"></i>
</a>
</td>
</tr>
@endforeach
@if (! $order->shipments->count())
<tr>
<td class="empty" colspan="7">{{ __('admin::app.common.no-result-found') }}</td>
<tr>
@endif
</table>
</div>
</tab>
@endif
</tab>
<tab name="{{ __('admin::app.sales.orders.refunds') }}">

View File

@ -110,37 +110,41 @@
</div>
</accordian>
<accordian :title="'{{ __('admin::app.sales.orders.address') }}'" :active="true">
<div slot="body">
@if ($order->billing_address || $order->shipping_address)
<accordian :title="'{{ __('admin::app.sales.orders.address') }}'" :active="true">
<div slot="body">
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.billing-address') }}</span>
</div>
@if ($order->billing_address)
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.billing-address') }}</span>
</div>
<div class="section-content">
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->billing_address])
@include ('admin::sales.address', ['address' => $order->billing_address])
</div>
</div>
@endif
@if ($order->shipping_address)
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.shipping-address') }}</span>
</div>
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->shipping_address])
</div>
</div>
@endif
</div>
</div>
@if ($order->shipping_address)
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.shipping-address') }}</span>
</div>
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->shipping_address])
</div>
</div>
@endif
</div>
</accordian>
</accordian>
@endif
<accordian :title="'{{ __('admin::app.sales.orders.payment-and-shipping') }}'" :active="true">
<div slot="body">

View File

@ -87,7 +87,7 @@
</span>
<span class="value">
{{ $shipment->address->name }}
{{ $shipment->order->customer_full_name }}
</span>
</div>
@ -97,7 +97,7 @@
</span>
<span class="value">
{{ $shipment->address->email }}
{{ $shipment->order->customer_email }}
</span>
</div>
</div>
@ -106,37 +106,41 @@
</div>
</accordian>
<accordian :title="'{{ __('admin::app.sales.orders.address') }}'" :active="true">
<div slot="body">
@if ($order->billing_address || $order->shipping_address)
<accordian :title="'{{ __('admin::app.sales.orders.address') }}'" :active="true">
<div slot="body">
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.billing-address') }}</span>
</div>
@if ($order->billing_address)
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.billing-address') }}</span>
</div>
<div class="section-content">
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->billing_address])
@include ('admin::sales.address', ['address' => $order->billing_address])
</div>
</div>
@endif
@if ($order->shipping_address)
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.shipping-address') }}</span>
</div>
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->shipping_address])
</div>
</div>
@endif
</div>
</div>
@if ($order->shipping_address)
<div class="sale-section">
<div class="secton-title">
<span>{{ __('admin::app.sales.orders.shipping-address') }}</span>
</div>
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->shipping_address])
</div>
</div>
@endif
</div>
</accordian>
</accordian>
@endif
<accordian :title="'{{ __('admin::app.sales.orders.payment-and-shipping') }}'" :active="true">
<div slot="body">

View File

@ -143,9 +143,9 @@
<div class="control-group">
<label for="theme">{{ __('admin::app.settings.channels.theme') }}</label>
<select class="control" id="theme" name="theme">
@foreach (themes()->all() as $theme)
<option value="{{ $theme->code }}" {{ old('theme') == $theme->code ? 'selected' : '' }}>
{{ $theme->name }}
@foreach (config('themes.themes') as $themeCode => $theme)
<option value="{{ $themeCode }}" {{ old('theme') == $themeCode ? 'selected' : '' }}>
{{ $theme['name'] }}
</option>
@endforeach
</select>

View File

@ -154,9 +154,9 @@
<?php $selectedOption = old('theme') ?: $channel->theme ?>
<select class="control" id="theme" name="theme">
@foreach (themes()->all() as $theme)
<option value="{{ $theme->code }}" {{ $selectedOption == $theme->code ? 'selected' : '' }}>
{{ $theme->name }}
@foreach (config('themes.themes') as $themeCode => $theme)
<option value="{{ $themeCode }}" {{ $selectedOption == $themeCode ? 'selected' : '' }}>
{{ $theme['name'] }}
</option>
@endforeach
</select>

View File

@ -8,7 +8,6 @@
}
],
"require": {
"nwidart/laravel-modules": "^3.2",
"bagisto/laravel-core": "dev-master"
},
"autoload": {

View File

@ -24,6 +24,16 @@ class AttributeFamily extends Model implements AttributeFamilyContract
->select('attributes.*');
}
/**
* Get all of the comparable attributes which belongs to attribute family.
*/
public function getComparableAttributesBelongsToFamily()
{
return (AttributeProxy::modelClass())::join('attribute_group_mappings', 'attribute_group_mappings.attribute_id', '=', 'attributes.id')
->select('attributes.*')->where('attributes.is_comparable', 1)->get();
}
/**
* Get all of the attributes for the attribute groups.
*/

View File

@ -8,8 +8,10 @@ use Webkul\BookingProduct\Models\BookingProduct;
use Webkul\Product\Models\Product;
$factory->define(BookingProduct::class, function (Faker $faker, array $attributes) {
$bookingTypes = ['event'];
return [
'type' => array_rand(['event']),
'type' => $bookingTypes[array_rand(['event'])],
'qty' => $faker->randomNumber(2),
'available_from' => Carbon::yesterday(),
'available_to' => Carbon::tomorrow(),

View File

@ -2,19 +2,19 @@
namespace Webkul\BookingProduct\Type;
use Carbon\Carbon;
use Illuminate\Support\Arr;
use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Product\Datatypes\CartItemValidationResult;
use Webkul\Product\Repositories\ProductRepository;
use Webkul\Product\Repositories\ProductAttributeValueRepository;
use Webkul\Product\Repositories\ProductInventoryRepository;
use Webkul\Product\Repositories\ProductImageRepository;
use Webkul\Product\Helpers\ProductImage;
use Webkul\BookingProduct\Repositories\BookingProductRepository;
use Webkul\BookingProduct\Helpers\Booking as BookingHelper;
use Webkul\Product\Type\Virtual;
use Carbon\Carbon;
use Webkul\BookingProduct\Repositories\BookingProductRepository;
use Webkul\Checkout\Models\CartItem;
use Webkul\Product\Datatypes\CartItemValidationResult;
use Webkul\Product\Helpers\ProductImage;
use Webkul\Product\Repositories\ProductAttributeValueRepository;
use Webkul\Product\Repositories\ProductImageRepository;
use Webkul\Product\Repositories\ProductInventoryRepository;
use Webkul\Product\Repositories\ProductRepository;
use Webkul\Product\Type\Virtual;
class Booking extends Virtual
{
@ -32,6 +32,9 @@ class Booking extends Virtual
*/
protected $bookingHelper;
/** @var bool do not allow booking products to be copied, it would be too complicated. */
protected $canBeCopied = false;
/**
* @var array
*/
@ -46,11 +49,11 @@ class Booking extends Virtual
/**
* Create a new product type instance.
*
* @param \Webkul\Attribute\Repositories\AttributeRepository $attributeRepository
* @param \Webkul\Product\Repositories\ProductRepository $productRepository
* @param \Webkul\Product\Repositories\ProductAttributeValueRepository $attributeValueRepository
* @param \Webkul\Product\Repositories\ProductInventoryRepository $productInventoryRepository
* @param \Webkul\Product\Repositories\ProductImageRepository $productImageRepository
* @param \Webkul\Attribute\Repositories\AttributeRepository $attributeRepository
* @param \Webkul\Product\Repositories\ProductRepository $productRepository
* @param \Webkul\Product\Repositories\ProductAttributeValueRepository $attributeValueRepository
* @param \Webkul\Product\Repositories\ProductInventoryRepository $productInventoryRepository
* @param \Webkul\Product\Repositories\ProductImageRepository $productImageRepository
* @param \Webkul\Product\Helpers\ProductImage $productImageHelper
* @param \Webkul\BookingProduct\Repositories\BookingProductRepository $bookingProductRepository
* @param \Webkul\BookingProduct\Helpers\BookingHelper $bookingHelper
@ -197,13 +200,8 @@ class Booking extends Virtual
continue;
}
$cartProducts = parent::prepareForCart(array_merge($data, [
'product_id' => $data['product_id'],
'quantity' => $qty,
'booking' => [
'ticket_id' => $ticketId,
],
]));
$data['booking']['ticket_id'] = $ticketId;
$cartProducts = parent::prepareForCart($data);
if (is_string($cartProducts)) {
return $cartProducts;

View File

@ -7,9 +7,7 @@
"email": "prashant.singh852@webkul.com"
}
],
"require": {
"konekt/concord": "^1.2"
},
"require": {},
"autoload": {
"psr-4": {
"Webkul\\CMS\\": "src/"

View File

@ -0,0 +1,36 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
/**
* Hack core: Change the migration
* Added by AuTN
*/
class UpdateCmsPageTranslationsTableFieldHtmlContent extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('cms_page_translations', function (Blueprint $table) {
$table->longtext('html_content')->nullable()->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('cms_page_translations', function (Blueprint $table) {
$table->text('html_content')->nullable()->change();
});
}
}

View File

@ -275,19 +275,23 @@ class CartRule
break;
case 'cart_fixed':
if ($this->itemTotals[$rule->id]['total_items'] <= 1) {
$discountAmount = core()->convertPrice($rule->discount_amount);
// if ($this->itemTotals[$rule->id]['total_items'] <= 1) {
// $discountAmount = core()->convertPrice($rule->discount_amount);
$baseDiscountAmount = min($item->base_price * $quantity, $rule->discount_amount);
} else {
$discountRate = $item->base_price * $quantity / $this->itemTotals[$rule->id]['base_total_price'];
// $baseDiscountAmount = min($item->base_price * $quantity, $rule->discount_amount);
// } else {
// $discountRate = $item->base_price * $quantity / $this->itemTotals[$rule->id]['base_total_price'];
$maxDiscount = $rule->discount_amount * $discountRate;
// $maxDiscount = $rule->discount_amount * $discountRate;
$discountAmount = core()->convertPrice($maxDiscount);
// $discountAmount = core()->convertPrice($maxDiscount);
$baseDiscountAmount = min($item->base_price * $quantity, $maxDiscount);
}
// $baseDiscountAmount = min($item->base_price * $quantity, $maxDiscount);
// }
$discountAmount = core()->convertPrice($rule->discount_amount);
$baseDiscountAmount = min($item->base_price * $quantity, $rule->discount_amount);
$discountAmount = min($item->price * $quantity, $discountAmount);

View File

@ -2,6 +2,7 @@
namespace Webkul\CartRule\Http\Controllers;
use Exception;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Event;
@ -87,7 +88,7 @@ class CartRuleController extends Controller
->replicate()
->fill([
'status' => 0,
'name' => __('admin::app.copy-of') . ' ' . $originalCartRule->name,
'name' => __('admin::app.copy-of') . $originalCartRule->name,
]);
$copiedCartRule->save();
@ -209,7 +210,7 @@ class CartRuleController extends Controller
session()->flash('success', trans('admin::app.response.delete-success', ['name' => 'Cart Rule']));
return response()->json(['message' => true], 200);
} catch (\Exception $e) {
} catch (Exception $e) {
session()->flash('error', trans('admin::app.response.delete-failed', ['name' => 'Cart Rule']));
}

View File

@ -7,9 +7,7 @@
"email": "jitendra@webkul.com"
}
],
"require": {
"baum/baum": "~1.1"
},
"require": {},
"autoload": {
"psr-4": {
"Webkul\\Category\\": "src/"

View File

@ -343,9 +343,9 @@ class Cart
/**
* This function handles when guest has some of cart products and then logs in.
*
* @return bool
* @return void
*/
public function mergeCart()
public function mergeCart(): void
{
if (session()->has('cart')) {
$cart = $this->cartRepository->findOneWhere([
@ -367,59 +367,11 @@ class Cart
session()->forget('cart');
return true;
return;
}
foreach ($guestCart->items as $key => $guestCartItem) {
$found = false;
foreach ($cart->items as $cartItem) {
if (! $cartItem
->product
->getTypeInstance()
->compareOptions($cartItem->additional, $guestCartItem->additional)
) {
continue;
}
$found = true;
$cartItem->quantity = $newQuantity = $cartItem->quantity + $guestCartItem->quantity;
if ($cartItem->quantity > $cartItem->product->getTypeInstance()->totalQuantity()) {
$cartItem->quantity = $newQuantity = $cartItem->product->getTypeInstance()->totalQuantity();
}
if (! $this->isItemHaveQuantity($cartItem)) {
$this->cartItemRepository->delete($guestCartItem->id);
continue;
}
$this->cartItemRepository->update([
'quantity' => $newQuantity,
'total' => core()->convertPrice($cartItem->price * $newQuantity),
'base_total' => $cartItem->price * $newQuantity,
'total_weight' => $cartItem->weight * $newQuantity,
'base_total_weight' => $cartItem->weight * $newQuantity,
], $cartItem->id);
$guestCart->items->forget($key);
$this->cartItemRepository->delete($guestCartItem->id);
}
if (! $found) {
$this->cartItemRepository->update([
'cart_id' => $cart->id,
], $guestCartItem->id);
foreach ($guestCartItem->children as $child) {
$this->cartItemRepository->update([
'cart_id' => $cart->id,
], $child->id);
}
}
foreach ($guestCart->items as $guestCartItem) {
$this->addProduct($guestCartItem->product_id, $guestCartItem->additional);
}
$this->collectTotals();
@ -428,8 +380,6 @@ class Cart
session()->forget('cart');
}
return true;
}
/**

View File

@ -7,8 +7,7 @@
"email": "jitendra@webkul.com"
}
],
"require": {
},
"require": {},
"autoload": {
"psr-4": {
"Webkul\\Core\\": "src/"

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RemovingForiegnKey extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('invoices', static function (Blueprint $table) {
$table->dropForeign(['order_address_id']);
});
Schema::table('shipments', static function (Blueprint $table) {
$table->dropForeign(['order_address_id']);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
}
}

View File

@ -7,9 +7,7 @@
"email": "jitendra@webkul.com"
}
],
"require": {
"propaganistas/laravel-intl": "^2.0"
},
"require": {},
"autoload": {
"psr-4": {
"Webkul\\Inventory\\": "src/"

View File

@ -10,7 +10,7 @@
"require": {},
"autoload": {
"psr-4": {
"Webkul\\Payment\\": "src/"
"Webkul\\Paypal\\": "src/"
}
},
"extra": {

View File

@ -2,16 +2,20 @@
namespace Webkul\Product\Http\Controllers;
use Exception;
use Webkul\Product\Models\Product;
use Illuminate\Support\Facades\Event;
use Webkul\Product\Http\Requests\ProductForm;
use Illuminate\Support\Facades\Storage;
use Webkul\Product\Helpers\ProductType;
use Webkul\Category\Repositories\CategoryRepository;
use Webkul\Core\Contracts\Validations\Slug;
use Webkul\Product\Http\Requests\ProductForm;
use Webkul\Product\Repositories\ProductRepository;
use Webkul\Product\Repositories\ProductDownloadableLinkRepository;
use Webkul\Product\Repositories\ProductDownloadableSampleRepository;
use Webkul\Category\Repositories\CategoryRepository;
use Webkul\Attribute\Repositories\AttributeFamilyRepository;
use Webkul\Inventory\Repositories\InventorySourceRepository;
use Illuminate\Support\Facades\Storage;
use Webkul\Product\Repositories\ProductDownloadableLinkRepository;
use Webkul\Product\Repositories\ProductDownloadableSampleRepository;
use Webkul\Product\Repositories\ProductAttributeValueRepository;
class ProductController extends Controller
{
@ -64,15 +68,24 @@ class ProductController extends Controller
*/
protected $inventorySourceRepository;
/**
* ProductAttributeValueRepository object
*
* @var \Webkul\Product\Repositories\ProductAttributeValueRepository
*/
protected $productAttributeValueRepository;
/**
* Create a new controller instance.
*
* @param \Webkul\Category\Repositories\CategoryRepository $categoryRepository
* @param \Webkul\Product\Repositories\ProductRepository $productRepository
* @param \Webkul\Product\Repositories\ProductDownloadableLinkRepository $productDownloadableLinkRepository
* @param \Webkul\Product\Repositories\ProductDownloadableSampleRepository $productDownloadableSampleRepository
* @param \Webkul\Attribute\Repositories\AttributeFamilyRepository $attributeFamilyRepository
* @param \Webkul\Inventory\Repositories\InventorySourceRepository $inventorySourceRepository
* @param \Webkul\Category\Repositories\CategoryRepository $categoryRepository
* @param \Webkul\Product\Repositories\ProductRepository $productRepository
* @param \Webkul\Product\Repositories\ProductDownloadableLinkRepository $productDownloadableLinkRepository
* @param \Webkul\Product\Repositories\ProductDownloadableSampleRepository $productDownloadableSampleRepository
* @param \Webkul\Attribute\Repositories\AttributeFamilyRepository $attributeFamilyRepository
* @param \Webkul\Inventory\Repositories\InventorySourceRepository $inventorySourceRepository
* @param \Webkul\Product\Repositories\ProductAttributeValueRepository $productAttributeValueRepository
*
* @return void
*/
public function __construct(
@ -81,7 +94,8 @@ class ProductController extends Controller
ProductDownloadableLinkRepository $productDownloadableLinkRepository,
ProductDownloadableSampleRepository $productDownloadableSampleRepository,
AttributeFamilyRepository $attributeFamilyRepository,
InventorySourceRepository $inventorySourceRepository
InventorySourceRepository $inventorySourceRepository,
ProductAttributeValueRepository $productAttributeValueRepository
)
{
$this->_config = request('_config');
@ -97,6 +111,8 @@ class ProductController extends Controller
$this->attributeFamilyRepository = $attributeFamilyRepository;
$this->inventorySourceRepository = $inventorySourceRepository;
$this->productAttributeValueRepository = $productAttributeValueRepository;
}
/**
@ -143,7 +159,7 @@ class ProductController extends Controller
if (ProductType::hasVariants(request()->input('type'))
&& (! request()->has('super_attributes')
|| ! count(request()->get('super_attributes')))
|| ! count(request()->get('super_attributes')))
) {
session()->flash('error', trans('admin::app.catalog.products.configurable-error'));
@ -153,7 +169,7 @@ class ProductController extends Controller
$this->validate(request(), [
'type' => 'required',
'attribute_family_id' => 'required',
'sku' => ['required', 'unique:products,sku', new \Webkul\Core\Contracts\Validations\Slug],
'sku' => ['required', 'unique:products,sku', new Slug],
]);
$product = $this->productRepository->create(request()->all());
@ -166,7 +182,8 @@ class ProductController extends Controller
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @param int $id
*
* @return \Illuminate\View\View
*/
public function edit($id)
@ -183,8 +200,9 @@ class ProductController extends Controller
/**
* Update the specified resource in storage.
*
* @param \Webkul\Product\Http\Requests\ProductForm $request
* @param int $id
* @param \Webkul\Product\Http\Requests\ProductForm $request
* @param int $id
*
* @return \Illuminate\Http\Response
*/
public function update(ProductForm $request, $id)
@ -201,20 +219,20 @@ class ProductController extends Controller
if (count($customAttributes)) {
foreach ($customAttributes as $attribute) {
if ($attribute->type == 'multiselect') {
array_push($multiselectAttributeCodes,$attribute->code);
}
array_push($multiselectAttributeCodes, $attribute->code);
}
}
}
}
if (count($multiselectAttributeCodes)) {
foreach ($multiselectAttributeCodes as $multiselectAttributeCode) {
if(! isset($data[$multiselectAttributeCode])){
if (! isset($data[$multiselectAttributeCode])) {
$data[$multiselectAttributeCode] = array();
}
}
}
}
$product = $this->productRepository->update($data, $id);
session()->flash('success', trans('admin::app.response.update-success', ['name' => 'Product']));
@ -225,7 +243,8 @@ class ProductController extends Controller
/**
* Uploads downloadable file
*
* @param int $id
* @param int $id
*
* @return \Illuminate\Http\Response
*/
public function uploadLink($id)
@ -235,10 +254,45 @@ class ProductController extends Controller
);
}
/**
* Copy a given Product.
*/
public function copy(int $productId)
{
$originalProduct = $this->productRepository->findOrFail($productId);
if (! $originalProduct->getTypeInstance()->canBeCopied()) {
session()->flash('error',
trans('admin::app.response.product-can-not-be-copied', [
'type' => $originalProduct->type,
]));
return redirect()->to(route('admin.catalog.products.index'));
}
if ($originalProduct->parent_id) {
session()->flash('error',
trans('admin::app.catalog.products.variant-already-exist-message'));
return redirect()->to(route('admin.catalog.products.index'));
}
$copiedProduct = $this->productRepository->copy($originalProduct);
if ($copiedProduct instanceof Product && $copiedProduct->id) {
session()->flash('success', trans('admin::app.response.product-copied'));
} else {
session()->flash('error', trans('admin::app.response.error-while-copying'));
}
return redirect()->to(route('admin.catalog.products.edit', ['id' => $copiedProduct->id]));
}
/**
* Uploads downloadable sample file
*
* @param int $id
* @param int $id
*
* @return \Illuminate\Http\Response
*/
public function uploadSample($id)
@ -251,7 +305,8 @@ class ProductController extends Controller
/**
* Remove the specified resource from storage.
*
* @param int $id
* @param int $id
*
* @return \Illuminate\Http\Response
*/
public function destroy($id)
@ -264,7 +319,7 @@ class ProductController extends Controller
session()->flash('success', trans('admin::app.response.delete-success', ['name' => 'Product']));
return response()->json(['message' => true], 200);
} catch (\Exception $e) {
} catch (Exception $e) {
report($e);
session()->flash('error', trans('admin::app.response.delete-failed', ['name' => 'Product']));
@ -363,16 +418,17 @@ class ProductController extends Controller
}
}
/**
/**
* Download image or file
*
* @param int $productId
* @param int $attributeId
* @param int $productId
* @param int $attributeId
*
* @return \Illuminate\Http\Response
*/
public function download($productId, $attributeId)
{
$productAttribute = $this->productAttributeValue->findOneWhere([
$productAttribute = $this->productAttributeValueRepository->findOneWhere([
'product_id' => $productId,
'attribute_id' => $attributeId,
]);

View File

@ -2,11 +2,15 @@
namespace Webkul\Product\Models;
use Exception;
use Webkul\Product\Type\AbstractType;
use Illuminate\Database\Eloquent\Model;
use Webkul\Attribute\Models\AttributeFamilyProxy;
use Webkul\Category\Models\CategoryProxy;
use Webkul\Attribute\Models\AttributeProxy;
use Webkul\Product\Database\Eloquent\Builder;
use Webkul\Attribute\Models\AttributeFamilyProxy;
use Webkul\Inventory\Models\InventorySourceProxy;
use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Product\Contracts\Product as ProductContract;
class Product extends Model implements ProductContract
@ -59,7 +63,8 @@ class Product extends Model implements ProductContract
}
/**
* Get the product variants that owns the product.
* Get the product flat entries that are associated with product.
* May be one for each locale and each channel.
*/
public function product_flats()
{
@ -220,8 +225,8 @@ class Product extends Model implements ProductContract
public function inventory_source_qty($inventorySourceId)
{
return $this->inventories()
->where('inventory_source_id', $inventorySourceId)
->sum('qty');
->where('inventory_source_id', $inventorySourceId)
->sum('qty');
}
/**
@ -237,6 +242,12 @@ class Product extends Model implements ProductContract
$this->typeInstance = app(config('product_types.' . $this->type . '.class'));
if (! $this->typeInstance instanceof AbstractType) {
throw new Exception(
"Please ensure the product type '{$this->type}' is configured in your application."
);
}
$this->typeInstance->setProduct($this);
return $this->typeInstance;
@ -283,6 +294,7 @@ class Product extends Model implements ProductContract
*
* @param Group $group
* @param bool $skipSuperAttribute
*
* @return Collection
*/
public function getEditableAttributes($group = null, $skipSuperAttribute = true)
@ -293,7 +305,8 @@ class Product extends Model implements ProductContract
/**
* Get an attribute from the model.
*
* @param string $key
* @param string $key
*
* @return mixed
*/
public function getAttribute($key)
@ -305,8 +318,8 @@ class Product extends Model implements ProductContract
if (isset($this->id)) {
$this->attributes[$key] = '';
$attribute = core()->getSingletonInstance(\Webkul\Attribute\Repositories\AttributeRepository::class)
->getAttributeByCode($key);
$attribute = core()->getSingletonInstance(AttributeRepository::class)
->getAttributeByCode($key);
$this->attributes[$key] = $this->getCustomAttributeValue($attribute);
@ -327,8 +340,9 @@ class Product extends Model implements ProductContract
$hiddenAttributes = $this->getHidden();
if (isset($this->id)) {
$familyAttributes = core()->getSingletonInstance(\Webkul\Attribute\Repositories\AttributeRepository::class)
->getFamilyAttributes($this->attribute_family);
$familyAttributes = core()
->getSingletonInstance(AttributeRepository::class)
->getFamilyAttributes($this->attribute_family);
foreach ($familyAttributes as $attribute) {
if (in_array($attribute->code, $hiddenAttributes)) {
@ -377,12 +391,13 @@ class Product extends Model implements ProductContract
/**
* Overrides the default Eloquent query builder
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $query
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function newEloquentBuilder($query)
{
return new \Webkul\Product\Database\Eloquent\Builder($query);
return new Builder($query);
}
/**

View File

@ -2,14 +2,20 @@
namespace Webkul\Product\Repositories;
use Illuminate\Pagination\Paginator;
use Exception;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\DB;
use Illuminate\Container\Container as App;
use Illuminate\Support\Facades\Event;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Product\Models\Product;
use Illuminate\Pagination\Paginator;
use Webkul\Core\Eloquent\Repository;
use Illuminate\Support\Facades\Event;
use Webkul\Attribute\Models\Attribute;
use Webkul\Product\Models\ProductFlat;
use Illuminate\Container\Container as App;
use Illuminate\Pagination\LengthAwarePaginator;
use Webkul\Product\Models\ProductAttributeValueProxy;
use Webkul\Attribute\Repositories\AttributeRepository;
use Illuminate\Database\Eloquent\ModelNotFoundException;
class ProductRepository extends Repository
{
@ -23,8 +29,9 @@ class ProductRepository extends Repository
/**
* Create a new repository instance.
*
* @param \Webkul\Attribute\Repositories\AttributeRepository $attributeRepository
* @param \Illuminate\Container\Container $app
* @param \Webkul\Attribute\Repositories\AttributeRepository $attributeRepository
* @param \Illuminate\Container\Container $app
*
* @return void
*/
public function __construct(
@ -48,7 +55,8 @@ class ProductRepository extends Repository
}
/**
* @param array $data
* @param array $data
*
* @return \Webkul\Product\Contracts\Product
*/
public function create(array $data)
@ -65,9 +73,10 @@ class ProductRepository extends Repository
}
/**
* @param array $data
* @param int $id
* @param string $attribute
* @param array $data
* @param int $id
* @param string $attribute
*
* @return \Webkul\Product\Contracts\Product
*/
public function update(array $data, $id, $attribute = "id")
@ -88,7 +97,8 @@ class ProductRepository extends Repository
}
/**
* @param int $id
* @param int $id
*
* @return void
*/
public function delete($id)
@ -101,7 +111,8 @@ class ProductRepository extends Repository
}
/**
* @param int $categoryId
* @param int $categoryId
*
* @return \Illuminate\Support\Collection
*/
public function getAll($categoryId = null)
@ -111,21 +122,21 @@ class ProductRepository extends Repository
if (core()->getConfigData('catalog.products.storefront.products_per_page')) {
$pages = explode(',', core()->getConfigData('catalog.products.storefront.products_per_page'));
$perPage = isset($params['limit']) ? (!empty($params['limit']) ? $params['limit'] : 9) : current($pages);
$perPage = isset($params['limit']) ? (! empty($params['limit']) ? $params['limit'] : 9) : current($pages);
} else {
$perPage = isset($params['limit']) && !empty($params['limit']) ? $params['limit'] : 9;
$perPage = isset($params['limit']) && ! empty($params['limit']) ? $params['limit'] : 9;
}
$page = Paginator::resolveCurrentPage('page');
$repository = app(ProductFlatRepository::class)->scopeQuery(function($query) use($params, $categoryId) {
$repository = app(ProductFlatRepository::class)->scopeQuery(function ($query) use ($params, $categoryId) {
$channel = request()->get('channel') ?: (core()->getCurrentChannelCode() ?: core()->getDefaultChannelCode());
$locale = request()->get('locale') ?: app()->getLocale();
$qb = $query->distinct()
->select('product_flat.*')
->join('product_flat as variants', 'product_flat.id', '=', DB::raw('COALESCE('.DB::getTablePrefix().'variants.parent_id, '.DB::getTablePrefix().'variants.id)'))
->join('product_flat as variants', 'product_flat.id', '=', DB::raw('COALESCE(' . DB::getTablePrefix() . 'variants.parent_id, ' . DB::getTablePrefix() . 'variants.id)'))
->leftJoin('product_categories', 'product_categories.product_id', '=', 'product_flat.product_id')
->leftJoin('product_attribute_values', 'product_attribute_values.product_id', '=', 'variants.product_id')
->where('product_flat.channel', $channel)
@ -149,25 +160,25 @@ class ProductRepository extends Repository
# sort direction
$orderDirection = 'asc';
if( isset($params['order']) && in_array($params['order'], ['desc', 'asc']) ){
if (isset($params['order']) && in_array($params['order'], ['desc', 'asc'])) {
$orderDirection = $params['order'];
} else {
$sortOptions = $this->getDefaultSortByOption();
$orderDirection = !empty($sortOptions) ? $sortOptions[1] : 'asc';
$orderDirection = ! empty($sortOptions) ? $sortOptions[1] : 'asc';
}
if (isset($params['sort'])) {
$this->checkSortAttributeAndGenerateQuery($qb, $params['sort'], $orderDirection);
} else {
$sortOptions = $this->getDefaultSortByOption();
if (!empty($sortOptions)) {
if (! empty($sortOptions)) {
$this->checkSortAttributeAndGenerateQuery($qb, $sortOptions[0], $orderDirection);
}
}
if ( $priceFilter = request('price') ){
if ($priceFilter = request('price')) {
$priceRange = explode(',', $priceFilter);
if( count($priceRange) > 0 ) {
if (count($priceRange) > 0) {
$qb->where('variants.min_price', '>=', core()->convertToBasePrice($priceRange[0]));
$qb->where('variants.min_price', '<=', core()->convertToBasePrice(end($priceRange)));
}
@ -178,8 +189,8 @@ class ProductRepository extends Repository
request()->except(['price'])
));
if ( count($attributeFilters) > 0 ) {
$qb->where(function ($filterQuery) use($attributeFilters){
if (count($attributeFilters) > 0) {
$qb->where(function ($filterQuery) use ($attributeFilters) {
foreach ($attributeFilters as $attribute) {
$filterQuery->orWhere(function ($attributeQuery) use ($attribute) {
@ -196,7 +207,7 @@ class ProductRepository extends Repository
$attributeQuery->where(function ($attributeValueQuery) use ($column, $filterInputValues) {
foreach ($filterInputValues as $filterValue) {
if (!is_numeric($filterValue)) {
if (! is_numeric($filterValue)) {
continue;
}
$attributeValueQuery->orWhereRaw("find_in_set(?, {$column})", [$filterValue]);
@ -239,9 +250,9 @@ class ProductRepository extends Repository
$items = [];
}
$results = new \Illuminate\Pagination\LengthAwarePaginator($items, $count, $perPage, $page, [
$results = new LengthAwarePaginator($items, $count, $perPage, $page, [
'path' => request()->url(),
'query' => request()->query()
'query' => request()->query(),
]);
return $results;
@ -250,8 +261,9 @@ class ProductRepository extends Repository
/**
* Retrive product from slug
*
* @param string $slug
* @param string $columns
* @param string $slug
* @param string $columns
*
* @return \Webkul\Product\Contracts\Product
*/
public function findBySlugOrFail($slug, $columns = null)
@ -274,7 +286,8 @@ class ProductRepository extends Repository
/**
* Retrieve product from slug without throwing an exception (might return null)
*
* @param string $slug
* @param string $slug
*
* @return \Webkul\Product\Contracts\ProductFlat
*/
public function findBySlug($slug)
@ -293,19 +306,19 @@ class ProductRepository extends Repository
*/
public function getNewProducts()
{
$results = app(ProductFlatRepository::class)->scopeQuery(function($query) {
$results = app(ProductFlatRepository::class)->scopeQuery(function ($query) {
$channel = request()->get('channel') ?: (core()->getCurrentChannelCode() ?: core()->getDefaultChannelCode());
$locale = request()->get('locale') ?: app()->getLocale();
return $query->distinct()
->addSelect('product_flat.*')
->where('product_flat.status', 1)
->where('product_flat.visible_individually', 1)
->where('product_flat.new', 1)
->where('product_flat.channel', $channel)
->where('product_flat.locale', $locale)
->inRandomOrder();
->addSelect('product_flat.*')
->where('product_flat.status', 1)
->where('product_flat.visible_individually', 1)
->where('product_flat.new', 1)
->where('product_flat.channel', $channel)
->where('product_flat.locale', $locale)
->inRandomOrder();
})->paginate(4);
return $results;
@ -318,19 +331,19 @@ class ProductRepository extends Repository
*/
public function getFeaturedProducts()
{
$results = app(ProductFlatRepository::class)->scopeQuery(function($query) {
$results = app(ProductFlatRepository::class)->scopeQuery(function ($query) {
$channel = request()->get('channel') ?: (core()->getCurrentChannelCode() ?: core()->getDefaultChannelCode());
$locale = request()->get('locale') ?: app()->getLocale();
return $query->distinct()
->addSelect('product_flat.*')
->where('product_flat.status', 1)
->where('product_flat.visible_individually', 1)
->where('product_flat.featured', 1)
->where('product_flat.channel', $channel)
->where('product_flat.locale', $locale)
->inRandomOrder();
->addSelect('product_flat.*')
->where('product_flat.status', 1)
->where('product_flat.visible_individually', 1)
->where('product_flat.featured', 1)
->where('product_flat.channel', $channel)
->where('product_flat.locale', $locale)
->inRandomOrder();
})->paginate(4);
return $results;
@ -339,7 +352,8 @@ class ProductRepository extends Repository
/**
* Search Product by Attribute
*
* @param string $term
* @param string $term
*
* @return \Illuminate\Support\Collection
*/
public function searchProductByAttribute($term)
@ -349,27 +363,27 @@ class ProductRepository extends Repository
$locale = request()->get('locale') ?: app()->getLocale();
if (config('scout.driver') == 'algolia') {
$results = app(ProductFlatRepository::class)->getModel()::search('query', function ($searchDriver, string $query, array $options) use($term, $channel, $locale) {
$results = app(ProductFlatRepository::class)->getModel()::search('query', function ($searchDriver, string $query, array $options) use ($term, $channel, $locale) {
$queries = explode('_', $term);
$options['similarQuery'] = array_map('trim', $queries);
$searchDriver->setSettings([
'attributesForFaceting' => [
"searchable(locale)",
"searchable(channel)"
]
"searchable(locale)",
"searchable(channel)",
],
]);
$options['facetFilters'] = ['locale:' . $locale, 'channel:' . $channel];
$options['facetFilters'] = ['locale:' . $locale, 'channel:' . $channel];
return $searchDriver->search($query, $options);
})
->where('status', 1)
->where('visible_individually', 1)
->orderBy('product_id', 'desc')
->paginate(16);
} else if(config('scout.driver') == 'elastic') {
->where('status', 1)
->where('visible_individually', 1)
->orderBy('product_id', 'desc')
->paginate(16);
} else if (config('scout.driver') == 'elastic') {
$queries = explode('_', $term);
$results = app(ProductFlatRepository::class)->getModel()::search(implode(' OR ', $queries))
@ -380,23 +394,23 @@ class ProductRepository extends Repository
->orderBy('product_id', 'desc')
->paginate(16);
} else {
$results = app(ProductFlatRepository::class)->scopeQuery(function($query) use($term, $channel, $locale) {
$results = app(ProductFlatRepository::class)->scopeQuery(function ($query) use ($term, $channel, $locale) {
return $query->distinct()
->addSelect('product_flat.*')
->where('product_flat.status', 1)
->where('product_flat.visible_individually', 1)
->where('product_flat.channel', $channel)
->where('product_flat.locale', $locale)
->whereNotNull('product_flat.url_key')
->where(function($subQuery) use ($term) {
$queries = explode('_', $term);
->addSelect('product_flat.*')
->where('product_flat.status', 1)
->where('product_flat.visible_individually', 1)
->where('product_flat.channel', $channel)
->where('product_flat.locale', $locale)
->whereNotNull('product_flat.url_key')
->where(function ($subQuery) use ($term) {
$queries = explode('_', $term);
foreach (array_map('trim', $queries) as $value) {
$subQuery->orWhere('product_flat.name', 'like', '%' . urldecode($value) . '%')
->orWhere('product_flat.short_description', 'like', '%' . urldecode($value) . '%');
}
})
->orderBy('product_id', 'desc');
foreach (array_map('trim', $queries) as $value) {
$subQuery->orWhere('product_flat.name', 'like', '%' . urldecode($value) . '%')
->orWhere('product_flat.short_description', 'like', '%' . urldecode($value) . '%');
}
})
->orderBy('product_id', 'desc');
})->paginate(16);
}
@ -406,7 +420,8 @@ class ProductRepository extends Repository
/**
* Returns product's super attribute with options
*
* @param \Webkul\Product\Contracts\Product $product
* @param \Webkul\Product\Contracts\Product $product
*
* @return \Illuminate\Support\Collection
*/
public function getSuperAttributes($product)
@ -432,35 +447,72 @@ class ProductRepository extends Repository
/**
* Search simple products for grouped product association
*
* @param string $term
* @param string $term
*
* @return \Illuminate\Support\Collection
*/
public function searchSimpleProducts($term)
{
return app(ProductFlatRepository::class)->scopeQuery(function($query) use($term) {
return app(ProductFlatRepository::class)->scopeQuery(function ($query) use ($term) {
$channel = request()->get('channel') ?: (core()->getCurrentChannelCode() ?: core()->getDefaultChannelCode());
$locale = request()->get('locale') ?: app()->getLocale();
return $query->distinct()
->addSelect('product_flat.*')
->addSelect('product_flat.product_id as id')
->leftJoin('products', 'product_flat.product_id', '=', 'products.id')
->where('products.type', 'simple')
->where('product_flat.channel', $channel)
->where('product_flat.locale', $locale)
->where('product_flat.name', 'like', '%' . urldecode($term) . '%')
->orderBy('product_id', 'desc');
->addSelect('product_flat.*')
->addSelect('product_flat.product_id as id')
->leftJoin('products', 'product_flat.product_id', '=', 'products.id')
->where('products.type', 'simple')
->where('product_flat.channel', $channel)
->where('product_flat.locale', $locale)
->where('product_flat.name', 'like', '%' . urldecode($term) . '%')
->orderBy('product_id', 'desc');
})->get();
}
/**
* Copy a product. Is usually called by the copy() function of the ProductController.
*
* Always make the copy is inactive so the admin is able to configure it before setting it live.
*
* @param int $sourceProductId the id of the product that should be copied
*/
public function copy(Product $originalProduct): Product
{
$this->fillOriginalProduct($originalProduct);
if (! $originalProduct->getTypeInstance()->canBeCopied()) {
throw new Exception(trans('admin::app.response.product-can-not-be-copied', ['type' => $originalProduct->type]));
}
DB::beginTransaction();
try {
$copiedProduct = $this->persistCopiedProduct($originalProduct);
$this->persistAttributeValues($originalProduct, $copiedProduct);
$this->persistRelations($originalProduct, $copiedProduct);
} catch (Exception $e) {
DB::rollBack();
report($e);
throw $e;
}
DB::commit();
return $copiedProduct;
}
/**
* Get default sort by option
*
* @return array
*/
private function getDefaultSortByOption()
{
{
$value = core()->getConfigData('catalog.products.storefront.sort_by');
$config = $value ? $value : 'name-desc';
@ -471,9 +523,10 @@ class ProductRepository extends Repository
/**
* Check sort attribute and generate query
*
* @param object $query
* @param string $sort
* @param string $direction
* @param object $query
* @param string $sort
* @param string $direction
*
* @return object
*/
private function checkSortAttributeAndGenerateQuery($query, $sort, $direction)
@ -481,13 +534,188 @@ class ProductRepository extends Repository
$attribute = $this->attributeRepository->findOneByField('code', $sort);
if ($attribute) {
if ($attribute->code == 'price') {
if ($attribute->code === 'price') {
$query->orderBy('min_price', $direction);
} else {
$query->orderBy($sort == 'created_at' ? 'product_flat.created_at' : $attribute->code, $direction);
$query->orderBy($sort === 'created_at' ? 'product_flat.created_at' : $attribute->code, $direction);
}
}
return $query;
}
private function fillOriginalProduct(Product &$sourceProduct): void
{
$sourceProduct
->load('attribute_family')
->load('categories')
->load('customer_group_prices')
->load('inventories')
->load('inventory_sources');
}
/**
* @param $originalProduct
*
* @return mixed
*/
private function persistCopiedProduct($originalProduct): Product
{
$copiedProduct = $originalProduct
->replicate()
->fill([
// the sku and url_key needs to be unique and should be entered again newly by the admin:
'sku' => 'temporary-sku-' . substr(md5(microtime()), 0, 6),
]);
$copiedProduct->save();
return $copiedProduct;
}
/**
* Gather the ids of the necessary product attributes.
* Throw an Exception if one of these 'basic' attributes are missing for some reason.
*/
private function gatherAttributeIds(): array
{
$ids = [];
foreach (['name', 'sku', 'status', 'url_key'] as $code) {
$ids[$code] = Attribute::query()->where(['code' => $code])->firstOrFail()->id;
}
return $ids;
}
private function persistAttributeValues(Product $originalProduct, Product $copiedProduct): void
{
$attributeIds = $this->gatherAttributeIds();
$newProductFlat = new ProductFlat();
// only obey copied locale and channel:
if (isset($originalProduct->product_flats[0])) {
$newProductFlat = $originalProduct->product_flats[0]->replicate();
}
$newProductFlat->product_id = $copiedProduct->id;
$attributesToSkip = config('products.skipAttributesOnCopy') ?? [];
$randomSuffix = substr(md5(microtime()), 0, 6);
foreach ($originalProduct->attribute_values as $oldValue) {
if (in_array($oldValue->attribute->code, $attributesToSkip)) {
continue;
}
$newValue = $oldValue->replicate();
// change name of copied product
if ($oldValue->attribute_id === $attributeIds['name']) {
$copyOf = trans('admin::app.copy-of');
$copiedName = sprintf('%s%s (%s)',
Str::startsWith($originalProduct->name, $copyOf) ? '' : $copyOf,
$originalProduct->name,
$randomSuffix
);
$newValue->text_value = $copiedName;
$newProductFlat->name = $copiedName;
}
// change url_key of copied product
if ($oldValue->attribute_id === $attributeIds['url_key']) {
$copyOfSlug = trans('admin::app.copy-of-slug');
$copiedSlug = sprintf('%s%s-%s',
Str::startsWith($originalProduct->url_key, $copyOfSlug) ? '' : $copyOfSlug,
$originalProduct->url_key,
$randomSuffix
);
$newValue->text_value = $copiedSlug;
$newProductFlat->url_key = $copiedSlug;
}
// change sku of copied product
if ($oldValue->attribute_id === $attributeIds['sku']) {
$newValue->text_value = $copiedProduct->sku;
$newProductFlat->sku = $copiedProduct->sku;
}
// force the copied product to be inactive so the admin can adjust it before release
if ($oldValue->attribute_id === $attributeIds['status']) {
$newValue->boolean_value = 0;
$newProductFlat->status = 0;
}
$copiedProduct->attribute_values()->save($newValue);
}
$newProductFlat->save();
}
/**
* @param $originalProduct
* @param $copiedProduct
*/
private function persistRelations($originalProduct, $copiedProduct): void
{
$attributesToSkip = config('products.skipAttributesOnCopy') ?? [];
if (! in_array('categories', $attributesToSkip)) {
foreach ($originalProduct->categories as $category) {
DB::table('product_categories')->insert([
'product_id' => $copiedProduct->id,
'category_id' => $category->id,
]);
}
}
if (! in_array('inventories', $attributesToSkip)) {
foreach ($originalProduct->inventories as $inventory) {
$copiedProduct->inventories()->save($inventory->replicate());
}
}
if (! in_array('customer_group_pricces', $attributesToSkip)) {
foreach ($originalProduct->customer_group_prices as $customer_group_price) {
$copiedProduct->customer_group_prices()->save($customer_group_price->replicate());
}
}
if (! in_array('images', $attributesToSkip)) {
foreach ($originalProduct->images as $image) {
$copiedProduct->images()->save($image->replicate());
}
}
if (! in_array('super_attributes', $attributesToSkip)) {
foreach ($originalProduct->super_attributes as $super_attribute) {
$copiedProduct->super_attributes()->save($super_attribute);
}
}
if (! in_array('bundle_options', $attributesToSkip)) {
foreach ($originalProduct->bundle_options as $bundle_option) {
$copiedProduct->bundle_options()->save($bundle_option->replicate());
}
}
if (! in_array('variants', $attributesToSkip)) {
foreach ($originalProduct->variants as $variant) {
$variant = $this->copy($variant);
$variant->parent_id = $copiedProduct->id;
$variant->save();
}
}
if (config('products.linkProductsOnCopy')) {
DB::table('product_relations')->insert([
'parent_id' => $originalProduct->id,
'child_id' => $copiedProduct->id,
]);
}
}
}

View File

@ -4,15 +4,13 @@ namespace Webkul\Product\Type;
use Illuminate\Support\Facades\Storage;
use Webkul\Attribute\Repositories\AttributeRepository;
use Webkul\Product\Datatypes\CartItemValidationResult;
use Webkul\Product\Repositories\ProductRepository;
use Webkul\Product\Repositories\ProductAttributeValueRepository;
use Webkul\Product\Repositories\ProductInventoryRepository;
use Webkul\Product\Repositories\ProductImageRepository;
use Webkul\Product\Models\ProductAttributeValue;
use Webkul\Product\Helpers\ProductImage;
use Webkul\Checkout\Facades\Cart;
use Webkul\Checkout\Models\CartItem;
use Webkul\Product\Helpers\ProductImage;
use Webkul\Product\Models\ProductAttributeValue;
use Webkul\Product\Repositories\ProductRepository;
use Webkul\Product\Repositories\ProductImageRepository;
use Webkul\Product\Repositories\ProductInventoryRepository;
use Webkul\Product\Repositories\ProductAttributeValueRepository;
abstract class AbstractType
{
@ -100,6 +98,13 @@ abstract class AbstractType
*/
protected $canBeMovedFromWishlistToCart = true;
/**
* Products of this type can be copied in the admin backend?
*
* @var bool
*/
protected $canBeCopied = true;
/**
* Has child products aka variants
*
@ -153,6 +158,17 @@ abstract class AbstractType
}
/**
<<<<<<< HEAD
=======
* Is the administrator able to copy products of this type in the admin backend?
*/
public function canBeCopied(): bool
{
return $this->canBeCopied;
}
/**
>>>>>>> bagisto/master
* @param array $data
*
* @return \Webkul\Product\Contracts\Product
@ -163,10 +179,16 @@ abstract class AbstractType
}
/**
<<<<<<< HEAD
* @param array $data
* @param int $id
* @param string $attribute
*
=======
* @param array $data
* @param int $id
* @param string $attribute
>>>>>>> bagisto/master
* @return \Webkul\Product\Contracts\Product
*/
public function update(array $data, $id, $attribute = "id")
@ -178,7 +200,7 @@ abstract class AbstractType
foreach ($product->attribute_family->custom_attributes as $attribute) {
$route = request()->route() ? request()->route()->getName() : "";
if ($attribute->type == 'boolean' && $route != 'admin.catalog.products.massupdate') {
if ($attribute->type === 'boolean' && $route !== 'admin.catalog.products.massupdate') {
$data[$attribute->code] = isset($data[$attribute->code]) && $data[$attribute->code] ? 1 : 0;
}
@ -201,7 +223,11 @@ abstract class AbstractType
if ($attribute->type == 'image' || $attribute->type == 'file') {
$data[$attribute->code] = gettype($data[$attribute->code]) == 'object'
? request()->file($attribute->code)->store('product/' . $product->id)
<<<<<<< HEAD
: null;
=======
: NULL;
>>>>>>> bagisto/master
}
$attributeValue = $this->attributeValueRepository->findOneWhere([
@ -221,7 +247,11 @@ abstract class AbstractType
]);
} else {
$this->attributeValueRepository->update([
<<<<<<< HEAD
ProductAttributeValue::$attributeTypeFields[$attribute->type] => $data[$attribute->code],
=======
ProductAttributeValue::$attributeTypeFields[$attribute->type] => $data[$attribute->code]
>>>>>>> bagisto/master
], $attributeValue->id
);
@ -233,8 +263,13 @@ abstract class AbstractType
$route = request()->route() ? request()->route()->getName() : "";
<<<<<<< HEAD
if ($route != 'admin.catalog.products.massupdate') {
if (!isset($data['categories'])) {
=======
if ($route !== 'admin.catalog.products.massupdate') {
if (! isset($data['categories'])) {
>>>>>>> bagisto/master
$data['categories'] = [];
}
@ -558,7 +593,11 @@ abstract class AbstractType
if ($customerGroupPrice !== $this->product->price) {
$haveSpecialPrice = true;
$this->product->special_price = $customerGroupPrice;
}
<<<<<<< HEAD
}
=======
}
>>>>>>> bagisto/master
}
return $haveSpecialPrice;

View File

@ -7,9 +7,7 @@
"email": "jitendra@webkul.com"
}
],
"require": {
"konekt/concord": "^1.2"
},
"require": {},
"autoload": {
"psr-4": {
"Webkul\\Sales\\": "src/"

View File

@ -218,7 +218,7 @@ class Order extends Model implements OrderContract
}
foreach ($this->items as $item) {
if ($item->canShip()) {
if ($item->canShip() && $item->order->status !== self::STATUS_CLOSED) {
return true;
}
}
@ -238,7 +238,7 @@ class Order extends Model implements OrderContract
}
foreach ($this->items as $item) {
if ($item->canInvoice()) {
if ($item->canInvoice() && $item->order->status !== self::STATUS_CLOSED) {
return true;
}
}
@ -257,8 +257,13 @@ class Order extends Model implements OrderContract
return false;
}
$pendingInvoice = $this->invoices->where('state', 'pending')->first();
if ($pendingInvoice) {
return true;
}
foreach ($this->items as $item) {
if ($item->canCancel()) {
if ($item->canCancel() && $item->order->status !== self::STATUS_CLOSED) {
return true;
}
}
@ -278,13 +283,13 @@ class Order extends Model implements OrderContract
}
foreach ($this->invoices as $item) {
if ($item->state == "pending" || $item->state == "overdue") {
if ($item->state == 'pending' || $item->state == 'overdue') {
return false;
}
}
foreach ($this->items as $item) {
if ($item->qty_to_refund > 0) {
if ($item->qty_to_refund > 0 && $item->order->status !== self::STATUS_CLOSED) {
return true;
}
}

View File

@ -259,10 +259,15 @@ class InvoiceRepository extends Repository
* @return void
*/
public function updateInvoiceState($invoice, $status)
{
{
$invoice->state = $status;
$invoice->save();
if ($status == 'paid'){
$order = $this->orderRepository->findOrFail($invoice->order->id);
$this->orderRepository->updateOrderStatus($order);
}
return true;
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
{
"/js/shop.js": "/js/shop.js?id=d64fdfe9e3fe3e4b9ee4",
"/css/shop.css": "/css/shop.css?id=72d87fe2508fdcd9f397"
"/css/shop.css": "/css/shop.css?id=8ef1aa65dda3180b66ee"
}

View File

@ -28,7 +28,7 @@ return [
'sort' => 4,
], [
'key' => 'account.compare',
'name' => 'velocity::app.customer.compare.text',
'name' => 'shop::app.customer.compare.text',
'route' =>'velocity.customer.product.compare',
'sort' => 5,
], [

View File

@ -15,7 +15,8 @@ class DownloadableProductDataGrid extends DataGrid
{
$queryBuilder = DB::table('downloadable_link_purchased')
->leftJoin('orders', 'downloadable_link_purchased.order_id', '=', 'orders.id')
->addSelect('downloadable_link_purchased.*', 'orders.increment_id')
->leftJoin('invoices', 'downloadable_link_purchased.order_id', '=', 'invoices.order_id')
->addSelect('downloadable_link_purchased.*', 'invoices.state as invoice_state', 'orders.increment_id')
->addSelect(DB::raw('(' . DB::getTablePrefix() . 'downloadable_link_purchased.download_bought - ' . DB::getTablePrefix() . 'downloadable_link_purchased.download_used) as remaining_downloads'))
->where('downloadable_link_purchased.customer_id', auth()->guard('customer')->user()->id);
@ -45,7 +46,7 @@ class DownloadableProductDataGrid extends DataGrid
'filterable' => true,
'closure' => true,
'wrapper' => function ($value) {
if ($value->status == 'pending' || $value->status == 'expired') {
if ($value->status == 'pending' || $value->status == 'expired' || $value->invoice_state !== 'paid') {
return $value->product_name;
} else {
return $value->product_name . ' ' . '<a href="' . route('customer.downloadable_products.download', $value->id) . '" target="_blank">' . $value->name . '</a>';

View File

@ -4286,10 +4286,6 @@ section.review {
}
}
.checkbox {
margin: 10px 0px 5px 5px;
}
.radio {
margin: 10px 0px 5px 5px;
@ -4304,11 +4300,22 @@ section.review {
}
}
.radio-container .checkmark {
top: 2px;
left: 4px;
}
.mt-5 {
margin-top: 5px;
margin-right: 28px;
}
@media only screen and (max-width: 770px) {
.checkout-process .col-main {
padding-left: 0px;
}
}
//checkout process page end here
//customer page start here

View File

@ -98,6 +98,7 @@ return [
'add-tooltip' => 'إضافة منتج لقائمة المقارنة',
'added' => 'تمت إضافة العنصر بنجاح لمقارنة القائمة',
'removed' => 'تمت إزالة العنصر بنجاح من قائمة المقارنة',
'removed-all' => 'تمت إزالة جميع العناصر بنجاح من قائمة المقارنة',
'already_added' => 'تمت إضافة العنصر بالفعل لمقارنة القائمة',
'empty-text' => "ليس لديك أي عناصر في قائمة المقارنة الخاصة بك",
'product_image' => 'Product Image',
@ -176,6 +177,11 @@ return [
'dashboard' => 'الملف الشخصي',
'menu' => 'القائمة',
'general' => [
'no' => 'لا',
'yes' => 'نعم',
],
'profile' => [
'index' => [
'page-title' => 'الملف الشخصي',

View File

@ -99,6 +99,7 @@ return [
'added' => 'Element erfolgreich zur Vergleichsliste hinzugefügt',
'already_added' => 'Artikel bereits zur Vergleichsliste hinzugefügt',
'removed' => 'Element erfolgreich aus Vergleichsliste entfernt',
'removed-all' => 'Alle Elemente wurden erfolgreich aus der Vergleichsliste entfernt',
'empty-text' => "Sie haben keine Elemente in Ihrer Vergleichsliste",
'product_image' => 'Produktbild',
'actions' => 'Aktionen',
@ -176,6 +177,11 @@ return [
'dashboard' => 'Profil bearbeiten',
'menu' => 'Menu',
'general' => [
'no' => 'Nein',
'yes' => 'Ja',
],
'profile' => [
'index' => [
'page-title' => 'Profil',

View File

@ -99,6 +99,7 @@ return [
'added' => 'Item successfully added to compare list',
'already_added' => 'Item already added to compare list',
'removed' => 'Item successfully removed from compare list',
'removed-all' => 'All items successfully removed from compare list',
'empty-text' => "You don't have any items in your compare list",
'product_image' => 'Product Image',
'actions' => 'Actions',
@ -176,6 +177,11 @@ return [
'dashboard' => 'Edit Profile',
'menu' => 'Menu',
'general' => [
'no' => 'No',
'yes' => 'Yes',
],
'profile' => [
'index' => [
'page-title' => 'Profile',

View File

@ -96,6 +96,7 @@ return [
'added' => 'Elemento agregado con éxito a la lista de comparación',
'already_added' => 'Elemento ya agregado a la lista de comparación',
'removed' => 'Elemento eliminado con éxito de la lista de comparación',
'removed-all' => 'Todos los elementos eliminados correctamente de la lista de comparación',
'empty-text' => "No tienes ningún artículo en tu lista de comparación",
'product_image' => 'Product Image',
'actions' => 'Actions',
@ -173,6 +174,11 @@ return [
'dashboard' => 'Cliente - Editar perfil',
'menu' => 'Menu',
'general' => [
'no' => 'No',
'yes' => 'si',
],
'profile' => [
'index' => [
'page-title' => 'Cliente - Perfil',

View File

@ -99,6 +99,7 @@ return [
'added' => 'مورد با موفقیت برای مقایسه لیست اضافه شد',
'already_added' => 'مورد در حال حاضر برای مقایسه لیست اضافه شده است',
'removed' => 'مورد با موفقیت از لیست مقایسه حذف شد',
'removed-all' => 'همه موارد با موفقیت از لیست مقایسه حذف شدند',
'empty-text' => "شما هیچ موردی را در لیست مقایسه خود ندارید",
'product_image' => 'Product Image',
'actions' => 'Actions',
@ -176,6 +177,11 @@ return [
'dashboard' => 'مشتری - ویرایش نمایه',
'menu' => 'فهرست',
'general' => [
'no' => 'نه',
'yes' => 'آره',
],
'profile' => [
'index' => [
'page-title' => 'مشتری - پروفایل',

View File

@ -99,6 +99,7 @@ return [
'added' => 'Articolo aggiunto alla lista di comparazione',
'already_added' => 'Articolo già aggiunto alla lista di comparazione',
'removed' => 'Articolo rimosso dalla lista di comparazione',
'removed-all' => 'Tutti gli elementi rimossi dall\'elenco di confronto',
'empty-text' => "Non hai articoli nella tua lista di comparazione",
],
@ -174,6 +175,11 @@ return [
'dashboard' => 'Modifica Profilo',
'menu' => 'Menu',
'general' => [
'no' => 'No',
'yes' => 'sì',
],
'profile' => [
'index' => [
'page-title' => 'Profilo',

View File

@ -96,6 +96,7 @@ return [
'added' => 'アイテムを比較リストに追加しました',
'already_added' => 'アイテムは比較リストに既に追加されています',
'removed' => '比較リストからアイテムを削除しました',
'removed-all' => '比較リストからすべてのアイテムを削除しました',
'empty-text' => "比較リストにアイテムがありません",
'product_image' => 'Product Image',
'actions' => 'Actions',
@ -173,6 +174,11 @@ return [
'dashboard' => 'プロフィールを編集',
'menu' => 'メニュー',
'general' => [
'no' => '番号',
'yes' => 'はい',
],
'profile' => [
'index' => [
'page-title' => 'プロフィール',

View File

@ -98,6 +98,7 @@ return [
'added' => 'Item successfully added to compare list',
'already_added' => 'Item already added to compare list',
'removed' => 'Item successfully removed from compare list',
'removed-all' => 'All items successfully removed from compare list',
'empty-text' => "You don't have any items in your compare list",
'product_image' => 'Product Image',
'actions' => 'Actions',
@ -181,6 +182,11 @@ return [
'dashboard' => 'Edit Profile',
'menu' => 'Menu',
'general' => [
'no' => 'Nee',
'yes' => 'Ja',
],
'profile' => [
'index' => [
'page-title' => 'Profiel',

View File

@ -99,6 +99,7 @@ return [
'added' => 'Produkt został pomyślnie dodany do listy porównania',
'already_added' => 'Produkt został już dodany do listy porównawczej',
'removed' => 'Produkt został pomyślnie usunięty z listy porównawcze',
'removed-all' => 'Wszystkie produkty zostały pomyślnie usunięte z listy porównawczej',
'empty-text' => 'Nie masz żadnych pozycji na liście porównawczej',
],
@ -174,6 +175,11 @@ return [
'dashboard' => 'Edytuj profil',
'menu' => 'Menu',
'general' => [
'no' => 'Nie',
'yes' => 'tak',
],
'profile' => [
'index' => [
'page-title' => 'Profil',

View File

@ -99,6 +99,7 @@ return [
'already_added' => 'Item já adicionado à lista de comparação',
'added' => 'Item adicionado com sucesso à lista de comparação',
'removed' => 'Item removido com sucesso da lista de comparação',
'removed-all' => 'Todos os itens removidos com sucesso da lista de comparação',
'empty-text' => "Você não possui nenhum item na sua lista de comparação",
'product_image' => 'Imagem do Produto',
'actions' => 'Ações',
@ -174,6 +175,11 @@ return [
'dashboard' => 'Cliente - Perfil',
'menu' => 'Menu',
'general' => [
'no' => 'Não',
'yes' => 'sim',
],
'profile' => [
'index' => [
'page-title' => 'Cliente - Perfil',

View File

@ -96,6 +96,7 @@ return [
'added' => 'Ürün karşılaştırma listesine başarıyla eklendi.',
'already_added' => 'Ürün zaten karşılaştırma listesinde yer alıyor.',
'removed' => 'Ürün karşılaştırma listesinden başarıyla kaldırıldı.',
'removed-all' => 'Tüm ürünler, karşılaştırma listesinden başarıyla çıkarıldı.',
'empty-text' => "Karşılaştırma listenizde henüz ürün bulunmuyor.",
'product_image' => 'Ürün Görseli',
'actions' => 'Eylemler',
@ -173,6 +174,11 @@ return [
'dashboard' => 'Profil Düzenle',
'menu' => 'Menü',
'general' => [
'no' => 'Hayır',
'yes' => 'Evet',
],
'profile' => [
'index' => [
'page-title' => 'Profil',

View File

@ -16,13 +16,11 @@
<div class="line-one">
<label class="radio-container">
<input v-validate="'required'" type="radio" id="{{ $payment['method'] }}" name="payment[method]" value="{{ $payment['method'] }}" v-model="payment.method" @change="methodSelected()" data-vv-as="&quot;{{ __('shop::app.checkout.onepage.payment-method') }}&quot;">
<span class="checkmark"></span>
<span class="payment-method method-label">
<b>{{ $payment['method_title'] }}</b>
</span>
</label>
<span class="payment-method method-label">
<b>{{ $payment['method_title'] }}</b>
</span>
</div>
<div class="line-two mt-5">

View File

@ -3,7 +3,7 @@
@include('shop::guest.compare.compare-products')
@section('page_title')
{{ __('velocity::app.customer.compare.compare_similar_items') }}
{{ __('shop::app.customer.compare.compare_similar_items') }}
@endsection
@section('content-wrapper')

View File

@ -21,7 +21,7 @@
@if ($order->canCancel())
<a href="{{ route('customer.orders.cancel', $order->id) }}" class="btn btn-lg btn-primary" v-alert:message="'{{ __('shop::app.customer.account.order.view.cancel-confirm-msg') }}'">
<a href="{{ route('customer.orders.cancel', $order->id) }}" class="btn btn-lg btn-primary" v-alert:message="'{{ __('shop::app.customer.account.order.view.cancel-confirm-msg') }}'" style="float: right;">
{{ __('shop::app.customer.account.order.view.cancel-btn-title') }}
</a>
@endif

View File

@ -1,13 +1,17 @@
@php
$attributeRepository = app('\Webkul\Attribute\Repositories\AttributeRepository');
$comparableAttributes = $attributeRepository->findByField('is_comparable', 1);
$attributeRepository = app('\Webkul\Attribute\Repositories\AttributeFamilyRepository');
$comparableAttributes = $attributeRepository->getComparableAttributesBelongsToFamily();
$locale = request()->get('locale') ?: app()->getLocale();
$attributeOptionTranslations = DB::table('attribute_option_translations')->where('locale', $locale)->get()->toJson();
@endphp
@push('scripts')
<script type="text/x-template" id="compare-product-template">
<section class="comparison-component">
<h1>
{{ __('velocity::app.customer.compare.compare_similar_items') }}
{{ __('shop::app.customer.compare.compare_similar_items') }}
</h1>
<button
@ -25,13 +29,13 @@
$comparableAttributes = $comparableAttributes->toArray();
array_splice($comparableAttributes, 1, 0, [[
'admin_name' => 'Product Image',
'type' => 'product_image'
'code' => 'product_image',
'admin_name' => __('velocity::app.customer.compare.product_image'),
]]);
array_splice($comparableAttributes, 2, 0, [[
'admin_name' => 'Actions',
'type' => 'action'
'code' => 'addToCartHtml',
'admin_name' => __('velocity::app.customer.compare.actions'),
]]);
@endphp
@ -42,74 +46,90 @@
</td>
<td :key="`title-${index}`" v-for="(product, index) in products">
@switch ($attribute['type'])
@case('text')
@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('textarea')
<span v-html="product.product['{{ $attribute['code'] }}']"></span>
@break;
@case('price')
<span v-html="product.product['{{ $attribute['code'] }}']"></span>
@break;
@case('boolean')
<span
v-text="product.product['{{ $attribute['code'] }}']
? '{{ __('velocity::app.shop.general.yes') }}'
: '{{ __('velocity::app.shop.general.no') }}'"
></span>
@break;
@case('select')
<span v-html="product.product['{{ $attribute['code'] }}']" class="fs16"></span>
@break;
@case('multiselect')
<span v-html="product.product['{{ $attribute['code'] }}']" class="fs16"></span>
@break
@case('file')
<a v-if="product.product['{{ $attribute['code'] }}']" :href="`${baseUrl}/storage/${product.product['{{ $attribute['code'] }}']}`">
<span v-text="product.product['{{ $attribute['code'] }}'].substr(product.product['{{ $attribute['code'] }}'].lastIndexOf('/') + 1)" class="fs16"></span>
<i class='icon sort-down-icon download'></i>
</a>
<span v-else class="fs16">__</span>
@break;
@case('image')
<img v-if="product.product['{{ $attribute['code'] }}']" :src="`${baseUrl}/storage/${product.product['{{ $attribute['code'] }}']}`">
@break;
@case('product_image')
<a :href="`${baseUrl}/${product.url_key}`" class="unset">
<img
class="image-wrapper"
:src="product['product_image']"
:src="product['{{ $attribute['code'] }}']"
:onerror="`this.src='${baseUrl}/vendor/webkul/ui/assets/images/product/large-product-placeholder.png'`" />
</a>
@break
@break
@case('action')
@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;
@break
@endswitch
@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;
@case('checkbox')
<span v-if="product.product['{{ $attribute['code'] }}']" v-html="getAttributeOptions(product['{{ $attribute['code'] }}'] ? product : product.product['{{ $attribute['code'] }}'] ? product.product : null, '{{ $attribute['code'] }}', 'multiple')" class="fs16"></span>
<span v-else class="fs16">__</span>
@break;
@case('select')
<span v-if="product.product['{{ $attribute['code'] }}']" v-html="getAttributeOptions(product['{{ $attribute['code'] }}'] ? product : product.product['{{ $attribute['code'] }}'] ? product.product : null, '{{ $attribute['code'] }}', 'single')" class="fs16"></span>
<span v-else class="fs16">__</span>
@break;
@case ('file')
@case ('image')
<a :href="`${baseUrl}/${product.url_key}`" class="unset">
<img
class="image-wrapper"
:src="'storage/' + product.product['{{ $attribute['code'] }}']"
:onerror="`this.src='${baseUrl}/vendor/webkul/ui/assets/images/product/large-product-placeholder.png'`" />
</a>
@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') }}
{{ __('shop::app.customer.compare.empty-text') }}
</span>
</table>
@ -126,6 +146,7 @@
'products': [],
'isProductListLoaded': false,
'baseUrl': "{{ url()->to('/') }}",
'attributeOptions': JSON.parse(@json($attributeOptionTranslations)),
'isCustomer': '{{ auth()->guard('customer')->user() ? "true" : "false" }}' == "true",
}
},
@ -167,7 +188,7 @@
})
.catch(error => {
this.isProductListLoaded = true;
console.log("{{ __('velocity::app.error.something_went_wrong') }}");
console.log("{{ __('shop::app.common.error') }}");
});
} else {
this.isProductListLoaded = true;
@ -190,7 +211,7 @@
this.$root.addFlashMessages();
})
.catch(error => {
console.log("{{ __('velocity::app.error.something_went_wrong') }}");
console.log("{{ __('shop::app.common.error') }}");
});
} else {
let existingItems = this.getStorageValue('compared_product');
@ -198,17 +219,19 @@
if (productId == "all") {
updatedItems = [];
this.$set(this, 'products', []);
window.flashMessages = [{'type': 'alert-success', 'message': '{{ __('velocity::app.customer.compare.removed-all') }}' }];
window.flashMessages = [{'type': 'alert-success', 'message': '{{ __('shop::app.customer.compare.removed-all') }}' }];
} else {
updatedItems = existingItems.filter(item => item != productId);
this.$set(this, 'products', this.products.filter(product => product.id != productId));
window.flashMessages = [{'type': 'alert-success', 'message': '{{ __('velocity::app.customer.compare.removed') }}' }];
window.flashMessages = [{'type': 'alert-success', 'message': '{{ __('shop::app.customer.compare.removed') }}' }];
}
this.setStorageValue('compared_product', updatedItems);
this.$root.addFlashMessages();
}
this.updateCompareCount();
},
'getDynamicHTML': function (input) {
@ -255,6 +278,64 @@
return true;
},
'getAttributeOptions': function (productDetails, attributeValues, type) {
var attributeOptions = '__';
if (productDetails && attributeValues) {
var attributeItems;
if (type == "multiple") {
attributeItems = productDetails[attributeValues].split(',');
} else if (type == "single") {
attributeItems = productDetails[attributeValues];
}
attributeOptions = this.attributeOptions.filter(option => {
if (type == "multiple") {
if (attributeItems.indexOf(option.attribute_option_id.toString()) > -1) {
return true;
}
} else if (type == "single") {
if (attributeItems == option.attribute_option_id.toString()) {
return true;
}
}
return false;
});
attributeOptions = attributeOptions.map(option => {
return option.label;
});
attributeOptions = attributeOptions.join(', ');
}
return attributeOptions;
},
'updateCompareCount': function () {
if (this.isCustomer == "true" || this.isCustomer == true) {
this.$http.get(`${this.baseUrl}/items-count`)
.then(response => {
$('#compare-items-count').html(response.data.compareProductsCount);
})
.catch(exception => {
window.flashMessages = [{
'type': `alert-error`,
'message': "{{ __('shop::app.common.error') }}"
}];
this.$root.addFlashMessages();
});
} else {
let comparedItems = JSON.parse(localStorage.getItem('compared_product'));
comparedItemsCount = comparedItems ? comparedItems.length : 0;
$('#compare-items-count').html(comparedItemsCount);
}
}
}
});
</script>

View File

@ -3,7 +3,7 @@
@include('shop::guest.compare.compare-products')
@section('page_title')
{{ __('velocity::app.customer.compare.compare_similar_items') }}
{{ __('shop::app.customer.compare.compare_similar_items') }}
@endsection
@section('content-wrapper')

View File

@ -55,7 +55,7 @@
{!! view_render_event('bagisto.shop.layout.header.comppare-item.before') !!}
@php
$showCompare = core()->getConfigData('general.content.shop.compare_option') == "1" ? true : false
$showCompare = core()->getConfigData('general.content.shop.compare_option') == "1" ? true : false
@endphp
@if ($showCompare)
@ -70,8 +70,8 @@
@endguest
style="color: #242424;"
>
<span class="name">{{ __('velocity::app.customer.compare.text') }}</span>
<span class="name">{{ __('shop::app.customer.compare.text') }}</span>
(<span id="compare-items-count"></span>)
</a>
</li>
@endif
@ -202,7 +202,7 @@
<button style="background: none; border: none; padding: 0px;">
<i class="icon icon-search"></i>
</button>
<image-search-component></image-search-component>
<input type="search" name="term" class="search">
@ -297,7 +297,7 @@
localStorage.searched_image_url = self.uploaded_image_url;
queryString = localStorage.searched_terms = analysedResult.join('_');
self.$root.hideLoader();
window.location.href = "{{ route('shop.search.index') }}" + '?term=' + queryString + '&image-search=1';
@ -336,6 +336,23 @@
toggleDropdown(e);
});
@auth('customer')
@php
$compareCount = app('Webkul\Velocity\Repositories\VelocityCustomerCompareProductRepository')
->count([
'customer_id' => auth()->guard('customer')->user()->id,
]);
@endphp
let comparedItems = JSON.parse(localStorage.getItem('compared_product'));
$('#compare-items-count').html({{ $compareCount }});
@endauth
@guest('customer')
let comparedItems = JSON.parse(localStorage.getItem('compared_product'));
$('#compare-items-count').html(comparedItems ? comparedItems.length : 0);
@endguest
function toggleDropdown(e) {
var currentElement = $(e.currentTarget);

View File

@ -18,7 +18,7 @@
template: '#compare-component-template',
data: function () {
data: function () {
return {
'baseUrl': "{{ url()->to('/') }}",
'customer': '{{ auth()->guard('customer')->user() ? "true" : "false" }}' == "true",
@ -37,12 +37,12 @@
'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') }}"
'message': "{{ __('shop::app.common.error') }}"
}];
this.$root.addFlashMessages()
@ -59,14 +59,14 @@
window.flashMessages = [{
'type': `alert-success`,
'message': "{{ __('velocity::app.customer.compare.added') }}"
'message': "{{ __('shop::app.customer.compare.added') }}"
}];
this.$root.addFlashMessages()
} else {
window.flashMessages = [{
'type': `alert-success`,
'message': "{{ __('velocity::app.customer.compare.already_added') }}"
'message': "{{ __('shop::app.customer.compare.already_added') }}"
}];
this.$root.addFlashMessages()
@ -76,12 +76,14 @@
window.flashMessages = [{
'type': `alert-success`,
'message': "{{ __('velocity::app.customer.compare.added') }}"
'message': "{{ __('shop::app.customer.compare.added') }}"
}];
this.$root.addFlashMessages()
}
}
this.updateCompareCount();
},
'getStorageValue': function (key) {
@ -99,6 +101,28 @@
return true;
},
'updateCompareCount': function () {
if (this.customer == "true" || this.customer == true) {
this.$http.get(`${this.baseUrl}/items-count`)
.then(response => {
$('#compare-items-count').html(response.data.compareProductsCount);
})
.catch(exception => {
window.flashMessages = [{
'type': `alert-error`,
'message': "{{ __('shop::app.common.error') }}"
}];
this.$root.addFlashMessages();
});
} else {
let comparedItems = JSON.parse(localStorage.getItem('compared_product'));
comparedItemsCount = comparedItems ? comparedItems.length : 0;
$('#compare-items-count').html(comparedItemsCount);
}
}
}
});
</script>

View File

@ -20,13 +20,13 @@ class ThemeViewFinder extends FileViewFinder
// Extract the $view and the $namespace parts
list($namespace, $view) = $this->parseNamespaceSegments($name);
if (! Str::contains(request()->route()->uri, 'admin/')) {
if (request()->route() !== null && ! Str::contains(request()->route()->uri, 'admin/')) {
$paths = $this->addThemeNamespacePaths($namespace);
try {
return $this->findInPaths($view, $paths);
} catch(\Exception $e) {
if ($namespace != 'shop') {
if ($namespace !== 'shop') {
if (strpos($view, 'shop.') !== false) {
$view = str_replace('shop.', 'shop.' . Themes::current()->code . '.', $view);
}

View File

@ -43,9 +43,7 @@ class Themes
*/
public function __construct()
{
$routeURI = request()->route()->uri;
if (Str::contains(request()->route()->uri, 'admin/')) {
if (request()->route() !== null && Str::contains(request()->route()->uri, 'admin/')) {
$this->defaultThemeCode = Config::get('themes.admin-default', null);
} else {
$this->defaultThemeCode = Config::get('themes.default', null);
@ -66,6 +64,32 @@ class Themes
return $this->themes;
}
/**
* Return list of registered themes
*
* @return array
*/
public function getChannelThemes()
{
$themes = config('themes.themes', []);
$channelThemes = [];
foreach ($themes as $code => $data) {
$channelThemes[] = new Theme(
$code,
isset($data['name']) ? $data['name'] : '',
isset($data['assets_path']) ? $data['assets_path'] : '',
isset($data['views_path']) ? $data['views_path'] : ''
);
if (isset($data['parent']) && $data['parent']) {
$parentThemes[$code] = $data['parent'];
}
}
return $channelThemes;
}
/**
* Check if specified exists
*
@ -79,7 +103,7 @@ class Themes
return true;
}
}
return false;
}
@ -91,8 +115,8 @@ class Themes
public function loadThemes()
{
$parentThemes = [];
if (Str::contains(request()->route()->uri, 'admin/')) {
if (request()->route() !== null && Str::contains(request()->route()->uri, 'admin/')) {
$themes = config('themes.admin-themes', []);
} else {
$themes = config('themes.themes', []);

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
{
"/js/velocity.js": "/js/velocity.js?id=1cccc6e984773916257d",
"/js/velocity.js": "/js/velocity.js?id=f02a5786e854ee22a4bb",
"/css/velocity-admin.css": "/css/velocity-admin.css?id=612d35e452446366eef7",
"/css/velocity.css": "/css/velocity.css?id=72cf9eb7824c25e1dad8"
}

View File

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddChannelToVelocityMetaDataTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('velocity_meta_data', function (Blueprint $table) {
$table->text('channel')->after('locale');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('velocity_meta_data', function (Blueprint $table) {
//
});
}
}

View File

@ -19,8 +19,9 @@ class VelocityMetaDataSeeder extends Seeder
'id' => 1,
'locale' => 'en',
'home_page_content' => "<p>@include('shop::home.advertisements.advertisement-four')@include('shop::home.featured-products') @include('shop::home.product-policy') @include('shop::home.advertisements.advertisement-three') @include('shop::home.new-products') @include('shop::home.advertisements.advertisement-two')</p>",
'header_content_count' => "5",
'channel' => "default",
'home_page_content' => "<p>@include('shop::home.advertisements.advertisement-four')@include('shop::home.featured-products') @include('shop::home.product-policy') @include('shop::home.advertisements.advertisement-three') @include('shop::home.new-products') @include('shop::home.advertisements.advertisement-two')</p>",
'footer_left_content' => __('velocity::app.admin.meta-data.footer-left-raw-content'),
'footer_middle_content' => '<div class="col-lg-6 col-md-12 col-sm-12 no-padding"><ul type="none"><li><a href="https://webkul.com/about-us/company-profile/">About Us</a></li><li><a href="https://webkul.com/about-us/company-profile/">Customer Service</a></li><li><a href="https://webkul.com/about-us/company-profile/">What&rsquo;s New</a></li><li><a href="https://webkul.com/about-us/company-profile/">Contact Us </a></li></ul></div><div class="col-lg-6 col-md-12 col-sm-12 no-padding"><ul type="none"><li><a href="https://webkul.com/about-us/company-profile/"> Order and Returns </a></li><li><a href="https://webkul.com/about-us/company-profile/"> Payment Policy </a></li><li><a href="https://webkul.com/about-us/company-profile/"> Shipping Policy</a></li><li><a href="https://webkul.com/about-us/company-profile/"> Privacy and Cookies Policy </a></li></ul></div>',

View File

@ -214,20 +214,26 @@ class Helper extends Review
*
* @return array
*/
public function getVelocityMetaData($locale = null, $default = true)
public function getVelocityMetaData($locale = null, $channel = null, $default = true)
{
if (! $locale) {
$locale = request()->get('locale') ?: app()->getLocale();
}
if (! $channel) {
$channel = request()->get('channel') ?: 'default';
}
try {
$metaData = $this->velocityMetadataRepository->findOneWhere([
'locale' => $locale
'locale' => $locale,
'channel' => $channel
]);
if (! $metaData && $default) {
$metaData = $this->velocityMetadataRepository->findOneWhere([
'locale' => 'en'
'locale' => 'en',
'channel' => 'default'
]);
}
@ -295,7 +301,7 @@ class Helper extends Review
* @param \Webkul\Product\Contracts\Product $product
* @param bool $list
* @param array $metaInformation
*
*
* @return array
*/
public function formatProduct($product, $list = false, $metaInformation = [])
@ -398,7 +404,7 @@ class Helper extends Review
}
}
}
return $productCollection;
}
}

View File

@ -15,8 +15,16 @@ class ConfigurationController extends Controller
*/
protected $velocityMetaDataRepository;
/**
* Locale
*/
protected $locale;
/**
* Channel
*/
protected $channel;
/**
* Create a new controller instance.
*
@ -28,10 +36,10 @@ class ConfigurationController extends Controller
$this->_config = request('_config');
$this->velocityHelper = app('Webkul\Velocity\Helpers\Helper');
$this->velocityMetaDataRepository = $velocityMetadataRepository;
$this->locale = request()->get('locale') ?: app()->getLocale();
$this->channel = request()->get('channel') ?: 'default';
}
/**
@ -39,12 +47,12 @@ class ConfigurationController extends Controller
*/
public function renderMetaData()
{
$velocityMetaData = $this->velocityHelper->getVelocityMetaData($this->locale, false);
$velocityMetaData = $this->velocityHelper->getVelocityMetaData($this->locale, $this->channel, false);
if (! $velocityMetaData) {
$this->createMetaData($this->locale);
$this->createMetaData($this->locale, $this->channel);
$velocityMetaData = $this->velocityHelper->getVelocityMetaData($this->locale);
$velocityMetaData = $this->velocityHelper->getVelocityMetaData($this->locale, $this->channel);
}
$velocityMetaData->advertisement = $this->manageAddImages(json_decode($velocityMetaData->advertisement, true) ?: []);
@ -112,7 +120,7 @@ class ConfigurationController extends Controller
unset($params['slides']);
$params['locale'] = $this->locale;
// update row
$product = $this->velocityMetaDataRepository->update($params, $id);
@ -125,7 +133,7 @@ class ConfigurationController extends Controller
* @param array $data
* @param int $index
* @param array $advertisement
*
*
* @return array
*/
public function uploadAdvertisementImages($data, $index, $advertisement)
@ -138,13 +146,13 @@ class ConfigurationController extends Controller
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);
@ -153,13 +161,13 @@ class ConfigurationController extends Controller
} 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);
}
}
@ -192,7 +200,7 @@ class ConfigurationController extends Controller
/**
* @param array $data
* @param int $index
*
*
* @return mixed
*/
public function uploadImage($data, $index)
@ -215,7 +223,7 @@ class ConfigurationController extends Controller
/**
* @param array $addImages
*
*
* @return array
*/
public function manageAddImages($addImages)
@ -236,14 +244,15 @@ class ConfigurationController extends Controller
];
}
}
return $imagePaths;
}
private function createMetaData($locale)
private function createMetaData($locale, $channel)
{
\DB::table('velocity_meta_data')->insert([
'locale' => $locale,
'channel' => $channel,
'home_page_content' => "<p>@include('shop::home.advertisements.advertisement-four')@include('shop::home.featured-products') @include('shop::home.product-policy') @include('shop::home.advertisements.advertisement-three') @include('shop::home.new-products') @include('shop::home.advertisements.advertisement-two')</p>",
'footer_left_content' => __('velocity::app.admin.meta-data.footer-left-raw-content'),

View File

@ -93,7 +93,6 @@ class Controller extends BaseController
* @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
*/

View File

@ -130,7 +130,7 @@ class ContentRepository extends Repository
$query = $this->model::orderBy('position', 'ASC');
$velocityMetaData = app('Webkul\Velocity\Helpers\Helper')->getVelocityMetaData();
$headerContentCount = $velocityMetaData->header_content_count;
$headerContentCount = $velocityMetaData->header_content_count ?? '';
$headerContentCount = $headerContentCount != '' ? $headerContentCount : 5;

View File

@ -1,5 +1,7 @@
<template>
<carousel
:rtl="localeDirection == 'rtl'"
:dir="localeDirection"
:id="id"
:navigationEnabled="true"
:paginationEnabled="true"
@ -7,9 +9,9 @@
:loop="loop == 'true' ? true : false"
:autoplay="autoplay == 'true' ? true : false"
:autoplayTimeout="timeout ? parseInt(timeout) : 2000"
:autoplayDirection="sliderDirection ? sliderDirection : 'forward'"
:autoplayDirection="'forward'"
:class="[
'ltr',
localeDirection,
(navigationEnabled == 'hide') ? 'navigation-hide' : '',
(paginationEnabled == 'hide') ? 'pagination-hide' : '',
addClass
@ -30,9 +32,10 @@
'timeout',
'autoplay',
'addClass',
'direction',
'slidesCount',
'slidesPerPage',
'sliderDirection',
'localeDirection',
'navigationEnabled',
'paginationEnabled',
],

View File

@ -3,7 +3,7 @@
<div class="product-image">
<a :title="product.name" :href="`${baseUrl}/${product.slug}`">
<img
:src="product.image"
:src="product.image || product.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" v-if="!isMobile()"></product-quick-view-btn>
@ -43,8 +43,8 @@
<img
loading="lazy"
:alt="product.name"
:src="product.image"
:data-src="product.image"
:src="product.image || product.product_image"
:data-src="product.image || product.product_image"
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`" /> -->

View File

@ -164,7 +164,7 @@ $(document).ready(function () {
},
isMobile: function () {
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i|/mobi/i.test(navigator.userAgent)) {
return true
} else {
return false
@ -339,7 +339,7 @@ $(document).ready(function () {
showLoader: function () {
$('#loader').show();
$('.overlay-loader').show();
document.body.classList.add("modal-open");
},

View File

@ -1,197 +1,199 @@
<?php
return [
'admin' => [
'admin' => [
'system' => [
'velocity' => [
'general' => 'General',
'category' => 'Category',
'settings' => 'Settings',
'extension_name' => 'Velocity Theme',
'error-module-inactive' => 'Warning: Velocity theme status is inactive',
'general' => '一般的な',
'category' => 'カテゴリー',
'settings' => '設定',
'extension_name' => '速度のテーマ',
'error-module-inactive' => '警告Velocityテーマのステータスは非アクティブです',
],
'settings' => [
'channels'=> [
'subscription_bar' => 'Subscription bar content'
'channels' => [
'subscription_bar' => 'サブスクリプションバーのコンテンツ'
],
],
'general' => [
'status' => 'Status',
'active' => 'Active',
'inactive' => 'Inactive',
'general' => [
'status' => '状態',
'active' => 'アクティブ',
'inactive' => '非活性',
],
'category' => [
'all' => 'All',
'left' => 'Left',
'right' => 'Right',
'active' => 'Active',
'custom' => 'Custom',
'inactive' => 'Inactive',
'image-alignment' => 'Image Alignment',
'icon-status' => 'Category Icon Status',
'image-status' => 'Category Image Status',
'sub-category-show' => 'Show Sub Category',
'image-height' => 'Image\'s Height [in Pixel]',
'image-width' => 'Image\'s Width [in Pixel]',
'show-tooltip' => 'Show Category\'s Tooltip',
'num-sub-category' => 'Number Of Sub Category',
'all' => 'すべて',
'left' => '左',
'right' => '正しい',
'active' => 'アクティブ',
'custom' => 'カスタム',
'inactive' => '非活性',
'image-alignment' => '画像の配置',
'icon-status' => 'カテゴリアイコンステータス',
'image-status' => 'カテゴリー画像ステータス',
'sub-category-show' => 'サブカテゴリーを表示',
'image-height' => '画像の高さ(ピクセル単位)',
'image-width' => '画像の幅[ピクセル単位]',
'show-tooltip' => 'カテゴリのツールチップを表示',
'num-sub-category' => 'サブカテゴリーの数',
]
],
'layouts' => [
'velocity' => 'Velocity',
'cms-pages' => 'CMS Pages',
'meta-data' => 'Meta Data',
'category-menu' => 'Category Menu',
'header-content' => 'Header Content',
'velocity' => '速度',
'cms-pages' => 'CMSページ',
'meta-data' => 'メタデータ',
'category-menu' => 'カテゴリーメニュー',
'header-content' => 'ヘッダーコンテンツ',
],
'contents' => [
'self' => 'Self',
'active' => 'Active',
'new-tab' => 'New Tab',
'inactive' => 'Inactive',
'title' => 'Content List',
'select' => '-- Select --',
'add-title' => 'Add Content',
'btn-add-content' => 'Add Content',
'save-btn-title' => 'Save Content',
'autocomplete' => '[Autocomplete]',
'no-result-found' => 'No record found.',
'search-hint' => 'Search product here...',
'mass-delete-success' => 'Selected content deleted successfully.',
'tab' => [
'page' => 'Page Setting',
'content' => 'Content Setting',
'meta_content' => 'Meta Data',
'self' => '自己',
'active' => 'アクティブ',
'new-tab' => '新しいタブ',
'inactive' => '非活性',
'title' => 'コンテンツリスト',
'select' => '- 選択する -',
'add-title' => 'コンテンツを追加',
'btn-add-content' => 'コンテンツを追加',
'save-btn-title' => 'コンテンツを保存',
'autocomplete' => '[オートコンプリート]',
'no-result-found' => 'レコードが見つかりません。',
'search-hint' => 'ここで製品を検索...',
'mass-delete-success' => '選択したコンテンツは正常に削除されました。',
'tab' => [
'page' => 'ページ設定',
'content' => 'コンテンツ設定',
'meta_content' => 'メタデータ',
],
'page' => [
'title' => 'Title',
'status' => 'Status',
'position' => 'Position',
'page' => [
'title' => '題名',
'status' => '状態',
'position' => 'ポジション',
],
'content' => [
'content-type' => 'Content Type',
'custom-title' => 'Custom Title',
'category-slug' => 'Category Slug',
'link-target' => 'Page Link Target',
'custom-product' => 'Store Products',
'custom-heading' => 'Custom Heading',
'catalog-type' => 'Product Catalog Type',
'static-description' => 'Content Description',
'page-link' => 'Page Link [e.g. http://example.com/../../]',
'content' => [
'content-type' => 'コンテンツタイプ',
'custom-title' => 'カスタムタイトル',
'category-slug' => 'カテゴリースラッグ',
'link-target' => 'ページリンクターゲット',
'custom-product' => 'ストア製品',
'custom-heading' => 'カスタム見出し',
'catalog-type' => '製品カタログのタイプ',
'static-description' => 'コンテンツの説明',
'page-link' => 'ページリンク[例: http://example.com/../../]',
],
'datagrid' => [
'id' => 'Id',
'title' => 'Title',
'status' => 'Status',
'position' => 'Position',
'content-type' => 'Content Type',
'datagrid' => [
'id' => 'Id',
'title' => '題名',
'status' => '状態',
'position' => 'ポジション',
'content-type' => 'コンテンツタイプ',
]
],
'meta-data' => [
'footer' => 'Footer',
'title' => 'Velocity meta data',
'activate-slider' => 'Activate Slider',
'home-page-content' => 'Home Page Content',
'footer-left-content' => 'Footer Left Content',
'subscription-content' => 'Subscription bar Content',
'sidebar-categories' => 'Sidebar Categories',
'header_content_count' => 'Header Content Count',
'footer-left-raw-content' => '<p>We love to craft softwares and solve the real world problems with the binaries. We are highly committed to our goals. We invest our resources to create world class easy to use softwares and applications for the enterprise business with the top notch, on the edge technology expertise.</p>',
'slider-path' => 'Slider Path',
'category-logo' => 'Category logo',
'product-policy' => 'Product Policy',
'update-meta-data' => 'Update Meta Data',
'product-view-image' => 'Product View Image',
'advertisement-two' => 'Advertisement Two Images',
'advertisement-one' => 'Advertisement One Images',
'footer-middle-content' => 'Footer Middle Content',
'advertisement-four' => 'Advertisement Four Images',
'advertisement-three' => 'Advertisement Three Images',
'images' => 'Images',
'general' => 'General',
'add-image-btn-title' => 'Add Image'
'footer' => 'フッター',
'title' => '速度メタデータ',
'activate-slider' => 'スライダーをアクティブにする',
'home-page-content' => 'ホームページコンテンツ',
'footer-left-content' => 'フッター左コンテンツ',
'subscription-content' => 'サブスクリプションバーのコンテンツ',
'sidebar-categories' => 'サイドバーのカテゴリ',
'header_content_count' => 'ヘッダーコンテンツ数',
'footer-left-raw-content' => '<p>私たちはソフトウェアを作成し、バイナリで現実世界の問題を解決するのが大好きです。私達は私達の目標に非常にコミットしています。私たちはリソースを投資して、最先端のテクノロジーの専門知識を活用し、一流のエンタープライズビジネス向けの使いやすいソフトウェアとアプリケーションを作成します。</p>',
'slider-path' => 'スライダーパス',
'category-logo' => 'カテゴリーロゴ',
'product-policy' => '製品ポリシー',
'update-meta-data' => 'メタデータを更新',
'product-view-image' => '製品ビュー画像',
'advertisement-two' => '広告2つの画像',
'advertisement-one' => '広告1つの画像',
'footer-middle-content' => 'フッターミドルコンテンツ',
'advertisement-four' => '広告4つの画像',
'advertisement-three' => '広告3つの画像',
'images' => '画像',
'general' => '一般的な',
'add-image-btn-title' => '画像を追加'
],
'category' => [
'save-btn-title' => 'Save Menu',
'title' => 'Category Menu List',
'add-title' => 'Add Menu Content',
'edit-title' => 'Edit Menu Content',
'btn-add-category' => 'Add Category Content',
'datagrid' => [
'category-id' => 'Category Id',
'category-name' => 'Category Name',
'category-icon' => 'Category Icon',
'category-status' => 'Status',
'save-btn-title' => '保存メニュー',
'title' => 'カテゴリーメニュー一覧',
'add-title' => 'メニューコンテンツを追加',
'edit-title' => 'メニューコンテンツの編集',
'btn-add-category' => 'カテゴリコンテンツを追加',
'datagrid' => [
'category-id' => 'カテゴリID',
'category-name' => '種別名',
'category-icon' => 'カテゴリーアイコン',
'category-status' => '状態',
],
'tab' => [
'general' => 'General',
'tab' => [
'general' => '一般的な',
],
'status' => 'Status',
'active' => 'Active',
'inactive' => 'Inactive',
'select' => '-- Select --',
'icon-class' => 'Icon Class',
'select-category' => 'Choose Category',
'tooltip-content' => 'Tooltip Content',
'mass-delete-success' => 'Selected categories menu deleted successfully.',
'status' => '状態',
'active' => 'アクティブ',
'inactive' => '非活性',
'select' => '- 選択する -',
'icon-class' => 'アイコンクラス',
'select-category' => 'カテゴリーを選択',
'tooltip-content' => 'ツールチップの内容',
'mass-delete-success' => '選択したカテゴリメニューを削除しました。',
],
'general' => [
'locale_logo' => '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',
'popular-categories' => 'Popular Categories',
'home' => [
'view-all' => 'すべてを見る',
'add-to-cart' => 'カートに追加',
'hot-categories' => '人気のカテゴリ',
'payment-methods' => 'お支払い方法',
'customer-reviews' => 'カスタマーレビュー',
'shipping-methods' => '輸送方法',
'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' => 'カート',
'guest' => 'ゲスト',
'logout' => 'ログアウト',
'title' => 'アカウント',
'account' => 'アカウント',
'profile' => 'プロフィール',
'wishlist' => 'ウィッシュリスト',
'all-categories' => 'すべてのカテゴリ',
'search-text' => 'ここで製品を検索',
'welcome-message' => 'ようこそ、:customer_name',
'dropdown-text' => 'カート、注文、ウィッシュリストを管理する',
],
'menu-navbar' => [
'text-more' => 'More',
'text-category' => 'Shop by Category',
'menu-navbar' => [
'text-more' => 'もっと',
'text-category' => 'カテゴリーで選ぶ',
],
'minicart' => [
'cart' => 'Cart',
'view-cart' => 'View Cart',
'minicart' => [
'cart' => 'カート',
'view-cart' => 'カート',
],
'checkout' => [
'qty' => 'Qty',
'checkout' => 'Checkout',
'checkout' => [
'qty' => '数量',
'checkout' => 'チェックアウト',
'cart' => [
'view-cart' => 'View Cart',
'cart-summary' => 'Cart Summary',
'view-cart' => 'かごの中身を見る',
'cart-summary' => 'カートの概要',
],
'qty' => 'Qty',
'items' => 'Items',
'subtotal' => 'Subtotal',
'sub-total' => 'Sub Total',
'proceed' => 'Proceed to checkout',
'qty' => '数量',
'items' => 'アイテム',
'subtotal' => '小計',
'sub-total' => '小計',
'proceed' => 'チェックアウトに進む',
],
'customer' => [
'customer' => [
'compare' => [
'text' => '比較する',
'compare_similar_items' => '類似アイテムを比較する',
@ -200,85 +202,84 @@ return [
'already_added' => 'アイテムは比較リストに既に追加されています',
'removed' => '比較リストからアイテムを削除しました',
'empty-text' => "比較リストにアイテムがありません",
'product_image' => 'Product Image',
'actions' => 'Actions',
'product_image' => '商品画像',
'actions' => '行動',
],
'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.',
'sign-up' => 'サインアップ',
'new-customer' => '新規のお客様',
'customer-login' => 'お客様ログイン',
'registered-user' => '登録ユーザー',
'your-email-address' => 'メールアドレス',
'form-login-text' => 'アカウントをお持ちの場合は、メールアドレスでログインしてください。',
],
'signup-form' => [
'login' => 'Login',
'become-user' => 'Become User',
'user-registration' => 'User Registration',
'form-sginup-text' => 'If you are new to our store, we glad to have you as member.',
'login' => 'ログインする',
'become-user' => 'ユーザーになる',
'user-registration' => 'ユーザー登録',
'form-sginup-text' => 'あなたが私たちの店に初めている場合は、メンバーとして喜んでいます。',
],
'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.',
'login' => 'ログインする',
'forgot-password' => 'パスワードをお忘れですか',
'recover-password' => 'パスワードを回復',
'recover-password-text' => 'パスワードを忘れた場合は、メールアドレスを入力してパスワードを回復してください。',
]
],
'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.",
'error' => [
'go-to-home' => '家に帰る',
'page-lost-short' => 'ページが失われたコンテンツ',
'something_went_wrong' => '問題が発生しました',
'page-lost-description' => "お探しのページはご利用いただけません。もう一度検索するか、下の[戻る]ボタンを使用してください。",
],
'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',
'products' => [
'text' => '製品',
'details' => '細部',
'reviews-title' => 'レビュー',
'reviewed' => '審査',
'review-by' => 'によるレビュー',
'quick-view' => 'クイックビュー',
'not-available' => '利用不可',
'submit-review' => 'レビュー送信',
'ratings' => ':totalRatings 評価',
'reviews-count' => ':totalReviews レビュー',
'customer-rating' => 'お客様の評価',
'more-infomation' => '詳しくは',
'view-all-reviews' => 'すべてのレビューを表示',
'write-your-review' => 'レビューを書く',
'short-description' => '短い説明',
'recently-viewed' => '最近見た製品',
'be-first-review' => '最初のレビューを書く',
],
'shop' => [
'shop' => [
'gender' => [
'male' => 'Male',
'other' => 'Other',
'female' => 'Female',
'male' => '男性',
'other' => 'その他の',
'female' => '女性',
],
'general' => [
'no' => 'No',
'yes' => 'Yes',
'view' => 'View',
'filter' => 'Filter',
'orders' => 'Orders',
'update' => 'Update',
'reviews' => 'Reviews',
'currencies' => 'Currencies',
'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',
'no' => '番号',
'yes' => 'はい',
'view' => '見る',
'filter' => 'フィルタ',
'orders' => '注文',
'update' => '更新',
'reviews' => 'レビュー',
'currencies' => '通貨',
'addresses' => '住所',
'top-brands' => 'トップブランド',
'new-password' => '新しいパスワード',
'downloadables' => 'ダウンロード可能な製品',
'confirm-new-password' => '新しいパスワードを確認',
'enter-current-password' => '現在のパスワードを入力してください',
'alert' => [
'info' => 'Info',
'error' => 'Error',
'success' => 'Success',
'warning' => 'Warning',
'info' => '情報',
'error' => 'エラー',
'success' => '成功',
'warning' => '警告',
],
],
'wishlist' => [
@ -287,13 +288,11 @@ return [
]
],
'responsive' => [
'responsive' => [
'header' => [
'done' => 'Done',
'languages' => 'Languages',
'greeting' => 'Welcome, :customer !',
'done' => 'できた',
'languages' => '言語',
'greeting' => 'ようこそ、:customer !',
]
],
]
?>
];

View File

@ -7,7 +7,7 @@
</label>
@php
$pageTarget = isset($locale) ? (old($locale)['page_link'] ?? (isset($content) ? $content->translate($locale)['page_link'] : '')) : '';
$pageTarget = isset($locale) ? (old($locale)['page_link'] ?? (isset($content) ? $content->translate($locale) ? $content->translate($locale)['page_link'] : '' : '')) : '';
@endphp
<input
@ -31,7 +31,7 @@
</label>
@php
$linkTarget = isset($locale) ? (old($locale)['link_target'] ?? (isset($content) ? $content->translate($locale)['link_target'] : '')) : '';
$linkTarget = isset($locale) ? (old($locale)['link_target'] ?? (isset($content) ? $content->translate($locale) ? $content->translate($locale)['link_target'] : '' : '')) : '';
@endphp
<select class="control" id="link_target" name="{{$locale}}[link_target]" value="">

View File

@ -6,7 +6,7 @@
@push('scripts')
<script type="text/x-template" id="catalog-product-template">
<div>
<?php $catalogType = old($locale)['catalog_type'] ?? (isset($content) ? $content->translate($locale)['catalog_type'] : ''); ?>
<?php $catalogType = old($locale)['catalog_type'] ?? (isset($content) ? $content->translate($locale) ? $content->translate($locale)['catalog_type'] : '' : ''); ?>
<div class="control-group" :class="[errors.has('{{$locale}}[catalog_type]') ? 'has-error' : '']">
<label for="catalog_type" class="required">

View File

@ -8,6 +8,7 @@
<div class="content">
@php
$locale = request()->get('locale') ?: app()->getLocale();
$translation = $content->translations->where('locale', $locale)->first();
@endphp
<form
@ -61,7 +62,7 @@
{{ __('velocity::app.admin.contents.page.title') }}
<span class="locale">[{{ $locale }}]</span>
</label>
<input type="text" v-validate="'required|max:100'" class="control" id="title" name="{{$locale}}[title]" value="{{ old($locale)['title'] ?? $content->translate($locale)['title'] }}" data-vv-as="&quot;{{ __('velocity::app.admin.contents.page.title') }}&quot;"/>
<input type="text" v-validate="'required|max:100'" class="control" id="title" name="{{$locale}}[title]" value="{{ old($locale)['title'] ?? isset($translation->title) ? $translation->title : '' }}" data-vv-as="&quot;{{ __('velocity::app.admin.contents.page.title') }}&quot;"/>
<span class="control-error" v-if="errors.has('{{$locale}}[title]')">@{{ errors.first('{!!$locale!!}[title]') }}</span>
</div>
@ -134,7 +135,7 @@
id="custom_title"
v-validate="'max:100'"
name="{{$locale}}[custom_title]"
value="{{ old($locale)['custom_title'] ?? ($content->translate($locale)['custom_title'] ?? '') }}"
value="{{ old($locale)['custom_title'] ?? ($content->translate($locale) ? $content->translate($locale)['custom_title'] : '' ?? '') }}"
data-vv-as="&quot;{{ __('velocity::app.admin.contents.content.custom-title') }}&quot;" />
<span
@ -156,7 +157,7 @@
id="custom_heading"
v-validate="'max:100'"
name="{{$locale}}[custom_heading]"
value="{{ old($locale)['custom_heading'] ?? $content->translate($locale)['custom_title'] }}" data-vv-as="&quot;{{ __('velocity::app.admin.contents.content.custom-heading') }}&quot;" />
value="{{ old($locale)['custom_heading'] ?? $content->translate($locale) ? $content->translate($locale)['custom_title'] : '' }}" data-vv-as="&quot;{{ __('velocity::app.admin.contents.content.custom-heading') }}&quot;" />
<span
class="control-error"
@ -219,7 +220,7 @@
class="control"
name="{{$locale}}[page_link]"
v-validate="'required|max:150'"
value="{{ old($locale)['page_link'] ?? $content->translate($locale)['page_link'] }}"
value="{{ old($locale)['page_link'] ?? $content->translate($locale) ? $content->translate($locale)['page_link'] : '' }}"
data-vv-as="&quot;{{ __('velocity::app.admin.contents.content.page-link') }}&quot;" />
<span
@ -266,7 +267,7 @@
v-validate="'required'"
name="{{$locale}}[description]"
data-vv-as="&quot;{{ __('velocity::app.admin.contents.content.static-description') }}&quot;">
{{ old($locale)['description'] ?? $content->translate($locale)['description'] }}
{{ old($locale)['description'] ?? $content->translate($locale) ? $content->translate($locale)['description'] : '' }}
</textarea>
<span

View File

@ -6,6 +6,7 @@
@php
$locale = request()->get('locale') ?: app()->getLocale();
$channel = request()->get('channel') ?: core()->getCurrentChannelCode();
@endphp
@section('content')
@ -29,12 +30,25 @@
</div>
<input type="hidden" name="locale" value="{{ $locale }}" />
<input type="hidden" name="channel" value="{{ $channel }}" />
<div class="control-group">
<select class="control" id="channel-switcher" onChange="window.location.href = this.value">
@foreach (core()->getAllChannels() as $ch)
<option value="{{ route('velocity.admin.meta-data') . '?channel=' . $ch->code . '&locale=' . $locale }}" {{ ($ch->code) == $channel ? 'selected' : '' }}>
{{ $ch->name }}
</option>
@endforeach
</select>
</div>
<div class="control-group">
<select class="control" id="locale-switcher" onChange="window.location.href = this.value">
@foreach (core()->getAllLocales() as $localeModel)
<option value="{{ route('velocity.admin.meta-data') . '?locale=' . $localeModel->code }}" {{ ($localeModel->code) == $locale ? 'selected' : '' }}>
<option value="{{ route('velocity.admin.meta-data') . '?locale=' . $localeModel->code . '&channel=' . $channel }}" {{ ($localeModel->code) == $locale ? 'selected' : '' }}>
{{ $localeModel->name }}
</option>
@ -62,7 +76,7 @@
class="control"
data-vv-as="&quot;slides&quot;"
{{ $metaData && $metaData->slider ? 'checked' : ''}} />
<span class="slider round"></span>
</label>
</div>
@ -112,7 +126,10 @@
</div>
<div class="control-group">
<label style="width:100%;">{{ __('velocity::app.admin.meta-data.home-page-content') }} <span class="locale">[{{ $metaData ? $metaData->locale : 'en' }}]</span></label>
<label style="width:100%;">
{{ __('velocity::app.admin.meta-data.home-page-content') }}
<span class="locale">[{{ $metaData ? $metaData->channel : $channel }} - {{ $metaData ? $metaData->locale : $locale }}]</span>
</label>
<textarea
class="control"
@ -123,7 +140,10 @@
</div>
<div class="control-group">
<label style="width:100%;">{{ __('velocity::app.admin.meta-data.product-policy') }} <span class="locale">[{{ $metaData ? $metaData->locale : 'en' }}]</span></label>
<label style="width:100%;">
{{ __('velocity::app.admin.meta-data.product-policy') }}
<span class="locale">[{{ $metaData ? $metaData->channel : $channel }} - {{ $metaData ? $metaData->locale : $locale }}]</span>
</label>
<textarea
class="control"
@ -149,10 +169,9 @@
];
$index = 0;
$currentLocale = request()->get('locale') ?: core()->getCurrentLocale();
foreach ($metaData->get('locale')->all() as $key => $value) {
if ($value->locale == $currentLocale) {
if ($value->locale == $locale) {
$index = $key;
}
}
@ -240,7 +259,10 @@
<accordian :title="'{{ __('velocity::app.admin.meta-data.footer') }}'" :active="false">
<div slot="body">
<div class="control-group">
<label style="width:100%;">{{ __('velocity::app.admin.meta-data.subscription-content') }} <span class="locale">[{{ $metaData ? $metaData->locale : 'en' }}]</span></label>
<label style="width:100%;">
{{ __('velocity::app.admin.meta-data.subscription-content') }}
<span class="locale">[{{ $metaData ? $metaData->channel : $channel }} - {{ $metaData ? $metaData->locale : $locale }}]</span>
</label>
<textarea
class="control"
@ -251,7 +273,10 @@
</div>
<div class="control-group">
<label style="width:100%;">{{ __('velocity::app.admin.meta-data.footer-left-content') }} <span class="locale">[{{ $metaData ? $metaData->locale : 'en' }}]</span></label>
<label style="width:100%;">
{{ __('velocity::app.admin.meta-data.footer-left-content') }}
<span class="locale">[{{ $metaData ? $metaData->channel : $channel }} - {{ $metaData ? $metaData->locale : $locale }}]</span>
</label>
<textarea
class="control"
@ -262,7 +287,10 @@
</div>
<div class="control-group">
<label style="width:100%;">{{ __('velocity::app.admin.meta-data.footer-middle-content') }} <span class="locale">[{{ $metaData ? $metaData->locale : 'en' }}]</span></label>
<label style="width:100%;">
{{ __('velocity::app.admin.meta-data.footer-middle-content') }}
<span class="locale">[{{ $metaData ? $metaData->channel : $channel }} - {{ $metaData ? $metaData->locale : $locale }}]</span>
</label>
<textarea
class="control"

View File

@ -1,6 +1,10 @@
@php
$attributeRepository = app('\Webkul\Attribute\Repositories\AttributeRepository');
$comparableAttributes = $attributeRepository->findByField('is_comparable', 1);
$attributeRepository = app('\Webkul\Attribute\Repositories\AttributeFamilyRepository');
$comparableAttributes = $attributeRepository->getComparableAttributesBelongsToFamily();
$locale = request()->get('locale') ?: app()->getLocale();
$attributeOptionTranslations = DB::table('attribute_option_translations')->where('locale', $locale)->get()->toJson();
@endphp
@push('css')
@ -39,13 +43,13 @@
$comparableAttributes = $comparableAttributes->toArray();
array_splice($comparableAttributes, 1, 0, [[
'admin_name' => 'Product Image',
'type' => 'product_image'
'code' => 'product_image',
'admin_name' => __('velocity::app.customer.compare.product_image'),
]]);
array_splice($comparableAttributes, 2, 0, [[
'admin_name' => 'Actions',
'type' => 'action'
'code' => 'addToCartHtml',
'admin_name' => __('velocity::app.customer.compare.actions'),
]]);
@endphp
@ -56,67 +60,91 @@
</td>
<td :key="`title-${index}`" v-for="(product, index) in products">
@switch ($attribute['type'])
@case('text')
<a :href="`${baseUrl}/${product.url_key}`" class="unset remove-decoration active-hover">
<h3 class="fw6 fs18" v-text="product['{{ $attribute['code'] }}']"></h3>
@switch ($attribute['code'])
@case('name')
<a :href="`${$root.baseUrl}/${product.url_key}`" class="unset remove-decoration active-hover">
<h1 class="fw6 fs18" v-text="product['{{ $attribute['code'] }}']"></h1>
</a>
@break;
@case('textarea')
<span v-html="product.product['{{ $attribute['code'] }}']"></span>
@break;
@case('price')
<span v-html="product.product['{{ $attribute['code'] }}']"></span>
@break;
@case('boolean')
<span
v-text="product.product['{{ $attribute['code'] }}']
? '{{ __('velocity::app.shop.general.yes') }}'
: '{{ __('velocity::app.shop.general.no') }}'"
></span>
@break;
@case('select')
<span v-html="product.product['{{ $attribute['code'] }}']" class="fs16"></span>
@break;
@case('multiselect')
<span v-html="product.product['{{ $attribute['code'] }}']" class="fs16"></span>
@break
@case('file')
<a v-if="product.product['{{ $attribute['code'] }}']" :href="`${baseUrl}/storage/${product.product['{{ $attribute['code'] }}']}`">
<span v-text="product.product['{{ $attribute['code'] }}'].substr(product.product['{{ $attribute['code'] }}'].lastIndexOf('/') + 1)" class="fs16"></span>
<i class='icon sort-down-icon download'></i>
</a>
<span v-else class="fs16">__</span>
@break;
@case('image')
<img v-if="product.product['{{ $attribute['code'] }}']" :src="`${baseUrl}/storage/${product.product['{{ $attribute['code'] }}']}`">
@break;
@case('product_image')
<a :href="`${baseUrl}/${product.url_key}`" class="unset">
<a :href="`${$root.baseUrl}/${product.url_key}`" class="unset">
<img
class="image-wrapper"
:src="product['product_image']"
:onerror="`this.src='${baseUrl}/vendor/webkul/ui/assets/images/product/large-product-placeholder.png'`" />
:src="product['{{ $attribute['code'] }}']"
onload="window.updateHeight ? window.updateHeight() : ''"
:onerror="`this.src='${$root.baseUrl}/vendor/webkul/ui/assets/images/product/large-product-placeholder.png'`" />
</a>
@break
@break
@case('action')
@case('price')
<span v-html="product['priceHTML']"></span>
@break
@case('addToCartHtml')
<div class="action">
<div v-html="product.defaultAddToCart"></div>
<vnode-injector :nodes="getDynamicHTML(product.addToCartHtml)"></vnode-injector>
<span class="icon white-cross-sm-icon remove-product" @click="removeProductCompare(product.id)"></span>
<i
class="material-icons cross fs16"
@click="removeProductCompare(product.id)">
close
</i>
</div>
@break;
@break
@endswitch
@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;
@case('checkbox')
<span v-if="product.product['{{ $attribute['code'] }}']" v-html="getAttributeOptions(product['{{ $attribute['code'] }}'] ? product : product.product['{{ $attribute['code'] }}'] ? product.product : null, '{{ $attribute['code'] }}', 'multiple')" class="fs16"></span>
<span v-else class="fs16">__</span>
@break;
@case('select')
<span v-if="product.product['{{ $attribute['code'] }}']" v-html="getAttributeOptions(product['{{ $attribute['code'] }}'] ? product : product.product['{{ $attribute['code'] }}'] ? product.product : null, '{{ $attribute['code'] }}', 'single')" class="fs16"></span>
<span v-else class="fs16">__</span>
@break;
@case ('file')
@case ('image')
<a :href="`${$root.baseUrl}/${product.url_key}`" class="unset">
<img
class="image-wrapper"
onload="window.updateHeight ? window.updateHeight() : ''"
:src="'storage/' + product.product['{{ $attribute['code'] }}']"
:onerror="`this.src='${$root.baseUrl}/vendor/webkul/ui/assets/images/product/large-product-placeholder.png'`" />
</a>
@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
@ -139,6 +167,7 @@
return {
'products': [],
'isProductListLoaded': false,
'attributeOptions': JSON.parse(@json($attributeOptionTranslations)),
'isCustomer': '{{ auth()->guard('customer')->user() ? "true" : "false" }}' == "true",
}
},
@ -231,6 +260,42 @@
this.$root.headerItemsCount++;
},
'getAttributeOptions': function (productDetails, attributeValues, type) {
var attributeOptions = '__';
if (productDetails && attributeValues) {
var attributeItems;
if (type == "multiple") {
attributeItems = productDetails[attributeValues].split(',');
} else if (type == "single") {
attributeItems = productDetails[attributeValues];
}
attributeOptions = this.attributeOptions.filter(option => {
if (type == "multiple") {
if (attributeItems.indexOf(option.attribute_option_id.toString()) > -1) {
return true;
}
} else if (type == "single") {
if (attributeItems == option.attribute_option_id.toString()) {
return true;
}
}
return false;
});
attributeOptions = attributeOptions.map(option => {
return option.label;
});
attributeOptions = attributeOptions.join(', ');
}
return attributeOptions;
}
}
});
</script>

View File

@ -44,6 +44,7 @@
navigation-enabled="hide"
pagination-enabled="hide"
id="wishlist-products-carousel"
locale-direction="{{ core()->getCurrentLocale()->direction == 'rtl' ? 'rtl' : 'ltr' }}"
:slides-count="products.length">
<slide

View File

@ -21,6 +21,7 @@
navigation-enabled="hide"
pagination-enabled="hide"
:slides-count="categoryProducts.length"
locale-direction="{{ core()->getCurrentLocale()->direction == 'rtl' ? 'rtl' : 'ltr' }}"
:id="`${categoryDetails.name}-carousel`">
<slide
@ -41,6 +42,7 @@
navigation-enabled="hide"
pagination-enabled="hide"
:slides-count="categoryProducts.length"
locale-direction="{{ core()->getCurrentLocale()->direction == 'rtl' ? 'rtl' : 'ltr' }}"
:id="`${categoryDetails.name}-carousel`">
<slide

View File

@ -1,5 +1,6 @@
@php
$count = $velocityMetaData ? $velocityMetaData->featured_product_count : 10;
$direction = core()->getCurrentLocale()->direction == 'rtl' ? 'rtl' : 'ltr';
@endphp
<featured-products></featured-products>
@ -13,12 +14,14 @@
<card-list-header heading="{{ __('shop::app.home.featured-products') }}">
</card-list-header>
<div class="carousel-products vc-full-screen ltr" v-if="!isMobileView">
<div class="carousel-products vc-full-screen {{ $direction }}" v-if="!isMobileView">
<carousel-component
slides-per-page="6"
navigation-enabled="hide"
pagination-enabled="hide"
id="fearured-products-carousel"
locale-direction="{{ $direction }}"
:autoplay="false"
:slides-count="featuredProducts.length">
<slide
@ -33,12 +36,13 @@
</carousel-component>
</div>
<div class="carousel-products vc-small-screen" v-else>
<div class="carousel-products vc-small-screen {{ $direction }}" v-else>
<carousel-component
slides-per-page="2"
navigation-enabled="hide"
pagination-enabled="hide"
id="fearured-products-carousel"
locale-direction="{{ $direction }}"
:slides-count="featuredProducts.length">
<slide

View File

@ -1,5 +1,6 @@
@php
$count = $velocityMetaData ? $velocityMetaData->new_products_count : 10;
$direction = core()->getCurrentLocale()->direction == 'rtl' ? 'rtl' : 'ltr';
@endphp
<new-products></new-products>
@ -27,13 +28,14 @@
</style>
@endpush
<div class="row ltr">
<div class="row {{ $direction }}">
<div class="col-9 no-padding carousel-products vc-full-screen with-recent-viewed" v-if="!isMobileView">
<carousel-component
slides-per-page="5"
navigation-enabled="hide"
pagination-enabled="hide"
id="new-products-carousel"
locale-direction="{{ $direction }}"
:slides-count="newProducts.length">
<slide
@ -54,6 +56,7 @@
navigation-enabled="hide"
pagination-enabled="hide"
id="new-products-carousel"
locale-direction="{{ $direction }}"
:slides-count="newProducts.length">
<slide
@ -74,12 +77,13 @@
])
</div>
@else
<div class="carousel-products vc-full-screen" v-if="!isMobileView">
<div class="carousel-products vc-full-screen {{ $direction }}" v-if="!isMobileView">
<carousel-component
slides-per-page="6"
navigation-enabled="hide"
pagination-enabled="hide"
id="new-products-carousel"
locale-direction="{{ $direction }}"
:slides-count="newProducts.length">
<slide
@ -94,12 +98,13 @@
</carousel-component>
</div>
<div class="carousel-products vc-small-screen" v-else>
<div class="carousel-products vc-small-screen {{ $direction }}" v-else>
<carousel-component
slides-per-page="2"
navigation-enabled="hide"
pagination-enabled="hide"
id="new-products-carousel"
locale-direction="{{ $direction }}"
:slides-count="newProducts.length">
<slide

View File

@ -8,14 +8,14 @@
@push('scripts')
<script type="text/x-template" id="slider-template">
<div class="slides-container ltr">
<div class="slides-container {{ $direction }}">
<carousel-component
loop="true"
timeout="5000"
autoplay="true"
slides-per-page="1"
navigation-enabled="hide"
:slider-direction="direction == 'rtl' ? 'backward' : 'forward'"
locale-direction="direction"
:slides-count="{{ ! empty($sliderData) ? sizeof($sliderData) : 1 }}">
@if (! empty($sliderData))

View File

@ -58,8 +58,9 @@
<img
src="{{ $productBaseImage['medium_image_url'] }}"
:onerror="`this.src='${this.$root.baseUrl}/vendor/webkul/ui/assets/images/product/large-product-placeholder.png'`" />
<product-quick-view-btn :quick-view-details="{{ json_encode($product) }}"></product-quick-view-btn>
<div class="quick-view-in-list">
<product-quick-view-btn :quick-view-details="{{ json_encode($product) }}"></product-quick-view-btn>
</div>
</a>
</div>

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