Merge branch 'master' into add_tests_for_cart_rules

This commit is contained in:
SteffenMahler 2020-04-29 10:31:06 +02:00 committed by GitHub
commit ede46da84b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
243 changed files with 6448 additions and 3155 deletions

View File

@ -1,13 +1,13 @@
APP_NAME=Bagisto
APP_ENV=local
APP_VERSION=1.1.0
APP_VERSION=1.1.2
APP_KEY=
APP_DEBUG=true
APP_URL=http://localhost
APP_TIMEZONE=
APP_TIMEZONE=Asia/Kolkata
APP_LOCALE=en
LOG_CHANNEL=stack
APP_CURRENCY=
APP_CURRENCY=USD
DB_CONNECTION=mysql
DB_HOST=127.0.0.1

View File

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

View File

@ -2,7 +2,210 @@
#### This changelog consists the bug & security fixes and new features being included in the releases listed below.
## **v1.1.0 (20th of March 2020)** - *Release*
## **v1.1.2 (24th of March 2020)** - *Release*
* [feature] - Now customer can cancel order.
* [feature] - Auto and manual currency exchange rates update feature added.
* #797 [fixed] - Add new module
* #2453 [fixed] - Velocity theme is not loading on fresh instance
* #2691 [fixed] - Shipping and Payment methods automatically selected on Checkout oage
* #2752 [fixed] - Error when you create or update a new catalog under root
* #2793 [fixed] - Stock Check Incorrect for Configurable Items
* #2826 [fixed] - Not able to view cart icon
* #2869 [fixed] - Updating "Velocity meta data" throws QueryException
* #2871 [fixed] - Refund throws "Undefined index: shipping" error
* #2875 [fixed] - Deleting brands that have been assigned to products causes checkout error
* #2884 [fixed] - Undefined Index slot: when add to cart rental booking
* #2890 [fixed] - cart rule condition (price in cart) always set to equal or less than when select greater than/less than
* #2895 [fixed] - The type hint of view in this blade file is 'address' - there is no tag in any provider which loads view with this type hint.
* #2896 [fixed] - There are two fields with having same value of name attribute one is hidden and other is of its desired type - is this redundant code or its solving any purpose?
* #2897 [fixed] - Inventory status field should be passed through validation for boolean in its backend controller.
* #2898 [fixed] - error when viewing a category and then wanting to change the language of the page in mobile view
* #2899 [fixed] - showing the configured products as radio button
* #2900 [fixed] - getting different variant of a configurable product in front end
* #2901 [fixed] - Error when creating a category
* #2902 [fixed] - unify address tables
* #2908 [fixed] - A class is missing from the Velocity ProductRepositiry file
* #2914 [fixed] - Filter not showing on mobile, also sorting not working on mobile
* #2915 [fixed] - filters are missing on mobile view.
* #2919 [fixed] - Header Content not working on other languages
* #2925 [fixed] - exception for php version 7.4
* #2938 [fixed] - Extend Model Class
* #2939 [fixed] - get product description for API without html tags
* #2940 [fixed] - creating categories have error
* #2943 [fixed] - Scroll images is not working
* #2945 [fixed] - API product detail return empty array
* #2954 [fixed] - The merging cart function does not work when already added all items of product into customer cart
## **v1.1.0 (24th of March 2020)** - *Release*
* #797 [fixed] - Add new module
* #826 [fixed] - Impossible to create the root directory "".
* #2152 [fixed] - Product images are not showing
* #2329 [fixed] - Getting exception on frontend after updating meta data.
* #2354 [fixed] - possible integrate this payment
* #2543 [fixed] - Sliders Text should be translatable
* #2558 [fixed] - Sliders Text should be translatable
* #2619 [fixed] - Issue when category slug & product slug are same
* #2684 [fixed] - API checkout/cart returns null for guest user
* #2691 [fixed] - Shipping and Payment methods automatically selected on Checkout oage
* #2706 [fixed] - Getting exception on editing category for pt_BR locale in php 7.4
* #2708 [fixed] - Able to create booking product from back date.
* #2713 [fixed] - fix the invoice header in pdf
* #2726 [fixed] - is shop.js the vue framework ??
* #2752 [fixed] - Error when you create or update a new catalog under root
* #2763 [fixed] - error to add rental booking into cart
* #2764 [fixed] - fix UI when select back_date of booking product,the calendar icon is set on another place
* #2765 [fixed] - Email settings configuration values are not write in .env file
* #2768 [fixed] - Getting exception in cart when remove one ticket from event booking from backend
* #2769 [fixed] - Can't delete Exchange Rates data
* #2774 [fixed] - How to add new icon in bagisto admin panel?
* #2775 [fixed] - compare icon is missing in each product for default theme
* #2776 [fixed] - compare option in side bar menu at customer panel should be available
* #2778 [fixed] - Issue in customer profile dropdown.
* #2779 [fixed] - Issue on checkout page, email should ask first as in default theme.
* #2780 [fixed] - Sidebar layout issue.
* #2781 [fixed] - Mobile menu is not showing correct sub-menu
* #2784 [fixed] - One booking for many days slot time issue
* #2785 [fixed] - missing address details in checkout page
* #2786 [fixed] - Getting error message on adding product to compare product from search page.
* #2788 [fixed] - guest_checkout is missing from edit product
* #2790 [fixed] - Minicart disable when use new languages only velocity theme
* #2792 [fixed] - Weight Validation Inconsistencies
* #2793 [fixed] - Stock Check Incorrect for Configurable Items
* #2794 [fixed] - When allow backorder is enabled, display a message available for order rather than in stock.
* #2796 [fixed] - Try to create category in windows 10 getting exception
* #2801 [fixed] - Address with more than 2 lines is not added correctly to the cart_address table
* #2807 [fixed] - Illegal mix of collations
* #2808 [fixed] - Correct the spelling on registration page.
* #2810 [fixed] - UI issue on compare similar item page.
* #2811 [fixed] - how to change checkout proccess
* #2812 [fixed] - getting timezone error while setup
* #2813 [fixed] - Ui issue if there is only one product in compare page.
* #2814 [fixed] - variant product's name aren't update when select their options in Front
* #2818 [fixed] - Not able to view menu in velocity theme on storefront
* #2821 [fixed] - Address Line is Null in Emails
* #2825 [fixed] - PHP Notice:
* #2827 [fixed] - default local not changing in storefront in velocity theme
* #2828 [fixed] - currency change error on velocity theme
* #2829 [fixed] - changing home page content in velocity and npm
* #2832 [fixed] - Illegal mix of collations
* #2834 [fixed] - Layout issue in compare page in pt_BR locale
* #2837 [fixed] - subscription bar content source code is not visible in text editor
* #2840 [fixed] - Velocity theme is not available on fresh install
* #2845 [fixed] - Implement custom RegistrationController
* #2846 [fixed] - does not show next step
* #2847 [fixed] - Class 'Faker\Factory' not found
* #2849 [fixed] - Can not add my stylesheet to Velocity theme
* #2850 [fixed] - admin crash on save configration
* #2851 [fixed] - Fix date picker icon layout at dashboard
* #2856 [fixed] - Issue with Sort by functionality, when open any category it by defaults show Newest First but after changing sort by when again select newest first it shows different product.
* #2865 [fixed] - Save order taking so long time 30s
* #2866 [fixed] - ayout issue when customer save addresses form
* #2871 [fixed] - Refund throws "Undefined index: shipping" error
* #2876 [fixed] - Place order is disable at checkout when select shipping address
## **v1.1.0 (24th of March 2020)** - *Release*
* [feature] Added new booking type product.
@ -10,6 +213,8 @@
* [feature] Impletment compare product feature.
* #2525 [fixed] - Add more settings to the installers
* #2541 [fixed] - Showing product's price with the price including tax
* #2552 [fixed] - error mysql 8
@ -72,14 +277,20 @@
* #2606 [fixed] - custom attributes are not Visible on Product View Page on Front-end
* #2607 [fixed] - Getting exception on editing category for pt_BR locale in php 7.4
* #2608 [fixed] - Getting exception on creating category.
* #2609 [fixed] - product removed from comparison page when update product by name
* #2611 [fixed] - installer error
* #2612 [fixed] - available slots are not showing for current date even if slot time is not expired
* #2613 [fixed] - Propaganistas/Laravel-Intl is abandoned
* #2614 [fixed] - table booking slot time is expired still exist in cart
* #2619 [fixed] - Issue when category slug & product slug are same
* #2621 [fixed] - i create a site and it is up kind of noting works
@ -150,7 +361,9 @@
* #2667 [fixed] - By default wishlist option is selected in cart
* #2669 [fixed] - Booking product should be removed from the cart when selected slot time expired
* #2670 [fixed] - Booking product should be removed from the cart when selected slot time expired
* #2669 [fixed] - Browser compatibility issue
* #2671 [fixed] - Error on moving booking product to wishlist
@ -164,7 +377,25 @@
* #2693 [fixed] - Booking product page - add to cart button js error
* #2707 [fixed] Getting exception when generate invoice in appointment booking
* #2704 [fixed] - product's assigned category can't be removed
* #2707 [fixed] - Getting exception when generate invoice in appointment booking
* #2715 [fixed] - Error message should throw if "To" time is less than "From".
* #2716 [fixed] - After saving the default booking time product selected time for date range changes to 00:00:00 ,because of which not able to book appointment on frontend.
* #2717 [fixed] - Getting error message on adding rental product in cart if rental booking is not available for that day.
* #2722 [fixed] - warning showing when update event booking cart quantity from the product page
* #2723 [fixed] - Compare product icon on header showing counts of compare product but there are no product in compare list.
* #2724 [fixed] - table bookings quantity should update in existing booking added in cart for same slot/date
* #2726 [fixed] - is shop.js the vue framework ??
* #2732 [fixed] - missing product's quick view in category page
## **v1.0.0 (24th of February 2020)** - *Release*

2
app/Console/Kernel.php Executable file → Normal file
View File

@ -39,4 +39,4 @@ class Kernel extends ConsoleKernel
require base_path('routes/console.php');
}
}
}

View File

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

539
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "dca322023597f38ef7991bc9d9bdc50f",
"content-hash": "89956b3147bad29980a3486770493059",
"packages": [
{
"name": "astrotomic/laravel-translatable",
@ -71,6 +71,74 @@
],
"time": "2020-03-03T10:43:26+00:00"
},
{
"name": "barryvdh/laravel-debugbar",
"version": "v3.2.9",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git",
"reference": "42d5da5379a7860093f8e4032167e4cb5ebec180"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/42d5da5379a7860093f8e4032167e4cb5ebec180",
"reference": "42d5da5379a7860093f8e4032167e4cb5ebec180",
"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-02-25T20:42:23+00:00"
},
{
"name": "barryvdh/laravel-dompdf",
"version": "v0.8.5",
@ -819,6 +887,56 @@
],
"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.2",
@ -1172,6 +1290,7 @@
"email": "jakub.onderka@gmail.com"
}
],
"abandoned": "php-parallel-lint/php-console-color",
"time": "2018-09-29T17:23:10+00:00"
},
{
@ -1218,6 +1337,7 @@
}
],
"description": "Highlight PHP code in terminal",
"abandoned": "php-parallel-lint/php-console-highlighter",
"time": "2018-09-29T18:48:56+00:00"
},
{
@ -1276,6 +1396,7 @@
"serialize",
"tokenizer"
],
"abandoned": "opis/closure",
"time": "2018-03-21T22:21:57+00:00"
},
{
@ -2216,6 +2337,67 @@
],
"time": "2019-10-06T11:29:25+00:00"
},
{
"name": "maximebf/debugbar",
"version": "v1.16.1",
"source": {
"type": "git",
"url": "https://github.com/maximebf/php-debugbar.git",
"reference": "58998b818c6567fac01e35b8a4b70c1a64530556"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/58998b818c6567fac01e35b8a4b70c1a64530556",
"reference": "58998b818c6567fac01e35b8a4b70c1a64530556",
"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": "2019-11-24T09:46:11+00:00"
},
{
"name": "monolog/monolog",
"version": "2.0.2",
@ -3914,16 +4096,16 @@
},
{
"name": "symfony/http-foundation",
"version": "v4.4.5",
"version": "v4.4.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "7e41b4fcad4619535f45f8bfa7744c4f384e1648"
"reference": "62f92509c9abfd1f73e17b8cf1b72c0bdac6611b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/7e41b4fcad4619535f45f8bfa7744c4f384e1648",
"reference": "7e41b4fcad4619535f45f8bfa7744c4f384e1648",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/62f92509c9abfd1f73e17b8cf1b72c0bdac6611b",
"reference": "62f92509c9abfd1f73e17b8cf1b72c0bdac6611b",
"shasum": ""
},
"require": {
@ -3965,7 +4147,7 @@
],
"description": "Symfony HttpFoundation Component",
"homepage": "https://symfony.com",
"time": "2020-02-13T19:40:01+00:00"
"time": "2020-03-30T14:07:33+00:00"
},
{
"name": "symfony/http-kernel",
@ -4059,16 +4241,16 @@
},
{
"name": "symfony/mime",
"version": "v5.0.5",
"version": "v5.0.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
"reference": "9b3e5b5e58c56bbd76628c952d2b78556d305f3c"
"reference": "481b7d6da88922fb1e0d86a943987722b08f3955"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/9b3e5b5e58c56bbd76628c952d2b78556d305f3c",
"reference": "9b3e5b5e58c56bbd76628c952d2b78556d305f3c",
"url": "https://api.github.com/repos/symfony/mime/zipball/481b7d6da88922fb1e0d86a943987722b08f3955",
"reference": "481b7d6da88922fb1e0d86a943987722b08f3955",
"shasum": ""
},
"require": {
@ -4117,7 +4299,7 @@
"mime",
"mime-type"
],
"time": "2020-02-04T09:41:09+00:00"
"time": "2020-03-27T16:56:45+00:00"
},
{
"name": "symfony/polyfill-ctype",
@ -4238,16 +4420,16 @@
},
{
"name": "symfony/polyfill-intl-idn",
"version": "v1.14.0",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-idn.git",
"reference": "6842f1a39cf7d580655688069a03dd7cd83d244a"
"reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/6842f1a39cf7d580655688069a03dd7cd83d244a",
"reference": "6842f1a39cf7d580655688069a03dd7cd83d244a",
"url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf",
"reference": "47bd6aa45beb1cd7c6a16b7d1810133b728bdfcf",
"shasum": ""
},
"require": {
@ -4261,7 +4443,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.14-dev"
"dev-master": "1.15-dev"
}
},
"autoload": {
@ -4296,20 +4478,20 @@
"portable",
"shim"
],
"time": "2020-01-17T12:01:36+00:00"
"time": "2020-03-09T19:04:49+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.14.0",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "34094cfa9abe1f0f14f48f490772db7a775559f2"
"reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/34094cfa9abe1f0f14f48f490772db7a775559f2",
"reference": "34094cfa9abe1f0f14f48f490772db7a775559f2",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac",
"reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac",
"shasum": ""
},
"require": {
@ -4321,7 +4503,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.14-dev"
"dev-master": "1.15-dev"
}
},
"autoload": {
@ -4355,7 +4537,7 @@
"portable",
"shim"
],
"time": "2020-01-13T11:15:53+00:00"
"time": "2020-03-09T19:04:49+00:00"
},
{
"name": "symfony/polyfill-php56",
@ -4415,16 +4597,16 @@
},
{
"name": "symfony/polyfill-php72",
"version": "v1.14.0",
"version": "v1.15.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf"
"reference": "37b0976c78b94856543260ce09b460a7bc852747"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf",
"reference": "46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/37b0976c78b94856543260ce09b460a7bc852747",
"reference": "37b0976c78b94856543260ce09b460a7bc852747",
"shasum": ""
},
"require": {
@ -4433,7 +4615,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.14-dev"
"dev-master": "1.15-dev"
}
},
"autoload": {
@ -4466,7 +4648,7 @@
"portable",
"shim"
],
"time": "2020-01-13T11:15:53+00:00"
"time": "2020-02-27T09:26:54+00:00"
},
{
"name": "symfony/polyfill-php73",
@ -5156,74 +5338,6 @@
}
],
"packages-dev": [
{
"name": "barryvdh/laravel-debugbar",
"version": "v3.2.9",
"source": {
"type": "git",
"url": "https://github.com/barryvdh/laravel-debugbar.git",
"reference": "42d5da5379a7860093f8e4032167e4cb5ebec180"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/barryvdh/laravel-debugbar/zipball/42d5da5379a7860093f8e4032167e4cb5ebec180",
"reference": "42d5da5379a7860093f8e4032167e4cb5ebec180",
"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-02-25T20:42:23+00:00"
},
{
"name": "behat/gherkin",
"version": "v4.6.1",
@ -5619,6 +5733,61 @@
],
"time": "2019-10-10T15:58:56+00:00"
},
{
"name": "codeception/module-webdriver",
"version": "1.0.7",
"source": {
"type": "git",
"url": "https://github.com/Codeception/module-webdriver.git",
"reference": "f05c5c25e39d10fbfb2d508779e1537df019ff9b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Codeception/module-webdriver/zipball/f05c5c25e39d10fbfb2d508779e1537df019ff9b",
"reference": "f05c5c25e39d10fbfb2d508779e1537df019ff9b",
"shasum": ""
},
"require": {
"codeception/codeception": "^4.0",
"php": ">=5.6.0 <8.0",
"php-webdriver/webdriver": "^1.6.0"
},
"require-dev": {
"codeception/util-robohelpers": "dev-master"
},
"suggest": {
"codeception/phpbuiltinserver": "Start and stop PHP built-in web server for your tests"
},
"type": "library",
"autoload": {
"classmap": [
"src/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Bodnarchuk"
},
{
"name": "Gintautas Miselis"
},
{
"name": "Zaahid Bateson"
}
],
"description": "WebDriver module for Codeception",
"homepage": "http://codeception.com/",
"keywords": [
"acceptance-testing",
"browser-testing",
"codeception"
],
"time": "2020-04-01T10:18:18+00:00"
},
{
"name": "codeception/phpunit-wrapper",
"version": "7.8.0",
@ -5810,56 +5979,6 @@
],
"time": "2020-01-15T10:00:00+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",
@ -5908,67 +6027,6 @@
],
"time": "2016-01-20T08:20:44+00:00"
},
{
"name": "maximebf/debugbar",
"version": "v1.16.1",
"source": {
"type": "git",
"url": "https://github.com/maximebf/php-debugbar.git",
"reference": "58998b818c6567fac01e35b8a4b70c1a64530556"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/58998b818c6567fac01e35b8a4b70c1a64530556",
"reference": "58998b818c6567fac01e35b8a4b70c1a64530556",
"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": "2019-11-24T09:46:11+00:00"
},
{
"name": "mockery/mockery",
"version": "1.3.1",
@ -6248,6 +6306,71 @@
"description": "Library for handling version information and constraints",
"time": "2018-07-08T19:19:57+00:00"
},
{
"name": "php-webdriver/webdriver",
"version": "1.8.2",
"source": {
"type": "git",
"url": "https://github.com/php-webdriver/php-webdriver.git",
"reference": "3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab",
"reference": "3308a70be084d6d7fd1ee5787b4c2e6eb4b70aab",
"shasum": ""
},
"require": {
"ext-curl": "*",
"ext-json": "*",
"ext-zip": "*",
"php": "^5.6 || ~7.0",
"symfony/polyfill-mbstring": "^1.12",
"symfony/process": "^2.8 || ^3.1 || ^4.0 || ^5.0"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.0",
"jakub-onderka/php-parallel-lint": "^1.0",
"php-coveralls/php-coveralls": "^2.0",
"php-mock/php-mock-phpunit": "^1.1",
"phpunit/phpunit": "^5.7",
"sebastian/environment": "^1.3.4 || ^2.0 || ^3.0",
"sminnee/phpunit-mock-objects": "^3.4",
"squizlabs/php_codesniffer": "^3.5",
"symfony/var-dumper": "^3.3 || ^4.0 || ^5.0"
},
"suggest": {
"ext-SimpleXML": "For Firefox profile creation"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.8.x-dev"
}
},
"autoload": {
"psr-4": {
"Facebook\\WebDriver\\": "lib/"
},
"files": [
"lib/Exception/TimeoutException.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A PHP client for Selenium WebDriver. Previously facebook/webdriver.",
"homepage": "https://github.com/php-webdriver/php-webdriver",
"keywords": [
"Chromedriver",
"geckodriver",
"php",
"selenium",
"webdriver"
],
"time": "2020-03-04T14:40:12+00:00"
},
{
"name": "phpdocumentor/reflection-common",
"version": "2.0.0",

View File

@ -153,7 +153,7 @@ return [
/*
Application Version
*/
'version' => env('APP_VERSION', '1.1.0'),
'version' => env('APP_VERSION'),
/**
* Blacklisting attributes while debugging

View File

@ -30,12 +30,16 @@ return [
],
'exchange-api' => [
'default' => 'fixer',
'default' => 'exchange_rates',
'fixer' => [
'paid_account' => false,
'key' => env('fixer_api_key'),
'class' => 'Webkul\Core\Helpers\Exchange\FixerExchange'
]
],
'exchange_rates' => [
'class' => 'Webkul\Core\Helpers\Exchange\ExchangeRates'
],
],
'stripe' => [

View File

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,4 +1,4 @@
{
"/js/admin.js": "/js/admin.js?id=c7c2ef0a298910b82304",
"/css/admin.css": "/css/admin.css?id=f2c6fe51889bca1fb79d"
"/js/admin.js": "/js/admin.js?id=2701b1627d73faa941d6",
"/css/admin.css": "/css/admin.css?id=bbb1e500385b8d7ade13"
}

View File

@ -3,6 +3,7 @@
namespace Webkul\Admin\DataGrids;
use Illuminate\Support\Facades\DB;
use Webkul\Customer\Models\CustomerAddress;
use Webkul\Ui\DataGrid\DataGrid;
use Webkul\Customer\Repositories\CustomerRepository;
@ -13,6 +14,7 @@ class AddressDataGrid extends DataGrid
*/
public $index = 'address_id';
/**
* @var string
*/
@ -42,10 +44,11 @@ class AddressDataGrid extends DataGrid
{
$customer = $this->customerRepository->find(request('id'));
$queryBuilder = DB::table('customer_addresses as ca')
$queryBuilder = DB::table('addresses as ca')
->leftJoin('countries', 'ca.country', '=', 'countries.code')
->leftJoin('customers as c', 'ca.customer_id', '=', 'c.id')
->addSelect('ca.id as address_id', 'ca.company_name', 'ca.address1', 'ca.country', DB::raw('' . DB::getTablePrefix() . 'countries.name as country_name'), 'ca.state', 'ca.city', 'ca.postcode', 'ca.phone', 'ca.default_address')
->where('ca.address_type', CustomerAddress::ADDRESS_TYPE)
->where('c.id', $customer->id);
$queryBuilder = $queryBuilder->leftJoin('country_states', function($qb) {
@ -168,4 +171,4 @@ class AddressDataGrid extends DataGrid
'method' => 'DELETE',
]);
}
}
}

View File

@ -117,9 +117,9 @@ class CustomerReviewDataGrid extends DataGrid
'action' => route('admin.customer.review.massupdate'),
'method' => 'PUT',
'options' => [
'Pending' => 0,
'Approve' => 1,
'Disapprove' => 2,
trans('admin::app.customers.reviews.pending') => 0,
trans('admin::app.customers.reviews.approved') => 1,
trans('admin::app.customers.reviews.disapproved') => 2,
],
]);
}

View File

@ -3,6 +3,7 @@
namespace Webkul\Admin\DataGrids;
use Illuminate\Support\Facades\DB;
use Webkul\Sales\Models\OrderAddress;
use Webkul\Ui\DataGrid\DataGrid;
class OrderDataGrid extends DataGrid
@ -14,13 +15,13 @@ class OrderDataGrid extends DataGrid
public function prepareQueryBuilder()
{
$queryBuilder = DB::table('orders')
->leftJoin('order_address as order_address_shipping', function($leftJoin) {
->leftJoin('addresses as order_address_shipping', function($leftJoin) {
$leftJoin->on('order_address_shipping.order_id', '=', 'orders.id')
->where('order_address_shipping.address_type', 'shipping');
->where('order_address_shipping.address_type', OrderAddress::ADDRESS_TYPE_SHIPPING);
})
->leftJoin('order_address as order_address_billing', function($leftJoin) {
->leftJoin('addresses as order_address_billing', function($leftJoin) {
$leftJoin->on('order_address_billing.order_id', '=', 'orders.id')
->where('order_address_billing.address_type', 'billing');
->where('order_address_billing.address_type', OrderAddress::ADDRESS_TYPE_BILLING);
})
->addSelect('orders.id','orders.increment_id', 'orders.base_sub_total', 'orders.base_grand_total', 'orders.created_at', 'channel_name', 'status')
->addSelect(DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_billing.first_name, " ", ' . DB::getTablePrefix() . 'order_address_billing.last_name) as billed_to'))

View File

@ -3,6 +3,7 @@
namespace Webkul\Admin\DataGrids;
use Illuminate\Support\Facades\DB;
use Webkul\Sales\Models\OrderAddress;
use Webkul\Ui\DataGrid\DataGrid;
class OrderRefundDataGrid extends DataGrid
@ -16,9 +17,9 @@ class OrderRefundDataGrid extends DataGrid
$queryBuilder = DB::table('refunds')
->select('refunds.id', 'orders.increment_id', 'refunds.state', 'refunds.base_grand_total', 'refunds.created_at')
->leftJoin('orders', 'refunds.order_id', '=', 'orders.id')
->leftJoin('order_address as order_address_billing', function($leftJoin) {
->leftJoin('addresses as order_address_billing', function($leftJoin) {
$leftJoin->on('order_address_billing.order_id', '=', 'orders.id')
->where('order_address_billing.address_type', 'billing');
->where('order_address_billing.address_type', OrderAddress::ADDRESS_TYPE_BILLING);
})
->addSelect(DB::raw('CONCAT(' . DB::getTablePrefix() . 'order_address_billing.first_name, " ", ' . DB::getTablePrefix() . 'order_address_billing.last_name) as billed_to'));

View File

@ -3,6 +3,7 @@
namespace Webkul\Admin\DataGrids;
use Illuminate\Support\Facades\DB;
use Webkul\Sales\Models\OrderAddress;
use Webkul\Ui\DataGrid\DataGrid;
class OrderShipmentsDataGrid extends DataGrid
@ -14,9 +15,9 @@ class OrderShipmentsDataGrid extends DataGrid
public function prepareQueryBuilder()
{
$queryBuilder = DB::table('shipments')
->leftJoin('order_address as order_address_shipping', function($leftJoin) {
->leftJoin('addresses as order_address_shipping', function($leftJoin) {
$leftJoin->on('order_address_shipping.order_id', '=', 'shipments.order_id')
->where('order_address_shipping.address_type', 'shipping');
->where('order_address_shipping.address_type', OrderAddress::ADDRESS_TYPE_SHIPPING);
})
->leftJoin('orders as ors', 'shipments.order_id', '=', 'ors.id')
->leftJoin('inventory_sources as is', 'shipments.inventory_source_id', '=', 'is.id')

View File

@ -11,11 +11,31 @@ class SliderDataGrid extends DataGrid
protected $sortOrder = 'desc';
protected $locale = 'all';
protected $channel = 'all';
public function __construct()
{
parent::__construct();
$this->locale = request()->get('locale') ?? 'all';
$this->channel = request()->get('channel') ?? 'all';
}
public function prepareQueryBuilder()
{
$queryBuilder = DB::table('sliders as sl')
->addSelect('sl.id as slider_id', 'sl.title', 'ch.name')
->leftJoin('channels as ch', 'sl.channel_id', '=', 'ch.id');
->addSelect('sl.id as slider_id', 'sl.title', 'sl.locale', 'ch.name', 'ch.code')
->leftJoin('channels as ch', 'sl.channel_id', '=', 'ch.id');
if ($this->locale !== 'all') {
$queryBuilder->where('locale', $this->locale);
}
if ($this->channel !== 'all') {
$queryBuilder->where('ch.code', $this->channel);
}
$this->addFilter('slider_id', 'sl.id');
$this->addFilter('channel_name', 'ch.name');
@ -51,6 +71,15 @@ class SliderDataGrid extends DataGrid
'sortable' => true,
'filterable' => true,
]);
$this->addColumn([
'index' => 'locale',
'label' => trans('admin::app.datagrid.locale'),
'type' => 'string',
'searchable' => true,
'sortable' => true,
'filterable' => true
]);
}
public function prepareActions()

View File

@ -2,6 +2,7 @@
namespace Webkul\Admin\Http\Controllers\Customer;
use Illuminate\Support\Facades\Event;
use Webkul\Admin\Http\Controllers\Controller;
use Webkul\Customer\Repositories\CustomerRepository;
use Webkul\Customer\Repositories\CustomerGroupRepository;
@ -111,8 +112,12 @@ class CustomerController extends Controller
$data['is_verified'] = 1;
Event::dispatch('customer.registration.before');
$customer = $this->customerRepository->create($data);
Event::dispatch('customer.registration.after', $customer);
try {
$configKey = 'emails.general.notifications.emails.general.notifications.customer';
if (core()->getConfigData($configKey)) {
@ -164,7 +169,11 @@ class CustomerController extends Controller
$data['status'] = ! isset($data['status']) ? 0 : 1;
$this->customerRepository->update($data, $id);
Event::dispatch('customer.update.before');
$customer = $this->customerRepository->update($data, $id);
Event::dispatch('customer.update.after', $customer);
session()->flash('success', trans('admin::app.response.update-success', ['name' => 'Customer']));

View File

@ -107,6 +107,10 @@ class RefundController extends Controller
$data = request()->all();
if (! $data['refund']['shipping']) {
$data['refund']['shipping'] = 0;
}
$totals = $this->refundRepository->getOrderItemsRefundSummary($data['refund']['items'], $orderId);
$maxRefundAmount = $totals['grand_total']['price'] - $order->refunds()->sum('base_adjustment_refund');

View File

@ -507,7 +507,7 @@ Route::group(['middleware' => ['web']], function () {
'view' => 'admin::settings.exchange_rates.edit'
])->name('admin.exchange_rates.edit');
Route::get('/exchange_rates/update-rates/{service}', 'Webkul\Core\Http\Controllers\ExchangeRateController@updateRates')->name('admin.exchange_rates.update-rates');
Route::get('/exchange_rates/update-rates', 'Webkul\Core\Http\Controllers\ExchangeRateController@updateRates')->name('admin.exchange_rates.update_rates');
Route::put('/exchange_rates/edit/{id}', 'Webkul\Core\Http\Controllers\ExchangeRateController@update')->defaults('_config', [
'redirect' => 'admin.exchange_rates.index'

View File

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

View File

@ -409,6 +409,7 @@ return [
'add-title' => 'أنشئ شحنة',
'save-btn-title' => 'احفظ الشحنة',
'qty-ordered' => 'أمر qty',
'qty-invoiced' => 'Qty Invoiced',
'qty-to-ship' => 'من كيوتي إلى السفينة',
'available-sources' => 'المصادر المتاحة',
'source' => 'المصدر',
@ -728,7 +729,7 @@ return [
'target_currency' => 'العملة المستهدفة',
'rate' => 'معدل',
'exchange-class-not-found' => ':service لم يتم العثور على فئة سعر الصرف آسيف',
'update-rates' => ':service تحديث الأسعار باستخدام ',
'update-rates' => 'الأسعار',
'create-success' => 'تم إنشاء سعر الصرف بنجاح',
'update-success' => 'تم تحديث سعر الصرف بنجاح',
'delete-success' => 'تم حذف سعر الصرف بنجاح',

View File

@ -409,6 +409,7 @@ return [
'add-title' => 'Create Shipment',
'save-btn-title' => 'Save Shipment',
'qty-ordered' => 'Qty Ordered',
'qty-invoiced' => 'Qty Invoiced',
'qty-to-ship' => 'Qty to Ship',
'available-sources' => 'Available Sources',
'source' => 'Source',
@ -728,7 +729,7 @@ return [
'target_currency' => 'Target Currency',
'rate' => 'Rate',
'exchange-class-not-found' => ':service exchange rate class not found',
'update-rates' => 'Update rates using :service',
'update-rates' => 'Update Rates',
'create-success' => 'Exchange Rate created successfully.',
'update-success' => 'Exchange Rate updated successfully.',
'delete-success' => 'Exchange Rate deleted successfully.',

View File

@ -409,6 +409,7 @@ return [
'add-title' => 'ایجاد حمل و نقل',
'save-btn-title' => 'ذخیره حمل و نقل',
'qty-ordered' => 'سفارش داده شده',
'qty-invoiced' => 'Qty Invoiced',
'qty-to-ship' => 'مقدار به کشتی',
'available-sources' => 'منابع موجود',
'source' => 'منابع',
@ -728,7 +729,7 @@ return [
'target_currency' => 'هدف ارز',
'rate' => 'نرخ',
'exchange-class-not-found' => 'کلاس نرخ ارز :service یافت نشد',
'update-rates' => ' به روز کنید :service نرخ ها را با استفاده از',
'update-rates' => 'نرخ ها را به روز کنید',
'create-success' => 'نرخ ارز با موفقیت ایجاد شد.',
'update-success' => 'نرخ ارز با موفقیت به روز شد.',
'delete-success' => 'نرخ ارز با موفقیت حذف شد.',

View File

@ -409,6 +409,7 @@ return [
'add-title' => 'Zending maken',
'save-btn-title' => 'Zending opslaan',
'qty-ordered' => 'Besteld aantal',
'qty-invoiced' => 'Qty Invoiced',
'qty-to-ship' => 'Te verzenden',
'available-sources' => 'Beschikbare bronnen',
'source' => 'Bron',
@ -728,7 +729,7 @@ return [
'target_currency' => 'Valuta doel',
'rate' => 'Tarief',
'exchange-class-not-found' => ':service wisselkoersklasse niet gevonden',
'update-rates' => 'Tarieven bijwerken met :service',
'update-rates' => 'Tarieven bijwerken',
'create-success' => 'Wisselkoers succesvol aangemaakt.',
'update-success' => 'Wisselkoers succesvol bijgewerkt.',
'delete-success' => 'Wisselkoers succesvol verwijderd.',

View File

@ -1,8 +1,8 @@
<?php
return [
'save' => 'Salve ',
'create' => 'Crio',
'save' => 'Salvar',
'create' => 'Criar',
'update' => 'Atualizar',
'delete' => 'Excluir',
'failed' => 'Falhou',
@ -64,7 +64,7 @@ return [
'settings' => 'Opções',
'locales' => 'Idiomas',
'currencies' => 'Moedas',
'exchange-rates' => 'Impostos de Câmbios',
'exchange-rates' => 'Taxas de Câmbios',
'inventory-sources' => 'Fontes de Inventários',
'channels' => 'Canais (Lojas)',
'users' => 'Usuários',
@ -98,7 +98,7 @@ return [
'locales' => 'Idiomas',
'currencies' => 'Moedas',
'exchange-rates' => 'Impostos de Câmbios',
'inventory-sources' => 'Fontes de Inventários',
'inventory-sources' => 'Origens de Estoque',
'channels' => 'Canais (Lojas)',
'users' => 'Usuários',
'roles' => 'Funções',
@ -409,6 +409,7 @@ return [
'add-title' => 'Criar Entrega',
'save-btn-title' => 'Salvar Entrega',
'qty-ordered' => 'Qtd pedido',
'qty-invoiced' => 'Qty Invoiced',
'qty-to-ship' => 'Qty para enviar',
'available-sources' => 'Fontes Disponíveis',
'source' => 'Fonte',
@ -728,6 +729,7 @@ return [
'target_currency' => 'Moeda Alvo',
'rate' => 'Taxa',
'exchange-class-not-found' => ':service de taxa de câmbio de serviço não encontrada',
'update-rates' => 'Atualizar Tarifas',
'rate' => 'Taxa',
'create-success' => 'Taxa de Câmbio criada com sucesso.',
'update-success' => 'Taxa de Câmbio atualizada com sucesso.',
@ -1241,14 +1243,14 @@ return [
'system' => [
'catalog' => 'Catálogo',
'products' => 'Produtos',
'guest-checkout' => 'Saída do hóspede',
'allow-guest-checkout' => 'Permitir saída do hóspede',
'guest-checkout' => 'Compras sem cadastro?',
'allow-guest-checkout' => 'Permitir compra para clientes sem cadastros?',
'allow-guest-checkout-hint' => 'Dica: se ativada, esta opção pode ser configurada para cada produto especificamente.',
'review' => 'Reveja',
'allow-guest-review' => 'Permitir comentário de convidado',
'review' => 'Avaliações',
'allow-guest-review' => 'Permitir comentários sem cadastro?',
'inventory' => 'Inventário',
'stock-options' => 'Opções de ações',
'allow-backorders' => 'Permitir atrasos',
'allow-backorders' => 'Permitir Pedidos pelo Admin',
'customer' => 'Cliente',
'settings' => 'Definições',
'address' => 'Endereço',
@ -1287,29 +1289,30 @@ return [
'locale-options' => 'Opções de unidade',
'weight-unit' => 'Unidade de peso',
'admin-page-limit' => 'Itens padrão por página (administrador)',
'design' => 'Projeto',
'email-settings' => 'Email Settings',
'email-sender-name' => 'Email Sender Name',
'shop-email-from' => 'Shop Email Address [For sending emails]',
'admin-name' => 'Admin Name',
'design' => 'Design',
'email-settings' => 'Configurações de Email',
'email-sender-name' => 'Nome do Email da Loja',
'shop-email-from' => 'Endereço de Email da Loja [Para enviar emails]',
'admin-name' => 'Admin Nome',
'admin-email' => 'Admin Email',
'admin-page-limit' => 'Quantidade Padrão de Itens por Página (Admin)',
'design' => 'Design',
'admin-logo' => 'Admin Logo',
'logo-image' => 'Logo Imagem',
'credit-max' => 'Máximo de crédito do cliente',
'credit-max-value' => 'Valor Máximo de Crédito',
'use-credit-max' => 'Use o máximo de crédito',
'order-settings' => 'Order Settings',
'orderNumber' => 'Order Number Settings',
'order-number-prefix' => 'Order Number Prefix',
'order-number-length' => 'Order Number Length',
'order-number-suffix' => 'Order Number Suffix',
'order-settings' => 'Configurações do Pedido',
'orderNumber' => 'Configuração do Número do Pedido',
'order-number-prefix' => 'Prefixo do Número do Pedido',
'order-number-length' => 'Tamanho do Número do Pedido',
'order-number-suffix' => 'Sufixo do Número de Pedido',
'default' => 'Padrão',
'sandbox' => 'Sandbox',
'all-channels' => 'Todos',
'all-locales' => 'Todos',
'sandbox' => 'Sandbox',
'invoice-slip-design' => 'Invoice Slip Design',
'invoice-slip-design' => 'Design da Nota do Pedido',
'logo' => 'logo'
]
]

View File

@ -13,7 +13,7 @@
<div class="page-action">
<a href="{{ route('admin.catalog.attributes.create') }}" class="btn btn-lg btn-primary">
{{ __('Add Attribute') }}
{{ __('admin::app.catalog.attributes.add-title') }}
</a>
</div>
</div>
@ -28,4 +28,4 @@
{!! view_render_event('bagisto.admin.catalog.attributes.list.after') !!}
</div>
@stop
@stop

View File

@ -20,7 +20,7 @@
<div class="page-action">
<button type="submit" class="btn btn-lg btn-primary">
{{ __('admin::app.save') }} {{ __('admin::app.category') }}
{{ __('admin::app.catalog.categories.save-btn-title') }}
</button>
</div>
</div>

View File

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

View File

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

View File

@ -1,4 +1,4 @@
@extends('address::admin.layouts.content')
@extends('admin::layouts.content')
@section('page_title')
{{ __('address::app.admin.addresses.title-orders', ['customer_name' => $customer->first_name . ' ' . $customer->last_name]) }}

View File

@ -31,24 +31,32 @@
<div class="form-container">
@csrf()
{!! view_render_event('bagisto.admin.customers.create.before') !!}
<div class="control-group" :class="[errors.has('first_name') ? 'has-error' : '']">
<label for="first_name" class="required">{{ __('admin::app.customers.customers.first_name') }}</label>
<input type="text" class="control" name="first_name" v-validate="'required'" value="{{ old('first_name') }}" data-vv-as="&quot;{{ __('shop::app.customer.signup-form.firstname') }}&quot;">
<span class="control-error" v-if="errors.has('first_name')">@{{ errors.first('first_name') }}</span>
</div>
{!! view_render_event('bagisto.admin.customers.create.first_name.after') !!}
<div class="control-group" :class="[errors.has('last_name') ? 'has-error' : '']">
<label for="last_name" class="required">{{ __('admin::app.customers.customers.last_name') }}</label>
<input type="text" class="control" name="last_name" v-validate="'required'" value="{{ old('last_name') }}" data-vv-as="&quot;{{ __('shop::app.customer.signup-form.lastname') }}&quot;">
<span class="control-error" v-if="errors.has('last_name')">@{{ errors.first('last_name') }}</span>
</div>
{!! view_render_event('bagisto.admin.customers.create.last_name.after') !!}
<div class="control-group" :class="[errors.has('email') ? 'has-error' : '']">
<label for="email" class="required">{{ __('shop::app.customer.signup-form.email') }}</label>
<input type="email" class="control" name="email" v-validate="'required|email'" value="{{ old('email') }}" data-vv-as="&quot;{{ __('shop::app.customer.signup-form.email') }}&quot;">
<span class="control-error" v-if="errors.has('email')">@{{ errors.first('email') }}</span>
</div>
{!! view_render_event('bagisto.admin.customers.create.email.after') !!}
<div class="control-group" :class="[errors.has('gender') ? 'has-error' : '']">
<label for="gender" class="required">{{ __('admin::app.customers.customers.gender') }}</label>
<select name="gender" class="control" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.customers.customers.gender') }}&quot;">
@ -60,18 +68,24 @@
<span class="control-error" v-if="errors.has('gender')">@{{ errors.first('gender') }}</span>
</div>
{!! view_render_event('bagisto.admin.customers.create.gender.after') !!}
<div class="control-group" :class="[errors.has('date_of_birth') ? 'has-error' : '']">
<label for="dob">{{ __('admin::app.customers.customers.date_of_birth') }}</label>
<input type="date" class="control" name="date_of_birth" v-validate="" value="{{ old('date_of_birth') }}" data-vv-as="&quot;{{ __('admin::app.customers.customers.date_of_birth') }}&quot;">
<span class="control-error" v-if="errors.has('date_of_birth')">@{{ errors.first('date_of_birth') }}</span>
</div>
{!! view_render_event('bagisto.admin.customers.create.date_of_birth.after') !!}
<div class="control-group" :class="[errors.has('phone') ? 'has-error' : '']">
<label for="phone">{{ __('admin::app.customers.customers.phone') }}</label>
<input type="text" class="control" name="phone" value="{{ old('phone') }}" data-vv-as="&quot;{{ __('admin::app.customers.customers.phone') }}&quot;">
<span class="control-error" v-if="errors.has('phone')">@{{ errors.first('phone') }}</span>
</div>
{!! view_render_event('bagisto.admin.customers.create.phone.after') !!}
<div class="control-group">
<label for="customerGroup" >{{ __('admin::app.customers.customers.customer_group') }}</label>
<select class="control" name="customer_group_id">
@ -80,6 +94,8 @@
@endforeach
</select>
</div>
{!! view_render_event('bagisto.admin.customers.create.after') !!}
</div>
</div>
</form>

View File

@ -36,6 +36,8 @@
<accordian :title="'{{ __('admin::app.account.general') }}'" :active="true">
<div slot="body">
{!! view_render_event('bagisto.admin.customer.edit.form.before', ['customer' => $customer]) !!}
<div class="control-group" :class="[errors.has('first_name') ? 'has-error' : '']">
<label for="first_name" class="required"> {{ __('admin::app.customers.customers.first_name') }}</label>
<input type="text" class="control" name="first_name" v-validate="'required'" value="{{old('first_name') ?:$customer->first_name}}"
@ -43,18 +45,24 @@
<span class="control-error" v-if="errors.has('first_name')">@{{ errors.first('first_name') }}</span>
</div>
{!! view_render_event('bagisto.admin.customer.edit.first_name.after', ['customer' => $customer]) !!}
<div class="control-group" :class="[errors.has('last_name') ? 'has-error' : '']">
<label for="last_name" class="required"> {{ __('admin::app.customers.customers.last_name') }}</label>
<input type="text" class="control" name="last_name" v-validate="'required'" value="{{old('last_name') ?:$customer->last_name}}" data-vv-as="&quot;{{ __('shop::app.customer.signup-form.lastname') }}&quot;">
<span class="control-error" v-if="errors.has('last_name')">@{{ errors.first('last_name') }}</span>
</div>
{!! view_render_event('bagisto.admin.customer.edit.last_name.after', ['customer' => $customer]) !!}
<div class="control-group" :class="[errors.has('email') ? 'has-error' : '']">
<label for="email" class="required"> {{ __('admin::app.customers.customers.email') }}</label>
<input type="email" class="control" name="email" v-validate="'required|email'" value="{{old('email') ?:$customer->email}}" data-vv-as="&quot;{{ __('shop::app.customer.signup-form.email') }}&quot;">
<span class="control-error" v-if="errors.has('email')">@{{ errors.first('email') }}</span>
</div>
{!! view_render_event('bagisto.admin.customer.edit.email.after', ['customer' => $customer]) !!}
<div class="control-group" :class="[errors.has('gender') ? 'has-error' : '']">
<label for="gender" class="required">{{ __('admin::app.customers.customers.gender') }}</label>
<select name="gender" class="control" value="{{ $customer->gender }}" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.customers.customers.gender') }}&quot;">
@ -66,6 +74,8 @@
<span class="control-error" v-if="errors.has('gender')">@{{ errors.first('gender') }}</span>
</div>
{!! view_render_event('bagisto.admin.customer.edit.gender.after', ['customer' => $customer]) !!}
<div class="control-group">
<label for="status" class="required">{{ __('admin::app.customers.customers.status') }}</label>
@ -77,18 +87,24 @@
<span class="control-error" v-if="errors.has('status')">@{{ errors.first('status') }}</span>
</div>
{!! view_render_event('bagisto.admin.customer.edit.status.after', ['customer' => $customer]) !!}
<div class="control-group" :class="[errors.has('date_of_birth') ? 'has-error' : '']">
<label for="dob">{{ __('admin::app.customers.customers.date_of_birth') }}</label>
<input type="date" class="control" name="date_of_birth" value="{{ old('date_of_birth') ?:$customer->date_of_birth }}" v-validate="" data-vv-as="&quot;{{ __('admin::app.customers.customers.date_of_birth') }}&quot;">
<span class="control-error" v-if="errors.has('date_of_birth')">@{{ errors.first('date_of_birth') }}</span>
</div>
{!! view_render_event('bagisto.admin.customer.edit.date_of_birth.after', ['customer' => $customer]) !!}
<div class="control-group" :class="[errors.has('phone') ? 'has-error' : '']">
<label for="phone">{{ __('admin::app.customers.customers.phone') }}</label>
<input type="text" class="control" name="phone" value="{{ $customer->phone }}" data-vv-as="&quot;{{ __('admin::app.customers.customers.phone') }}&quot;">
<span class="control-error" v-if="errors.has('phone')">@{{ errors.first('phone') }}</span>
</div>
{!! view_render_event('bagisto.admin.customer.edit.phone.after', ['customer' => $customer]) !!}
<div class="control-group">
<label for="customerGroup" >{{ __('admin::app.customers.customers.customer_group') }}</label>

View File

@ -447,10 +447,10 @@
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-less-than') }}'
}, {
'operator': '<=',
'operator': '>',
'label': '{{ __('admin::app.promotions.cart-rules.greater-than') }}'
}, {
'operator': '<=',
'operator': '<',
'label': '{{ __('admin::app.promotions.cart-rules.less-than') }}'
}],
'decimal': [{

View File

@ -535,10 +535,10 @@
'operator': '<=',
'label': '{{ __('admin::app.promotions.cart-rules.equals-or-less-than') }}'
}, {
'operator': '<=',
'operator': '>',
'label': '{{ __('admin::app.promotions.cart-rules.greater-than') }}'
}, {
'operator': '<=',
'operator': '<',
'label': '{{ __('admin::app.promotions.cart-rules.less-than') }}'
}],
'decimal': [{

View File

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

View File

@ -12,16 +12,24 @@
<div class="page-header">
<div class="page-title">
<h1>
{!! view_render_event('sales.invoice.title.before', ['order' => $order]) !!}
<i class="icon angle-left-icon back-link" onclick="history.length > 1 ? history.go(-1) : window.location = '{{ url('/admin/dashboard') }}';"></i>
{{ __('admin::app.sales.invoices.view-title', ['invoice_id' => $invoice->id]) }}
{!! view_render_event('sales.invoice.title.after', ['order' => $order]) !!}
</h1>
</div>
<div class="page-action">
{!! view_render_event('sales.invoice.page_action.before', ['order' => $order]) !!}
<a href="{{ route('admin.sales.invoices.print', $invoice->id) }}" class="btn btn-lg btn-primary">
{{ __('admin::app.sales.invoices.print') }}
</a>
{!! view_render_event('sales.invoice.page_action.after', ['order' => $order]) !!}
</div>
</div>
@ -47,6 +55,8 @@
</span>
</div>
{!! view_render_event('sales.invoice.increment_id.after', ['order' => $order]) !!}
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.order-date') }}
@ -57,6 +67,8 @@
</span>
</div>
{!! view_render_event('sales.invoice.created_at.after', ['order' => $order]) !!}
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.order-status') }}
@ -67,6 +79,8 @@
</span>
</div>
{!! view_render_event('sales.invoice.status_label.after', ['order' => $order]) !!}
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.channel') }}
@ -76,6 +90,8 @@
{{ $order->channel_name }}
</span>
</div>
{!! view_render_event('sales.invoice.channel_name.after', ['order' => $order]) !!}
</div>
</div>
@ -95,6 +111,8 @@
</span>
</div>
{!! view_render_event('sales.invoice.customer_name.after', ['order' => $order]) !!}
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.email') }}
@ -104,6 +122,8 @@
{{ $invoice->address->email }}
</span>
</div>
{!! view_render_event('sales.invoice.customer_email.after', ['order' => $order]) !!}
</div>
</div>
@ -119,9 +139,9 @@
</div>
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->billing_address])
{!! view_render_event('sales.invoice.billing_address.after', ['order' => $order]) !!}
</div>
</div>
@ -132,9 +152,9 @@
</div>
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->shipping_address])
{!! view_render_event('sales.invoice.shipping_address.after', ['order' => $order]) !!}
</div>
</div>
@endif
@ -170,6 +190,8 @@
{{ $order->order_currency_code }}
</span>
</div>
{!! view_render_event('sales.invoice.payment-method.after', ['order' => $order]) !!}
</div>
</div>
@ -199,6 +221,8 @@
{{ core()->formatBasePrice($order->base_shipping_amount) }}
</span>
</div>
{!! view_render_event('sales.invoice.shipping-method.after', ['order' => $order]) !!}
</div>
</div>
@endif
@ -236,7 +260,7 @@
@if (isset($item->additional['attributes']))
<div class="item-options">
@foreach ($item->additional['attributes'] as $attribute)
<b>{{ $attribute['attribute_name'] }} : </b>{{ $attribute['option_label'] }}</br>
@endforeach

View File

@ -12,13 +12,19 @@
<div class="page-title">
<h1>
{!! view_render_event('sales.order.title.before', ['order' => $order]) !!}
<i class="icon angle-left-icon back-link" onclick="history.length > 1 ? history.go(-1) : window.location = '{{ url('/admin/dashboard') }}';"></i>
{{ __('admin::app.sales.orders.view-title', ['order_id' => $order->increment_id]) }}
{!! view_render_event('sales.order.title.after', ['order' => $order]) !!}
</h1>
</div>
<div class="page-action">
{!! view_render_event('sales.order.page_action.before', ['order' => $order]) !!}
@if ($order->canCancel())
<a href="{{ route('admin.sales.orders.cancel', $order->id) }}" class="btn btn-lg btn-primary" v-alert:message="'{{ __('admin::app.sales.orders.cancel-confirm-msg') }}'">
{{ __('admin::app.sales.orders.cancel-btn-title') }}
@ -42,6 +48,8 @@
{{ __('admin::app.sales.orders.shipment-btn-title') }}
</a>
@endif
{!! view_render_event('sales.order.page_action.after', ['order' => $order]) !!}
</div>
</div>
@ -72,6 +80,8 @@
</span>
</div>
{!! view_render_event('sales.order.created_at.after', ['order' => $order]) !!}
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.order-status') }}
@ -82,6 +92,8 @@
</span>
</div>
{!! view_render_event('sales.order.status_label.after', ['order' => $order]) !!}
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.channel') }}
@ -91,6 +103,8 @@
{{ $order->channel_name }}
</span>
</div>
{!! view_render_event('sales.order.channel_name.after', ['order' => $order]) !!}
</div>
</div>
@ -110,6 +124,8 @@
</span>
</div>
{!! view_render_event('sales.order.customer_full_name.after', ['order' => $order]) !!}
<div class="row">
<span class="title">
{{ __('admin::app.sales.orders.email') }}
@ -120,6 +136,8 @@
</span>
</div>
{!! view_render_event('sales.order.customer_email.after', ['order' => $order]) !!}
@if (! is_null($order->customer))
<div class="row">
<span class="title">
@ -131,6 +149,8 @@
</span>
</div>
@endif
{!! view_render_event('sales.order.customer_group.after', ['order' => $order]) !!}
</div>
</div>
@ -146,9 +166,9 @@
</div>
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->billing_address])
{!! view_render_event('sales.order.billing_address.after', ['order' => $order]) !!}
</div>
</div>
@ -159,9 +179,9 @@
</div>
<div class="section-content">
@include ('admin::sales.address', ['address' => $order->shipping_address])
{!! view_render_event('sales.order.shipping_address.after', ['order' => $order]) !!}
</div>
</div>
@endif
@ -197,6 +217,8 @@
{{ $order->order_currency_code }}
</span>
</div>
{!! view_render_event('sales.order.payment-method.after', ['order' => $order]) !!}
</div>
</div>
@ -226,6 +248,8 @@
{{ core()->formatBasePrice($order->base_shipping_amount) }}
</span>
</div>
{!! view_render_event('sales.order.shipping-method.after', ['order' => $order]) !!}
</div>
</div>
@endif

View File

@ -263,6 +263,7 @@
<th>{{ __('admin::app.sales.orders.SKU') }}</th>
<th>{{ __('admin::app.sales.orders.product-name') }}</th>
<th>{{ __('admin::app.sales.shipments.qty-ordered') }}</th>
<th>{{ __('admin::app.sales.shipments.qty-invoiced') }}</th>
<th>{{ __('admin::app.sales.shipments.qty-to-ship') }}</th>
<th>{{ __('admin::app.sales.shipments.available-sources') }}</th>
</tr>
@ -288,6 +289,7 @@
@endif
</td>
<td>{{ $item->qty_ordered }}</td>
<td>{{ $item->qty_invoiced }}</td>
<td>{{ $item->qty_to_ship }}</td>
<td>
@ -324,8 +326,8 @@
<div class="control-group" :class="[errors.has('{{ $inputName }}') ? 'has-error' : '']">
<input type="text" v-validate="'required|numeric|min_value:0|max_value:{{$sourceQty}}'" class="control" id="{{ $inputName }}" name="{{ $inputName }}" value="0" data-vv-as="&quot;{{ __('admin::app.sales.shipments.qty-to-ship') }}&quot;" :disabled="source != '{{ $inventorySource->id }}'"/>
<input type="text" v-validate="'required|numeric|min_value:0|max_value:{{$sourceQty}}'" class="control" id="{{ $inputName }}" name="{{ $inputName }}" value="{{ $item->qty_invoiced }}" data-vv-as="&quot;{{ __('admin::app.sales.shipments.qty-to-ship') }}&quot;" :disabled="source != '{{ $inventorySource->id }}'"/>
<span class="control-error" v-if="errors.has('{{ $inputName }}')">
@verbatim
{{ errors.first('<?php echo $inputName; ?>') }}

View File

@ -56,7 +56,7 @@
<div class="control-group" :class="[errors.has('target_currency') ? 'has-error' : '']">
<select v-validate="'required'" class="control" name="target_currency" data-vv-as="&quot;{{ __('admin::app.settings.exchange_rates.target_currency') }}&quot;">
@foreach ($currencies as $currency)
@if (is_null($currency->CurrencyExchangeRate))
@if (is_null($currency->exchange_rate))
<option value="{{ $currency->id }}">{{ $currency->name }}</option>
@endif
@endforeach

View File

@ -12,25 +12,20 @@
</div>
<div class="page-action">
<a href="{{ route('admin.exchange_rates.update_rates') }}" class="btn btn-lg btn-primary">
{{ __('admin::app.settings.exchange_rates.update-rates') }}
</a>
<a href="{{ route('admin.exchange_rates.create') }}" class="btn btn-lg btn-primary">
{{ __('admin::app.settings.exchange_rates.add-title') }}
</a>
@php
$defaultService = config('services.exchange-api.default');
@endphp
{{-- <a href="{{ route('admin.exchange_rates.update-rates', $defaultService) }}" class="btn btn-lg btn-primary">
{{ __('admin::app.settings.exchange_rates.update-rates', [
'service' => $defaultService
]) }}
</a> --}}
</div>
</div>
<div class="page-content">
@inject('exchange_rates','Webkul\Admin\DataGrids\ExchangeRatesDataGrid')
{!! $exchange_rates->render() !!}
{!! app('Webkul\Admin\DataGrids\ExchangeRatesDataGrid')->render() !!}
</div>
</div>
@stop

View File

@ -6,7 +6,12 @@
@section('content')
<div class="content">
<form method="POST" action="{{ route('admin.sliders.create') }}" @submit.prevent="onSubmit" enctype="multipart/form-data">
<form
method="POST"
@submit.prevent="onSubmit"
enctype="multipart/form-data"
action="{{ route('admin.sliders.create') }}">
<div class="page-header">
<div class="page-title">
<h1>
@ -29,6 +34,20 @@
{!! view_render_event('bagisto.admin.settings.slider.create.before') !!}
<div class="control-group" :class="[errors.has('locale') ? 'has-error' : '']">
<label for="locale">{{ __('admin::app.datagrid.locale') }}</label>
<select class="control" id="locale" name="locale" data-vv-as="&quot;{{ __('admin::app.datagrid.locale') }}&quot;" value="" v-validate="'required'">
@foreach (core()->getAllLocales() as $localeModel)
<option value="{{ $localeModel->code }}" {{ ($localeModel->code) == $locale ? 'selected' : '' }}>
{{ $localeModel->name }}
</option>
@endforeach
</select>
</div>
<div class="control-group" :class="[errors.has('title') ? 'has-error' : '']">
<label for="title" class="required">{{ __('admin::app.settings.sliders.name') }}</label>
<input type="text" class="control" name="title" v-validate="'required'" data-vv-as="&quot;{{ __('admin::app.settings.sliders.name') }}&quot;">

View File

@ -6,6 +6,8 @@
@section('content')
<div class="content">
<?php $locale = request()->get('locale') ?: app()->getLocale(); ?>
<form method="POST" action="{{ route('admin.sliders.update', $slider->id) }}" @submit.prevent="onSubmit" enctype="multipart/form-data">
<div class="page-header">
<div class="page-title">
@ -13,6 +15,11 @@
<i class="icon angle-left-icon back-link" onclick="history.length > 1 ? history.go(-1) : window.location = '{{ url('/admin/dashboard') }}';"></i>
{{ __('admin::app.settings.sliders.edit-title') }}
@if ($slider->locale)
<span class="locale">[{{ $slider->locale }}]</span>
@endif
</h1>
</div>

View File

@ -6,11 +6,49 @@
@section('content')
<div class="content">
<?php $locale = request()->get('locale') ?: null; ?>
<?php $channel = request()->get('channel') ?: null; ?>
<div class="page-header">
<div class="page-title">
<h1>{{ __('admin::app.settings.sliders.title') }}</h1>
<div class="control-group">
<select class="control" id="channel-switcher" name="channel" onchange="reloadPage('channel', this.value)" >
<option value="all" {{ ! isset($channel) ? 'selected' : '' }}>
{{ __('admin::app.admin.system.all-channels') }}
</option>
@foreach (core()->getAllChannels() as $channelModel)
<option
value="{{ $channelModel->code }}" {{ (isset($channel) && ($channelModel->code) == $channel) ? 'selected' : '' }}>
{{ $channelModel->name }}
</option>
@endforeach
</select>
</div>
<div class="control-group">
<select class="control" id="locale-switcher" name="locale" onchange="reloadPage('locale', this.value)" >
<option value="all" {{ ! isset($locale) ? 'selected' : '' }}>
{{ __('admin::app.admin.system.all-locales') }}
</option>
@foreach (core()->getAllLocales() as $localeModel)
<option
value="{{ $localeModel->code }}" {{ (isset($locale) && ($localeModel->code) == $locale) ? 'selected' : '' }}>
{{ $localeModel->name }}
</option>
@endforeach
</select>
</div>
</div>
<div class="page-action">
@ -25,4 +63,18 @@
{!! $sliders->render() !!}
</div>
</div>
@stop
@stop
@push('scripts')
<script>
function reloadPage(getVar, getVal) {
let url = new URL(window.location.href);
url.searchParams.set(getVar, getVal);
window.location.href = url.href;
}
</script>
@endpush

View File

@ -26,22 +26,6 @@
<div class="form-container">
@csrf()
<div class="control-group" :class="[errors.has('channel') ? 'has-error' : '']">
<label for="channel" class="required">{{ __('admin::app.configuration.tax-categories.select-channel') }}</label>
<select class="control" name="channel_id">
@foreach (core()->getAllChannels() as $channelModel)
<option value="{{ $channelModel->id }}">
{{ $channelModel->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('channel')">@{{ errors.first('channel') }}</span>
</div>
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
<label for="code" class="required">{{ __('admin::app.configuration.tax-categories.code') }}</label>
@ -67,7 +51,7 @@
</div>
<?php $selectedOptions = old('taxrates') ?: [] ?>
<div class="control-group" :class="[errors.has('taxrates[]') ? 'has-error' : '']">
<label for="taxrates" class="required">{{ __('admin::app.configuration.tax-categories.select-taxrates') }}</label>

View File

@ -27,22 +27,6 @@
<div class="form-container">
@csrf()
@method('PUT')
<div class="control-group" :class="[errors.has('channel') ? 'has-error' : '']">
<label for="channel" class="required">{{ __('admin::app.settings.tax-categories.select-channel') }}</label>
<select class="control" name="channel_id">
@foreach (core()->getAllChannels() as $channelModel)
<option @if ($taxCategory->channel_id == $channelModel->id) selected @endif value="{{ $channelModel->id }}">
{{ $channelModel->name }}
</option>
@endforeach
</select>
<span class="control-error" v-if="errors.has('channel')">@{{ errors.first('channel') }}</span>
</div>
<div class="control-group" :class="[errors.has('code') ? 'has-error' : '']">
<label for="code" class="required">{{ __('admin::app.settings.tax-categories.code') }}</label>

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

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

View File

@ -32,14 +32,13 @@ class DefaultSlot extends Booking
$availableFrom = $bookingProduct->available_from
? Carbon::createFromTimeString($bookingProduct->available_from)
: clone $currentTime;
: Carbon::createFromTimeString($currentTime->format('Y-m-d 00:00:00'));
$availableTo = $bookingProduct->available_to
? Carbon::createFromTimeString($bookingProduct->available_to)
: Carbon::createFromTimeString('2080-01-01 00:00:00');
if ($requestedDate < $currentTime
|| $requestedDate < $availableFrom
if ($requestedDate < $availableFrom
|| $requestedDate > $availableTo
) {
return [];
@ -63,8 +62,10 @@ class DefaultSlot extends Booking
{
$slots = [];
$dayOfWeek = $requestedDate->dayOfWeek;
foreach ($bookingProductSlot->slots as $timeDuration) {
if ($requestedDate->dayOfWeek != $timeDuration['from_day']) {
if ($dayOfWeek != $timeDuration['from_day']) {
continue;
}
@ -101,7 +102,7 @@ class DefaultSlot extends Booking
$availableFrom = $bookingProduct->available_from
? Carbon::createFromTimeString($bookingProduct->available_from)
: clone $currentTime;
: Carbon::createFromTimeString($currentTime->format('Y-m-d 00:00:00'));
$availableTo = $bookingProduct->available_to
? Carbon::createFromTimeString($bookingProduct->available_to)

View File

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

View File

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

View File

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

View File

@ -2,8 +2,10 @@
namespace Webkul\BookingProduct\Providers;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Event;
use Webkul\Theme\ViewRenderEventManager;
class EventServiceProvider extends ServiceProvider
{
@ -14,8 +16,10 @@ class EventServiceProvider extends ServiceProvider
*/
public function boot()
{
Event::listen('bagisto.shop.products.view.short_description.after', function($viewRenderEventManager) {
$viewRenderEventManager->addTemplate('bookingproduct::shop.products.view.booking');
Event::listen('bagisto.shop.products.view.short_description.after', static function(ViewRenderEventManager $viewRenderEventManager) {
if (View::exists('bookingproduct::shop.' . core()->getCurrentChannel()->theme . '.products.view.booking')) {
$viewRenderEventManager->addTemplate('bookingproduct::shop.' . core()->getCurrentChannel()->theme . '.products.view.booking');
}
});
Event::listen('checkout.order.save.after', 'Webkul\BookingProduct\Listeners\Order@afterPlaceOrder');

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -165,9 +165,9 @@ class Cart
'cart_id' => $cart->id
]));
} else {
if ($cartItem->product->getTypeInstance()->showQuantityBox() === false) {
return ['warning' => __('shop::app.checkout.cart.integrity.qty_impossible')];
}
// if ($cartItem->product->getTypeInstance()->showQuantityBox() === false) {
// return ['warning' => __('shop::app.checkout.cart.integrity.qty_impossible')];
// }
$cartItem = $this->cartItemRepository->update($cartProduct, $cartItem->id);
}
@ -368,8 +368,14 @@ class Cart
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);
@ -387,8 +393,6 @@ class Cart
$guestCart->items->forget($key);
$this->cartItemRepository->delete($guestCartItem->id);
$found = true;
}
if (! $found) {
@ -1200,21 +1204,21 @@ class Cart
} else {
if (isset($billingAddressData['use_for_shipping']) && $billingAddressData['use_for_shipping']) {
$this->cartAddressRepository->create(array_merge($billingAddressData,
['address_type' => 'shipping']));
['address_type' => CartAddress::ADDRESS_TYPE_SHIPPING]));
} else {
$this->cartAddressRepository->create(array_merge($shippingAddressData,
['address_type' => 'shipping']));
['address_type' => CartAddress::ADDRESS_TYPE_SHIPPING]));
}
}
}
} else {
$this->cartAddressRepository->create(array_merge($billingAddressData, ['address_type' => 'billing']));
$this->cartAddressRepository->create(array_merge($billingAddressData, ['address_type' => CartAddress::ADDRESS_TYPE_BILLING]));
if ($cart->haveStockableItems()) {
if (isset($billingAddressData['use_for_shipping']) && $billingAddressData['use_for_shipping']) {
$this->cartAddressRepository->create(array_merge($billingAddressData, ['address_type' => 'shipping']));
$this->cartAddressRepository->create(array_merge($billingAddressData, ['address_type' => CartAddress::ADDRESS_TYPE_SHIPPING]));
} else {
$this->cartAddressRepository->create(array_merge($shippingAddressData, ['address_type' => 'shipping']));
$this->cartAddressRepository->create(array_merge($shippingAddressData, ['address_type' => CartAddress::ADDRESS_TYPE_SHIPPING]));
}
}
}

View File

@ -6,14 +6,10 @@ use Faker\Generator as Faker;
use Webkul\Checkout\Models\CartAddress;
$factory->define(CartAddress::class, function (Faker $faker) {
$now = date("Y-m-d H:i:s");
return [
'first_name' => $faker->firstName(),
'last_name' => $faker->lastName,
'email' => $faker->email,
'created_at' => $now,
'updated_at' => $now,
'address_type' => 'billing',
'address_type' => CartAddress::ADDRESS_TYPE_BILLING,
];
});

View File

@ -48,7 +48,7 @@ class Cart extends Model implements CartContract
*/
public function billing_address()
{
return $this->addresses()->where('address_type', 'billing');
return $this->addresses()->where('address_type', CartAddress::ADDRESS_TYPE_BILLING);
}
/**
@ -64,7 +64,7 @@ class Cart extends Model implements CartContract
*/
public function shipping_address()
{
return $this->addresses()->where('address_type', 'shipping');
return $this->addresses()->where('address_type', CartAddress::ADDRESS_TYPE_SHIPPING);
}
/**

View File

@ -2,30 +2,47 @@
namespace Webkul\Checkout\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Webkul\Checkout\Contracts\CartAddress as CartAddressContract;
use Webkul\Core\Models\Address;
class CartAddress extends Model implements CartAddressContract
/**
* Class CartAddress
* @package Webkul\Checkout\Models
*
* @property integer $cart_id
* @property Cart $cart
*
*/
class CartAddress extends Address implements CartAddressContract
{
protected $table = 'cart_address';
public const ADDRESS_TYPE_SHIPPING = 'cart_shipping';
public const ADDRESS_TYPE_BILLING = 'cart_billing';
protected $fillable = [
'first_name',
'last_name',
'email',
'company_name',
'vat_id',
'address1',
'city',
'state',
'postcode',
'country',
'phone',
'address_type',
'cart_id',
'customer_id',
/**
* @var array default values
*/
protected $attributes = [
'address_type' => self::ADDRESS_TYPE_BILLING,
];
/**
* The "booted" method of the model.
*
* @return void
*/
protected static function boot()
{
static::addGlobalScope('address_type', static function (Builder $builder) {
$builder->whereIn('address_type', [
self::ADDRESS_TYPE_BILLING,
self::ADDRESS_TYPE_SHIPPING
]);
});
parent::boot();
}
/**
* Get the shipping rates for the cart address.
*/
@ -35,10 +52,10 @@ class CartAddress extends Model implements CartAddressContract
}
/**
* Get all of the attributes for the attribute groups.
* Get the cart record associated with the address.
*/
public function getNameAttribute()
public function cart()
{
return $this->first_name . ' ' . $this->last_name;
return $this->belongsTo(Cart::class);
}
}

View File

@ -24,6 +24,7 @@ class CartShippingRate extends Model implements CartShippingRateContract
*/
public function shipping_address()
{
return $this->belongsTo(CartAddressProxy::modelClass());
return $this->belongsTo(CartAddressProxy::modelClass(), 'cart_address_id')
->where('address_type', CartAddress::ADDRESS_TYPE_SHIPPING);
}
}

View File

@ -1,6 +1,6 @@
<?php
namespace App\Console\Commands;
namespace Webkul\Core\Console\Commands;
use Illuminate\Console\Command;

View File

@ -0,0 +1,36 @@
<?php
namespace Webkul\Core\Console\Commands;
use Illuminate\Console\Command;
class ExchangeRateUpdate extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'exchange-rate:update';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Automatically updates currency exchange rates ';
/**
* Execute the console command.
*
* @return void
*/
public function handle()
{
try {
app(config('services.exchange-api.' . config('services.exchange-api.default') . '.class'))->updateRates();
} catch(\Exception $e) {
}
}
}

View File

@ -1,12 +1,12 @@
<?php
namespace App\Console\Commands;
namespace Webkul\Core\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Artisan;
class install extends Command
class Install extends Command
{
/**
* The name and signature of the console command.

View File

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

View File

@ -17,4 +17,4 @@ $factory->define(CartRuleCoupon::class, function (Faker $faker) {
return factory(CartRule::class)->create()->id;
},
];
});
});

View File

@ -0,0 +1,39 @@
<?php
use Faker\Generator as Faker;
use Webkul\Category\Models\Category;
use Webkul\Core\Models\Channel;
use Webkul\Core\Models\Currency;
use Webkul\Core\Models\Locale;
/** @var \Illuminate\Database\Eloquent\Factory $factory */
$factory->define(Channel::class, function (Faker $faker, array $attributes) {
$seoTitle = $attributes['seo_title'] ?? $faker->word;
$seoDescription = $attributes['seo_description'] ?? $faker->words(10, true);
$seoKeywords = $attributes['seo_keywords'] ?? $faker->words(3, true);
$seoData = [
'meta_title' => $seoTitle,
'meta_description' => $seoDescription,
'meta_keywords' => $seoKeywords,
];
unset($attributes['seo_title'], $attributes['seo_description'], $attributes['seo_keywords']);
return [
'code' => $faker->unique()->word,
'name' => $faker->word,
'default_locale_id' => function () {
return factory(Locale::class)->create()->id;
},
'base_currency_id' => function () {
return factory(Currency::class)->create()->id;
},
'root_category_id' => function () {
return factory(Category::class)->create()->id;
},
'home_seo' => json_encode($seoData),
];
});

View File

@ -0,0 +1,10 @@
<?php
/** @var \Illuminate\Database\Eloquent\Factory $factory */
$factory->define('channel_inventory_sources', function () {
return [
'channel_id' => core()->getCurrentChannel()->id,
'inventory_source_id' => 1,
];
});

View File

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

View File

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

View File

@ -0,0 +1,294 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Webkul\Checkout\Models\CartAddress;
use Webkul\Checkout\Models\CartShippingRate;
use Webkul\Sales\Models\Invoice;
use Webkul\Sales\Models\OrderAddress;
use Webkul\Sales\Models\Shipment;
class AddTableAddresses extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
try {
// transaction is important to prevent loosing data on failure
DB::beginTransaction();
Schema::create('addresses', function (Blueprint $table) {
$table->increments('id');
$table->string('address_type');
$table->unsignedInteger('customer_id')->nullable()->comment('null if guest checkout');
$table->unsignedInteger('cart_id')->nullable()->comment('only for cart_addresses');
$table->unsignedInteger('order_id')->nullable()->comment('only for order_addresses');
$table->string('first_name');
$table->string('last_name');
$table->string('gender')->nullable();
$table->string('company_name')->nullable();
$table->string('address1');
$table->string('address2')->nullable();
$table->string('postcode');
$table->string('city');
$table->string('state');
$table->string('country');
$table->string('email')->nullable();
$table->string('phone')->nullable();
$table->string('vat_id')->nullable();
$table->boolean('default_address')
->default(false)
->comment('only for customer_addresses');
$table->json('additional')->nullable();
$table->timestamps();
$table->foreign(['customer_id'])->references('id')->on('customers')->onDelete('cascade');
$table->foreign(['cart_id'])->references('id')->on('cart')->onDelete('cascade');
$table->foreign(['order_id'])->references('id')->on('orders')->onDelete('cascade');
});
Schema::disableForeignKeyConstraints();
$this->migrateCustomerAddresses();
$this->migrateCartAddresses();
$this->migrateOrderAddresses();
$this->migrateForeignKeys();
Schema::drop('customer_addresses');
Schema::drop('cart_address');
Schema::drop('order_address');
Schema::enableForeignKeyConstraints();
DB::commit();
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
throw new Exception('you cannot revert this migration: data would be lost');
}
private function migrateCustomerAddresses(): void
{
$dbPrefix = DB::getTablePrefix();
$insertCustomerAddresses = <<< SQL
INSERT INTO ${dbPrefix}addresses(
address_type,
customer_id,
first_name,
last_name,
gender,
company_name,
address1,
address2,
postcode,
city,
state,
country,
email,
phone,
default_address,
additional,
created_at,
updated_at
)
SELECT
"customer",
customer_id,
first_name,
last_name,
(SELECT gender FROM customers c WHERE c.id=ca.customer_id),
company_name,
address1,
address2,
postcode,
city,
state,
country,
null,
phone,
default_address,
JSON_INSERT('{}', '$.old_customer_address_id', id),
created_at,
updated_at
FROM customer_addresses ca;
SQL;
DB::unprepared($insertCustomerAddresses);
}
private function migrateCartAddresses(): void
{
$dbPrefix = DB::getTablePrefix();
$insertCustomerAddresses = <<< SQL
INSERT INTO ${dbPrefix}addresses(
address_type,
customer_id,
cart_id,
first_name,
last_name,
gender,
company_name,
address1,
address2,
postcode,
city,
state,
country,
email,
phone,
additional,
created_at,
updated_at
)
SELECT
(CASE WHEN ca.address_type='billing' THEN "cart_billing" ELSE "cart_shipping" END),
customer_id,
cart_id,
first_name,
last_name,
(SELECT gender FROM customers c WHERE c.id=ca.customer_id),
company_name,
address1,
address2,
postcode,
city,
state,
country,
email,
phone,
JSON_INSERT('{}', '$.old_cart_address_id', id),
created_at,
updated_at
FROM cart_address ca;
SQL;
DB::unprepared($insertCustomerAddresses);
}
private function migrateOrderAddresses(): void
{
$dbPrefix = DB::getTablePrefix();
$insertCustomerAddresses = <<< SQL
INSERT INTO ${dbPrefix}addresses(
address_type,
customer_id,
order_id,
first_name,
last_name,
gender,
company_name,
address1,
address2,
postcode,
city,
state,
country,
email,
phone,
additional,
created_at,
updated_at
)
SELECT
(CASE WHEN oa.address_type='billing' THEN "order_billing" ELSE "order_shipping" END),
customer_id,
order_id,
first_name,
last_name,
(SELECT gender FROM customers c WHERE c.id=oa.customer_id),
company_name,
address1,
address2,
postcode,
city,
state,
country,
email,
phone,
JSON_INSERT('{}', '$.old_order_address_id', id),
created_at,
updated_at
FROM order_address oa;
SQL;
DB::unprepared($insertCustomerAddresses);
}
private function migrateForeignKeys(): void
{
Schema::table('cart_shipping_rates', static function (Blueprint $table) {
$table->dropForeign(['cart_address_id']);
CartAddress::query()
->orderBy('id', 'asc') // for some reason each() needs an orderBy in before
->each(static function ($row) {
CartShippingRate::query()
->where('cart_address_id', $row->additional['old_cart_address_id'])
->update(['cart_address_id' => $row->id]);
});
$table->foreign(['cart_address_id'])
->references('id')
->on('addresses')
->onDelete('cascade');
});
Schema::table('invoices', static function (Blueprint $table) {
$table->dropForeign(['order_address_id']);
OrderAddress::query()
->orderBy('id', 'asc') // for some reason each() needs an orderBy in before
->each(static function ($row) {
Invoice::query()
->where('order_address_id', $row->additional['old_order_address_id'])
->update(['order_address_id' => $row->id]);
});
$table->foreign(['order_address_id'])
->references('id')
->on('addresses')
->onDelete('cascade');
});
Schema::table('shipments', static function (Blueprint $table) {
$table->dropForeign(['order_address_id']);
OrderAddress::query()
->orderBy('id', 'asc') // for some reason each() needs an orderBy in before
->each(static function ($row) {
Shipment::query()
->where('order_address_id', $row->additional['old_order_address_id'])
->update(['order_address_id' => $row->id]);
});
$table->foreign(['order_address_id'])
->references('id')
->on('addresses')
->onDelete('cascade');
});
}
}

View File

@ -22,7 +22,10 @@ class LocalesTableSeeder extends Seeder
'id' => 2,
'code' => 'fr',
'name' => 'French',
]
]);
], [
'id' => 3,
'code' => 'nl',
'name' => 'Dutch',
]]);
}
}

View File

@ -2,11 +2,16 @@
namespace Webkul\Core\Eloquent;
use Prettus\Repository\Contracts\CacheableInterface;
use Prettus\Repository\Eloquent\BaseRepository;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Container\Container as App;
use Prettus\Repository\Traits\CacheableRepository;
abstract class Repository extends BaseRepository {
abstract class Repository extends BaseRepository implements CacheableInterface {
use CacheableRepository;
/**
* Find data by field and value
@ -18,7 +23,7 @@ abstract class Repository extends BaseRepository {
*/
public function findOneByField($field, $value = null, $columns = ['*'])
{
$model = parent::findByField($field, $value, $columns = ['*']);
$model = $this->findByField($field, $value, $columns = ['*']);
return $model->first();
}
@ -33,7 +38,7 @@ abstract class Repository extends BaseRepository {
*/
public function findOneWhere(array $where, $columns = ['*'])
{
$model = parent::findWhere($where, $columns);
$model = $this->findWhere($where, $columns);
return $model->first();
}
@ -132,4 +137,4 @@ abstract class Repository extends BaseRepository {
{
return $this->model;
}
}
}

View File

@ -4,7 +4,5 @@ namespace Webkul\Core\Helpers\Exchange;
abstract class ExchangeRate
{
abstract public function fetchRates();
abstract public function UpdateRates();
abstract public function updateRates();
}

View File

@ -0,0 +1,88 @@
<?php
namespace Webkul\Core\Helpers\Exchange;
use Webkul\Core\Helpers\Exchange\ExchangeRate;
use Webkul\Core\Repositories\CurrencyRepository;
use Webkul\Core\Repositories\ExchangeRateRepository;
class ExchangeRates extends ExchangeRate
{
/**
* API endpoint
*
* @var string
*/
protected $apiEndPoint;
/**
* Holds CurrencyRepository instance
*
* @var \Webkul\Core\Repositories\CurrencyRepository
*/
protected $currencyRepository;
/**
* Holds ExchangeRateRepository instance
*
* @var \Webkul\Core\Repositories\ExchangeRateRepository
*/
protected $exchangeRateRepository;
/**
* Create a new helper instance.
*
* @param \Webkul\Core\Repositories\CurrencyRepository $currencyRepository
* @param \Webkul\Core\Repositories\ExchangeRateRepository $exchangeRateRepository
* @return void
*/
public function __construct(
CurrencyRepository $currencyRepository,
ExchangeRateRepository $exchangeRateRepository
)
{
$this->currencyRepository = $currencyRepository;
$this->exchangeRateRepository = $exchangeRateRepository;
$this->apiEndPoint = 'https://api.exchangeratesapi.io/latest';
}
/**
* Fetch rates and updates in currency_exchange_rates table
*
* @return \Exception|void
*/
public function updateRates()
{
$client = new \GuzzleHttp\Client();
foreach ($this->currencyRepository->all() as $currency) {
if ($currency->code == config('app.currency')) {
continue;
}
$result = $client->request('GET', $this->apiEndPoint . '?base=' . config('app.currency') . '&symbols=' . $currency->code);
$result = json_decode($result->getBody()->getContents(), true);
if (isset($result['success']) && ! $result['success']) {
throw new E\xception(
isset($result['error']['info'])
? $result['error']['info']
: $result['error']['type'], 1);
}
if ($exchangeRate = $currency->exchange_rate) {
$this->exchangeRateRepository->update([
'rate' => $result['rates'][$currency->code],
], $exchangeRate->id);
} else {
$this->exchangeRateRepository->create([
'rate' => $result['rates'][$currency->code],
'target_currency' => $currency->id,
]);
}
}
}
}

View File

@ -3,9 +3,10 @@
namespace Webkul\Core\Helpers\Exchange;
use Webkul\Core\Helpers\Exchange\ExchangeRate;
use Webkul\Core\Repositories\CurrencyRepository;
use Webkul\Core\Repositories\ExchangeRateRepository;
class FixerExchange extends ExchangeRate
class FixerExchange extends ExchangeRate
{
/**
* API key
@ -21,49 +22,76 @@ class FixerExchange extends ExchangeRate
*/
protected $apiEndPoint;
/**
* Holds CurrencyRepository instance
*
* @var \Webkul\Core\Repositories\CurrencyRepository
*/
protected $currencyRepository;
/**
* Holds ExchangeRateRepository instance
*
* @var \Webkul\Core\Helpers\Exchange\ExchangeRate
* @var \Webkul\Core\Repositories\ExchangeRateRepository
*/
protected $exchangeRate;
protected $exchangeRateRepository;
/**
* Create a new helper instance.
*
* @param \Webkul\Core\Repositories\CurrencyRepository $currencyRepository
* @param \Webkul\Core\Repositories\ExchangeRateRepository $exchangeRateRepository
* @return void
*/
public function __construct()
public function __construct(
CurrencyRepository $currencyRepository,
ExchangeRateRepository $exchangeRateRepository
)
{
$this->apiKey = config('services.exchange-api')['fixer']['key'];
$this->currencyRepository = $currencyRepository;
$this->apiEndPoint = 'http://data.fixer.io/api/latest?access_key=' . $this->apiKey;
$this->exchangeRateRepository = $exchangeRateRepository;
$this->apiEndPoint = 'http://data.fixer.io/api';
$this->apiKey = config('services.exchange-api')['fixer']['key'];
}
/**
* @return array
* Fetch rates and updates in currency_exchange_rates table
*
* @return \Exception|void
*/
public function fetchRates()
{
$rates = array();
$this->exchangeRate = app('Webkul\Core\Repositories\ExchangeRateRepository');
// dummy api call
$client = new \GuzzleHttp\Client();
if (config('services.exchange-api')['fixer']['paid_account']) {
$result = $client->request('GET', 'http://data.fixer.io/api/' . date('Y-m-d').'?access_key=' . $this->apiKey.'&base=' . core()->getBaseCurrency()->code . '&symbols=INR');
} else {
$result = $client->request('GET', 'http://data.fixer.io/api/' . date('Y-m-d') . '?access_key=' . $this->apiKey . '&symbols=USD');
}
$result = json_decode($result->getBody()->getContents());
return $result;
}
public function updateRates()
{
$client = new \GuzzleHttp\Client();
foreach ($this->currencyRepository->all() as $currency) {
if ($currency->code == config('app.currency')) {
continue;
}
$result = $client->request('GET', $this->apiEndPoint . '/' . date('Y-m-d') . '?access_key=' . $this->apiKey .'&base=' . config('app.currency') . '&symbols=' . $currency->code);
$result = json_decode($result->getBody()->getContents(), true);
if (isset($result['success']) && ! $result['success']) {
throw new \Exception(
isset($result['error']['info'])
? $result['error']['info']
: $result['error']['type'], 1);
}
if ($exchangeRate = $currency->exchange_rate) {
$this->exchangeRateRepository->update([
'rate' => $result['rates'][$currency->code],
], $exchangeRate->id);
} else {
$this->exchangeRateRepository->create([
'rate' => $result['rates'][$currency->code],
'target_currency' => $currency->id,
]);
}
}
}
}

View File

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

View File

@ -67,7 +67,7 @@ class ExchangeRateController extends Controller
*/
public function create()
{
$currencies = $this->currencyRepository->with('CurrencyExchangeRate')->all();
$currencies = $this->currencyRepository->with('exchange_rate')->all();
return view($this->_config['view'], compact('currencies'));
}
@ -137,38 +137,19 @@ class ExchangeRateController extends Controller
/**
* Update Rates Using Exchange Rates API
*
* @param string $service
* @return \Illuminate\Http\JsonResponse
*/
public function updateRates($service)
public function updateRates()
{
$exchangeService = config('services.exchange-api')[$service];
try {
app(config('services.exchange-api.' . config('services.exchange-api.default') . '.class'))->updateRates();
if (is_array($exchangeService)) {
if (! array_key_exists('class', $exchangeService)) {
return response()->json([
'success' => false,
'rates' => null,
'error' => trans('admin::app.exchange-rate.exchange-class-not-found', [
'service' => $service,
]),
], 400);
}
$exchangeServiceInstance = new $exchangeService['class'];
$updatedRates = $exchangeServiceInstance->fetchRates();
return response()->json([
'success' => true,
'rates' => 'rates',
], 200);
} else {
return response()->json([
'success' => false,
'rates' => null,
'error' => trans('admin::app.exchange-rate.invalid-config'),
], 400);
session()->flash('success', trans('admin::app.settings.exchange_rates.update-success'));
} catch(\Exception $e) {
session()->flash('error', $e->getMessage());
}
return redirect()->back();
}
/**

View File

@ -57,7 +57,9 @@ class SliderController extends Controller
{
$channels = core()->getAllChannels();
return view($this->_config['view']);
$locale = request()->get('locale') ?: core()->getCurrentLocale();
return view($this->_config['view'])->with("locale", $locale);
}
/**

View File

@ -0,0 +1,91 @@
<?php
namespace Webkul\Core\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Webkul\Customer\Models\Customer;
/**
* Class Address
* @package Webkul\Core\Models
*
* @property string $address_type
* @property integer $customer_id
* @property Customer $customer
* @property string $first_name
* @property string $last_name
* @property string $gender
* @property string $company_name
* @property string $address1
* @property string $address2
* @property string $postcode
* @property string $city
* @property string $state
* @property string $country
* @property string $email
* @property string $phone
* @property boolean $default_address
* @property array $additional
*
* @property-read integer $id
* @property-read string $name
* @property-read Carbon $created_at
* @property-read Carbon $updated_at
*
*/
abstract class Address extends Model
{
protected $table = 'addresses';
protected $guarded = [
'id',
'created_at',
'updated_at',
];
protected $fillable = [
'address_type',
'customer_id',
'cart_id',
'order_id',
'first_name',
'last_name',
'gender',
'company_name',
'address1',
'address2',
'postcode',
'city',
'state',
'country',
'email',
'phone',
'default_address',
'vat_id',
'additional',
];
protected $casts = [
'additional' => 'array',
];
/**
* Get all of the attributes for the attribute groups.
*/
public function getNameAttribute(): string
{
return $this->first_name . ' ' . $this->last_name;
}
/**
* Get the customer record associated with the address.
*/
public function customer(): BelongsTo
{
return $this->belongsTo(Customer::class);
}
}

View File

@ -30,9 +30,9 @@ class Currency extends Model implements CurrencyContract
}
/**
* Get the currency_exchange associated with the currency.
* Get the exchange rate associated with the currency.
*/
public function CurrencyExchangeRate()
public function exchange_rate()
{
return $this->hasOne(CurrencyExchangeRateProxy::modelClass(), 'target_currency');
}

View File

@ -20,6 +20,7 @@ class Slider extends Model implements SliderContract
'path',
'content',
'channel_id',
'locale'
];
/**

View File

@ -10,6 +10,9 @@ use Webkul\Core\Core;
use Webkul\Core\Facades\Core as CoreFacade;
use Webkul\Core\Models\SliderProxy;
use Webkul\Core\Observers\SliderObserver;
use Webkul\Core\Console\Commands\BagistoVersion;
use Webkul\Core\Console\Commands\Install;
use Webkul\Core\Console\Commands\ExchangeRateUpdate;
class CoreServiceProvider extends ServiceProvider
{
@ -49,6 +52,8 @@ class CoreServiceProvider extends ServiceProvider
public function register()
{
$this->registerFacades();
$this->registerCommands();
}
/**
@ -66,6 +71,18 @@ class CoreServiceProvider extends ServiceProvider
});
}
/**
* Register the console commands of this package
*
* @return void
*/
protected function registerCommands(): void
{
if ($this->app->runningInConsole()) {
$this->commands([BagistoVersion::class, Install::class, ExchangeRateUpdate::class]);
}
}
/**
* Register factories.
*

View File

@ -7,8 +7,6 @@ use Webkul\Customer\Models\Customer;
use Webkul\Customer\Models\CustomerAddress;
$factory->define(CustomerAddress::class, function (Faker $faker) {
$now = date("Y-m-d H:i:s");
// use an locale from a country in europe so the vat id can be generated
$fakerIt = \Faker\Factory::create('it_IT');
@ -27,8 +25,7 @@ $factory->define(CustomerAddress::class, function (Faker $faker) {
'postcode' => $faker->postcode,
'phone' => $faker->e164PhoneNumber,
'default_address' => array_random([0, 1]),
'created_at' => $now,
'updated_at' => $now,
'address_type' => CustomerAddress::ADDRESS_TYPE,
];
});

View File

@ -3,6 +3,7 @@
namespace Webkul\Customer\Http\Controllers;
use Hash;
use Illuminate\Support\Facades\Event;
use Webkul\Customer\Repositories\CustomerRepository;
use Webkul\Product\Repositories\ProductReviewRepository;
@ -114,7 +115,12 @@ class CustomerController extends Controller
}
}
if ($this->customerRepository->update($data, $id)) {
Event::dispatch('customer.update.before');
if ($customer = $this->customerRepository->update($data, $id)) {
Event::dispatch('customer.update.after', $customer);
Session()->flash('success', trans('shop::app.customer.account.profile.edit-success'));
return redirect()->route($this->_config['redirect']);

View File

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

View File

@ -2,34 +2,32 @@
namespace Webkul\Customer\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Webkul\Core\Models\Address;
use Webkul\Customer\Contracts\CustomerAddress as CustomerAddressContract;
class CustomerAddress extends Model implements CustomerAddressContract
class CustomerAddress extends Address implements CustomerAddressContract
{
protected $table = 'customer_addresses';
public const ADDRESS_TYPE = 'customer';
protected $fillable = [
'customer_id',
'company_name',
'vat_id',
'address1',
'address2',
'country',
'state',
'city',
'postcode',
'phone',
'default_address',
'first_name',
'last_name',
/**
* @var array default values
*/
protected $attributes = [
'address_type' => self::ADDRESS_TYPE,
];
/**
* Get the customer address full name.
* The "booted" method of the model.
*
* @return void
*/
public function getNameAttribute()
protected static function boot()
{
return $this->first_name . ' ' . $this->last_name;
static::addGlobalScope('address_type', static function (Builder $builder) {
$builder->where('address_type', self::ADDRESS_TYPE);
});
parent::boot();
}
}

View File

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

View File

@ -1,6 +1,6 @@
<?php
namespace App\Console\Commands;
namespace Webkul\Product\Console\Commands;
use Illuminate\Console\Command;
use Webkul\Product\Helpers\GenerateProduct;

View File

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

View File

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

View File

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

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