From 6c398f45bdf5da3a63a4ef5b7d1583f583a6f41a Mon Sep 17 00:00:00 2001 From: peternuernberger Date: Fri, 29 Nov 2019 16:46:35 +0100 Subject: [PATCH 01/84] updated some dependencies --- packages/Webkul/Admin/package.json | 14 +++++++------- .../Webkul/Admin/src/Resources/assets/js/app.js | 4 ++++ packages/Webkul/Admin/webpack.mix.js | 4 ++++ packages/Webkul/Ui/package.json | 16 ++++++++-------- packages/Webkul/Ui/publishable/assets/css/ui.css | 2 +- packages/Webkul/Ui/publishable/assets/js/ui.js | 2 +- .../Ui/publishable/assets/mix-manifest.json | 4 ++-- .../Webkul/Ui/src/Resources/assets/js/app.js | 7 +++++-- packages/Webkul/Ui/webpack.mix.js | 4 ++++ 9 files changed, 36 insertions(+), 21 deletions(-) diff --git a/packages/Webkul/Admin/package.json b/packages/Webkul/Admin/package.json index 132be42e2..d594b0c87 100755 --- a/packages/Webkul/Admin/package.json +++ b/packages/Webkul/Admin/package.json @@ -10,14 +10,14 @@ "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" }, "devDependencies": { - "axios": "^0.18", - "cross-env": "^5.1.4", - "laravel-mix": "^2.1", - "laravel-mix-merge-manifest": "^0.1.1", - "jquery": "^3.2", - "vue": "^2.1.10" + "axios": "^0.19.0", + "cross-env": "^6.0.3", + "jquery": "^3.4.1", + "laravel-mix": "^5.0.0", + "laravel-mix-merge-manifest": "^0.1.2", + "vue": "^2.6.10" }, "dependencies": { - "vee-validate": "2.0.0-rc.26" + "vee-validate": "^2.2.15" } } diff --git a/packages/Webkul/Admin/src/Resources/assets/js/app.js b/packages/Webkul/Admin/src/Resources/assets/js/app.js index c197f8d89..0ffbe1b24 100755 --- a/packages/Webkul/Admin/src/Resources/assets/js/app.js +++ b/packages/Webkul/Admin/src/Resources/assets/js/app.js @@ -82,6 +82,10 @@ $(document).ready(function () { }, addFlashMessages() { + if (typeof flashMessages !== 'undefined') { + return; + }; + const flashes = this.$refs.flashes; flashMessages.forEach(function(flash) { diff --git a/packages/Webkul/Admin/webpack.mix.js b/packages/Webkul/Admin/webpack.mix.js index c1352b024..2b81e7e66 100755 --- a/packages/Webkul/Admin/webpack.mix.js +++ b/packages/Webkul/Admin/webpack.mix.js @@ -22,6 +22,10 @@ mix.js(__dirname + "/src/Resources/assets/js/app.js", "js/admin.js") processCssUrls: false }); +if (!mix.inProduction()) { + mix.sourceMaps(); +} + if (mix.inProduction()) { mix.version(); } \ No newline at end of file diff --git a/packages/Webkul/Ui/package.json b/packages/Webkul/Ui/package.json index 798f7716e..5afcb9705 100755 --- a/packages/Webkul/Ui/package.json +++ b/packages/Webkul/Ui/package.json @@ -10,16 +10,16 @@ "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" }, "devDependencies": { - "axios": "^0.18", - "cross-env": "^5.1.4", - "laravel-mix": "^2.1", - "laravel-mix-merge-manifest": "^0.1.1", - "jquery": "^3.2", - "vue": "^2.1.10", - "flatpickr": "^4.4.6" + "axios": "^0.19.0", + "cross-env": "^6.0.3", + "flatpickr": "^4.6.3", + "jquery": "^3.4.1", + "laravel-mix": "^5.0.0", + "laravel-mix-merge-manifest": "^0.1.2", + "vue": "^2.6.10" }, "dependencies": { - "@babel/polyfill": "^7.4.4", + "@babel/polyfill": "^7.7.0", "tooltip.js": "^1.3.1", "url-polyfill": "^1.1.5", "url-search-params-polyfill": "^6.0.0", diff --git a/packages/Webkul/Ui/publishable/assets/css/ui.css b/packages/Webkul/Ui/publishable/assets/css/ui.css index e70650670..e79954c7d 100644 --- a/packages/Webkul/Ui/publishable/assets/css/ui.css +++ b/packages/Webkul/Ui/publishable/assets/css/ui.css @@ -1 +1 @@ -.active .cms-icon,.active.configuration-icon,.catalog-icon,.cms-icon,.configuration-icon,.customer-icon,.dashboard-icon,.promotion-icon,.sales-icon,.settings-icon{width:48px;height:48px;display:inline-block;background-size:cover}.icon{display:inline-block;background-size:cover}.dashboard-icon{background-image:url("../images/Icon-Dashboard.svg")}.sales-icon{background-image:url("../images/Icon-Sales.svg")}.catalog-icon{background-image:url("../images/Icon-Catalog.svg")}.customer-icon{background-image:url("../images/Icon-Customers.svg")}.configuration-icon{background-image:url("../images/Icon-Configure.svg")}.settings-icon{background-image:url("../images/Icon-Settings.svg")}.promotion-icon{background-image:url("../images/icon-promotion.svg")}.cms-icon{background-image:url("../images/Icon-CMS.svg")}.angle-right-icon{background-image:url("../images/Angle-Right.svg");width:17px;height:17px}.angle-left-icon{background-image:url("../images/Angle-Left.svg");width:17px;height:17px}.arrow-down-icon{background-image:url("../images/Arrow-Down-Light.svg");width:14px;height:8px}.arrow-right-icon{background-image:url("../images/Arrow-Right.svg");width:18px;height:18px}.white-cross-sm-icon{background-image:url("../images/Icon-Sm-Cross-White.svg");width:18px;height:18px}.accordian-up-icon{background-image:url("../images/Accordion-Arrow-Up.svg");width:24px;height:24px}.accordian-down-icon{background-image:url("../images/Accordion-Arrow-Down.svg");width:24px;height:24px}.cross-icon{background-image:url("../images/Icon-Crossed.svg");width:18px;height:18px}.trash-icon{background-image:url("../images/Icon-Trash.svg");width:24px;height:24px}.remove-icon{background-image:url("../images/Icon-remove.svg");width:24px;height:24px}.pencil-lg-icon{background-image:url("../images/Icon-Pencil-Large.svg");width:24px;height:24px}.eye-icon{background-image:url("../images/Icon-eye.svg");width:24px;height:24px}.search-icon{background-image:url("../images/icon-search.svg");width:24px;height:24px}.sortable-icon{background-image:url("../images/Icon-Sortable.svg");width:24px;height:24px}.sort-down-icon,.sort-up-icon{background-image:url("../images/Icon-Sort-Down.svg");width:18px;height:18px}.sort-up-icon{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.primary-back-icon{background-image:url("../images/Icon-Back-Primary.svg");width:24px;height:24px}.checkbox-dash-icon{background-image:url("../images/Checkbox-Dash.svg");width:24px;height:24px}.account-icon{background-image:url("../images/icon-account.svg");width:24px;height:24px}.expand-icon{background-image:url("../images/Expand-Light.svg");width:18px;height:18px}.expand-on-icon{background-image:url("../images/Expand-Light-On.svg");width:18px;height:18px}.dark-left-icon{background-image:url("../images/arrow-left-dark.svg");width:18px;height:18px}.light-right-icon{background-image:url("../images/arrow-right-light.svg");width:18px;height:18px}.folder-icon{background-image:url("../images/Folder-Icon.svg");width:24px;height:24px}.star-icon{background-image:url("../images/Star-Icon.svg");width:24px;height:24px}.arrow-down-white-icon{background-image:url("../images/down-arrow-white.svg");width:17px;height:13px}.arrow-up-white-icon{background-image:url("../images/up-arrow-white.svg");width:17px;height:13px}.profile-pic-icon{background-image:url("../images/Profile-Pic.svg");width:60px;height:60px}.graph-up-icon{background-image:url("../images/Icon-Graph-Green.svg");width:24px;height:24px}.graph-down-icon{background-image:url("../images/Icon-Graph-Red.svg");width:24px;height:24px}.no-result-icon{background-image:url("../images/limited-icon.svg");width:52px;height:47px}.note-icon{background-image:url("../images/icon-note.svg")}.list-icon,.note-icon{width:24px;height:24px}.list-icon{background-image:url("../images/Icon-Listing.svg")}.active .dashboard-icon{background-image:url("../images/Icon-Dashboard-Active.svg")}.active .sales-icon{background-image:url("../images/Icon-Sales-Active.svg")}.active .catalog-icon{background-image:url("../images/Icon-Catalog-Active.svg")}.active .customer-icon{background-image:url("../images/Icon-Customers-Active.svg")}.active .settings-icon{background-image:url("../images/Icon-Settings-Active.svg")}.active .configuration-icon{background-image:url("../images/Icon-Configure-Active.svg")}.active .promotion-icon{background-image:url("../images/icon-promotion-active.svg")}.active .cms-icon{background-image:url("../images/Icon-CMS-Active.svg")}.active>.arrow-down-icon{background-image:url("../images/Arrow-Down.svg");width:14px;height:8px}.active>.expand-icon{background-image:url("../images/Expand-Light-On.svg")}.active.dashboard-icon{background-image:url("../images/Icon-Dashboard-Active.svg")}.active.customer-icon{background-image:url("../images/Icon-Customers-Active.svg")}.active.sales-icon{background-image:url("../images/Icon-Sales-Active.svg")}.active.settings-icon{background-image:url("../images/Icon-Settings-Active.svg")}.active.configuration-icon{background-image:url("../images/Icon-Configure-Active.svg")}.active.arrow-down-icon{background-image:url("../images/Arrow-Down.svg");width:14px;height:8px}.active.expand-icon{background-image:url("../images/Expand-Light-On.svg")}.icon-404{background-image:url("../images/404-image.svg");width:255px;height:255px}.export-icon{background-image:url("../images/Icon-Export.svg");width:32px;height:32px}.import-icon{background-image:url("../images/Icon-Import.svg");width:32px;height:32px}.star-blue-icon{width:17px;height:17px;background-image:url("../images/Icon-star.svg")}.grid-container{display:block;width:100%}.filter-row-one{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;width:100%;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-bottom:20px}.filter-row-one .dropdown-filters{position:absolute;right:25px}.filter-row-two{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-bottom:10px}.filter-row-two,.search-filter{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex}.search-filter .control{font-size:15px;border:2px solid #c7c7c7;border-right:none;border-top-right-radius:0;border-bottom-right-radius:0;border-radius:3px;height:36px;width:280px;padding-left:10px}.search-filter .contorl:focus{border-color:#0041ff}.search-filter .icon-wrapper{border:2px solid #c7c7c7;border-radius:3px;border-top-left-radius:0;border-bottom-left-radius:0;height:36px;width:36px;margin-left:-1px}.search-filter .icon-wrapper .search-icon{margin-top:3px;margin-left:3px}.grid-dropdown-header{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:36px;width:200px;border:2px solid #c7c7c7;border-radius:3px;color:#8e8e8e;padding:0 5px}.grid-dropdown-header .arrow-icon-down{float:right}.dropdown-list.dropdown-container{padding:15px;width:100%;top:43px}.dropdown-list.dropdown-container ul li .control-group{margin-bottom:15px}.dropdown-list.dropdown-container .apply-filter{padding:10px;width:100%}.filter-tag{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;margin-right:20px}.filter-tag,.filter-tag .wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-size:14px;height:28px;border-radius:2px}.filter-tag .wrapper{margin-left:10px;padding:5px 10px;background:#e7e7e7;color:#000311;letter-spacing:-.22px}.filter-tag .wrapper .icon.cross-icon{margin-left:10px;cursor:pointer}@-webkit-keyframes jelly{0%{-webkit-transform:translateY(0) scale(.7);transform:translateY(0) scale(.7);opacity:0}70%{-webkit-transform:translateY(5px) scale(1.05);transform:translateY(5px) scale(1.05);opacity:1}to{-webkit-transform:translateY(0) scale(1);transform:translateY(0) scale(1);opacity:1}}@keyframes jelly{0%{-webkit-transform:translateY(0) scale(.7);transform:translateY(0) scale(.7);opacity:0}70%{-webkit-transform:translateY(5px) scale(1.05);transform:translateY(5px) scale(1.05);opacity:1}to{-webkit-transform:translateY(0) scale(1);transform:translateY(0) scale(1);opacity:1}}@-webkit-keyframes jelly-out{0%{-webkit-transform:translateY(0) scale(1);transform:translateY(0) scale(1);opacity:1}30%{-webkit-transform:translateY(-5px) scale(1.05);transform:translateY(-5px) scale(1.05);opacity:1}to{-webkit-transform:translateY(0) scale(.7);transform:translateY(0) scale(.7);opacity:0}}@keyframes jelly-out{0%{-webkit-transform:translateY(0) scale(1);transform:translateY(0) scale(1);opacity:1}30%{-webkit-transform:translateY(-5px) scale(1.05);transform:translateY(-5px) scale(1.05);opacity:1}to{-webkit-transform:translateY(0) scale(.7);transform:translateY(0) scale(.7);opacity:0}}*{-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}:focus{outline:none}.mb-10{margin-bottom:10px}.mb-15{margin-bottom:15px}.mb-20{margin-bottom:20px}.mb-25{margin-bottom:25px}.mb-30{margin-bottom:30px}.mb-35{margin-bottom:35px}.mb-40{margin-bottom:40px}.mb-45{margin-bottom:45px}.mb-50{margin-bottom:50px}.mb-60{margin-bottom:60px}.mb-70{margin-bottom:70px}.mb-80{margin-bottom:80px}.mb-90{margin-bottom:90px}.mt-5{margin-top:5px}.mt-10{margin-top:10px}.mt-15{margin-top:15px}.mt-20{margin-top:20px}.mt-25{margin-top:25px}.mt-30{margin-top:30px}.mt-35{margin-top:35px}.mt-40{margin-top:40px}.mt-45{margin-top:45px}.mt-50{margin-top:50px}.mt-60{margin-top:60px}.mt-70{margin-top:70px}.mt-80{margin-top:80px}.mt-90{margin-top:90px}body{letter-spacing:-.26px;line-height:19px}a:active,a:focus,a:hover,a:link,a:visited{text-decoration:none;color:#0041ff}::-moz-selection{background-color:rgba(0,64,255,.6);color:#fff}::selection{background-color:rgba(0,64,255,.6);color:#fff}textarea{resize:none}ul{margin:0;padding:0;list-style:none}h1{font-size:28px;margin-top:0}h1,h2{color:#3a3a3a}h2{font-size:24px}h3{font-size:20px}h3,h4{color:#3a3a3a}h4{font-size:16px}h5{font-size:12px;color:#3a3a3a}.hide{display:none!important}.row{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.btn{-webkit-box-shadow:0 1px 4px 0 rgba(0,0,0,.2),0 0 8px 0 rgba(0,0,0,.1);box-shadow:0 1px 4px 0 rgba(0,0,0,.2),0 0 8px 0 rgba(0,0,0,.1);border-radius:3px;border:none;color:#fff;cursor:pointer;-webkit-transition:.2s cubic-bezier(.4,0,.2,1);transition:.2s cubic-bezier(.4,0,.2,1);font:inherit;display:inline-block}.btn:active,.btn:focus,.btn:hover{opacity:.75;border:none}.btn.btn-sm{padding:6px 12px}.btn.btn-md{padding:8px 16px}.btn.btn-lg{padding:10px 20px}.btn.btn-xl{padding:12px 24px;font-size:16px}.btn.btn-primary{background:#0041ff;color:#fff}.btn.btn-black{background:#000;color:#fff}.btn.btn-white{background:#fff;color:#000}.btn:disabled,.btn[disabled=disabled],.btn[disabled=disabled]:active,.btn[disabled=disabled]:hover{cursor:not-allowed;background:#b1b1ae;-webkit-box-shadow:none;box-shadow:none;opacity:1}.dropdown-btn{min-width:150px;text-align:left;background:#fff;border:2px solid #c7c7c7;border-radius:3px;font-size:14px;padding:8px 35px 8px 10px;cursor:pointer;position:relative}.dropdown-btn:active,.dropdown-btn:focus,.dropdown-btn:hover{opacity:.75;border:2px solid #c7c7c7}.dropdown-btn .icon{position:absolute;right:10px;top:50%;margin-top:-4px}.dropdown-toggle{cursor:pointer}.dropdown-open{position:relative}.dropdown-list{width:200px;margin-bottom:20px;-webkit-box-shadow:0 2px 4px 0 rgba(0,0,0,.16),0 0 9px 0 rgba(0,0,0,.16);box-shadow:0 2px 4px 0 rgba(0,0,0,.16),0 0 9px 0 rgba(0,0,0,.16);border-radius:3px;background-color:#fff;position:absolute;display:none;z-index:10;text-align:left}.dropdown-list.bottom-left{top:42px;left:0}.dropdown-list.bottom-right{top:42px;right:0}.dropdown-list.top-left{bottom:0;left:42px}.dropdown-list.top-right{bottom:0;right:42px}.dropdown-list .search-box{padding:20px;border-bottom:1px solid #e8e8e8}.dropdown-list .search-box .control{background:#fff;border:2px solid #c7c7c7;border-radius:3px;width:100%;height:36px;display:inline-block;vertical-align:middle;-webkit-transition:.2s cubic-bezier(.4,0,.2,1);transition:.2s cubic-bezier(.4,0,.2,1);padding:0 10px;font-size:15px}.dropdown-list .search-box .control:focus{border-color:#0041ff}.dropdown-list .dropdown-container{padding:20px;overflow-y:auto}.dropdown-list .dropdown-container label{font-size:15px;display:inline-block;text-transform:uppercase;color:#9e9e9e;font-weight:700;padding-bottom:5px}.dropdown-list .dropdown-container ul{margin:0;list-style-type:none;padding:0}.dropdown-list .dropdown-container ul li{padding:5px 0}.dropdown-list .dropdown-container ul li a:active,.dropdown-list .dropdown-container ul li a:focus,.dropdown-list .dropdown-container ul li a:link,.dropdown-list .dropdown-container ul li a:visited{color:#333;display:block}.dropdown-list .dropdown-container ul li a:hover{color:#0041ff}.dropdown-list .dropdown-container ul li .checkbox{margin:0}.dropdown-list .dropdown-container ul li .control-group label{color:#3a3a3a;font-size:15px;font-weight:500;text-transform:capitalize;width:100%}.dropdown-list .dropdown-container .btn{width:100%;margin-top:10px}.section .secton-title{font-size:18px;color:#8e8e8e;padding:15px 0;border-bottom:1px solid #e8e8e8}.section .section-content{display:block;padding:20px 0}.section .section-content .row{display:block;padding:7px 0}.section .section-content .row .title{width:200px}.section .section-content .row .title,.section .section-content .row .value{color:#3a3a3a;letter-spacing:-.26px;display:inline-block}.table{width:100%}.table table{border-collapse:collapse;text-align:left;width:100%}.table table thead th{font-weight:700;padding:12px 10px;background:#f8f9fa;color:#3a3a3a}.table table tbody td{padding:10px;border-bottom:1px solid #d3d3d3;color:#3a3a3a;vertical-align:top}.table table tbody td.actions .action{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex}.table table tbody td.actions .icon{cursor:pointer;vertical-align:middle}.table table tbody td.empty{text-align:center}.table table tbody tr:last-child td{border-bottom:none}.table .control-group{width:100%;margin-bottom:0;min-width:140px}.table .control-group .control{width:100%;margin:0}.pagination .page-item{background:#fff;border:2px solid #c7c7c7;border-radius:3px;padding:7px 14px;margin-right:5px;font-size:16px;display:inline-block;color:#8e8e8e;vertical-align:middle;text-decoration:none}.pagination .page-item.next,.pagination .page-item.previous{padding:6px 9px}.pagination .page-item.active{background:#0041ff;color:#fff;border-color:#0041ff}.pagination .page-item .icon{vertical-align:middle;margin-bottom:3px}.checkbox{position:relative;display:block}.checkbox input{left:0;opacity:0;position:absolute;top:0;height:24px;width:24px;z-index:100}.checkbox .checkbox-view{background-image:url("../images/Checkbox.svg");height:24px;width:24px;margin:0;display:inline-block!important;vertical-align:middle;margin-right:5px}.checkbox input:checked+.checkbox-view{background-image:url("../images/Checkbox-Checked.svg")}.checkbox input:disabled+.checkbox-view{opacity:.5;cursor:not-allowed}.radio{position:relative;display:block;margin:10px 5px 5px 0}.radio input{left:0;opacity:0;position:absolute;top:0;z-index:100}.radio .radio-view{background-image:url("../images/controls.svg");background-position:-21px 0;height:20px;width:20px;margin:0;display:inline-block!important;vertical-align:middle;margin-right:5px}.radio input:checked+.radio-view{background-position:-21px -21px}.radio input:disabled+.radio-view{opacity:.5;cursor:not-allowed}.control-group{display:block;margin-bottom:25px;font-size:15px;color:#333;width:750px;max-width:100%;position:relative}.control-group label{display:block;color:#3a3a3a}.control-group label.required:after{content:"*";color:#fc6868;font-weight:700;display:inline-block}.control-group textarea.control{height:100px;padding:10px}.control-group .control{background:#fff;border:2px solid #c7c7c7;border-radius:3px;width:70%;height:36px;display:inline-block;vertical-align:middle;-webkit-transition:.2s cubic-bezier(.4,0,.2,1);transition:.2s cubic-bezier(.4,0,.2,1);padding:0 10px;font-size:15px;margin-top:10px;margin-bottom:5px}.control-group .control:focus{border-color:#0041ff}.control-group .control[disabled=disabled]{border-color:#d3d3d3;background-color:#d3d3d3;cursor:not-allowed}.control-group .control[multiple]{height:100px}.control-group.date:after,.control-group.datetime:after{background-image:url("../images/Icon-Calendar.svg");width:24px;height:24px;content:"";display:inline-block;vertical-align:middle;margin-left:-34px;margin-top:2px;pointer-events:none}.control-group .control-info{display:block;font-size:14px;color:#6f6f6f;font-style:italic}.control-group .control-error{display:none;color:#ff5656;margin-top:5px}.control-group.has-error .control{border-color:#fc6868}.control-group.has-error .control-error{display:block}.control-group.price .currency-code{vertical-align:middle;display:inline-block}.control-group .switch{position:relative;display:inline-block;width:60px;height:34px;margin-top:10px;margin-bottom:5px}.control-group .switch input{opacity:0;width:0;height:0}.control-group .slider{cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#8e8e8e}.control-group .slider,.control-group .slider:before{position:absolute;-webkit-transition:.2s;transition:.2s}.control-group .slider:before{content:"";height:26px;width:26px;left:4px;bottom:4px;background-color:#fff}.control-group input:checked+.slider{background-color:#0041ff}.control-group input:focus+.slider{-webkit-box-shadow:0 0 1px #0041ff;box-shadow:0 0 1px #0041ff}.control-group input:checked+.slider:before{-webkit-transform:translateX(26px);transform:translateX(26px)}.control-group .slider.round{border-radius:34px}.control-group .slider.round:before{border-radius:50%}.button-group{margin-top:20px;margin-bottom:20px}.alert-wrapper{width:300px;top:10px;right:10px;position:fixed;z-index:100;text-align:left}.alert-wrapper .alert{width:300px;padding:15px;border-radius:3px;display:inline-block;-webkit-box-shadow:0 4px 15.36px .64px rgba(0,0,0,.1),0 2px 6px 0 rgba(0,0,0,.12);box-shadow:0 4px 15.36px .64px rgba(0,0,0,.1),0 2px 6px 0 rgba(0,0,0,.12);position:relative;-webkit-animation:jelly .5s ease-in-out;animation:jelly .5s ease-in-out;-webkit-transform-origin:center top;transform-origin:center top;z-index:500;margin-bottom:10px}.alert-wrapper .alert.alert-error{background:#fc6868}.alert-wrapper .alert.alert-info{background:#204d74}.alert-wrapper .alert.alert-success{background:#4caf50}.alert-wrapper .alert.alert-warning{background:#ffc107}.alert-wrapper .alert .icon{position:absolute;right:10px;top:10px;cursor:pointer}.alert-wrapper .alert p{color:#fff;margin:0;padding:0;font-size:15px}.tabs ul{border-bottom:1px solid #e8e8e8}.tabs ul li{display:inline-block}.tabs ul li a{padding:15px 20px;cursor:pointer;margin:0 2px;text-align:center;color:#000311;display:block}.tabs ul li.active a{border-bottom:3px solid #0041ff}.accordian,accordian{display:inline-block;width:100%}.accordian .accordian-header,.accordian div[slot*=header],accordian .accordian-header,accordian div[slot*=header]{width:100%;display:inline-block;font-size:18px;color:#3a3a3a;border-top:1px solid #e8e8e8;border-bottom:1px solid #e8e8e8;padding:20px 15px;cursor:pointer;margin-top:-1px}.accordian .accordian-header .expand-icon,.accordian div[slot*=header] .expand-icon,accordian .accordian-header .expand-icon,accordian div[slot*=header] .expand-icon{background-image:url("../images/Expand-Light.svg");margin-right:10px;margin-top:3px}.accordian .accordian-header h1,.accordian div[slot*=header] h1,accordian .accordian-header h1,accordian div[slot*=header] h1{margin:0;font-size:20px;font-weight:500;display:inline-block}.accordian .accordian-header .icon,.accordian div[slot*=header] .icon,accordian .accordian-header .icon,accordian div[slot*=header] .icon{float:right}.accordian .accordian-header .icon.left,.accordian div[slot*=header] .icon.left,accordian .accordian-header .icon.left,accordian div[slot*=header] .icon.left{float:left}.accordian.error .accordian-header,accordian.error .accordian-header{color:#ff5656}.accordian .accordian-content,.accordian div[slot*=body],accordian .accordian-content,accordian div[slot*=body]{width:100%;padding:20px 15px;display:none;-webkit-transition:all .3s ease;transition:all .3s ease}.accordian.active>.accordian-content,accordian.active>.accordian-content{display:inline-block}.accordian.active>.accordian-header .expand-icon,accordian.active>.accordian-header .expand-icon{background-image:url("../images/Expand-Light-On.svg")}.tree-container .tree-item{padding-left:30px;display:inline-block;margin-top:10px;width:100%}.tree-container .tree-item>.tree-item{display:none}.tree-container .tree-item.active>.tree-item{display:inline-block}.tree-container .tree-item .checkbox,.tree-container .tree-item .radio{margin:0;display:inline-block}.tree-container .tree-item .expand-icon{display:inline-block;margin-right:10px;cursor:pointer;background-image:url("../images/Expand-Light.svg");width:18px;height:18px;vertical-align:middle}.tree-container .tree-item .folder-icon{vertical-align:middle;margin-right:10px}.tree-container .tree-item.active>.expand-icon{background-image:url("../images/Expand-Light-On.svg")}.tree-container>.tree-item{padding-left:0}.panel{-webkit-box-shadow:0 2px 25px 0 rgba(0,0,0,.15);box-shadow:0 2px 25px 0 rgba(0,0,0,.15);border-radius:5px;background:#fff}.panel .panel-content{padding:20px}modal{display:none}.modal-open{overflow:hidden}.modal-overlay{display:none;overflow-y:auto;z-index:10;top:0;right:0;bottom:0;left:0;position:fixed;background:#000;opacity:.7}.modal-open .modal-overlay{display:block}.modal-container{background:#fff;top:100px;width:600px;max-width:80%;left:50%;margin-left:-300px;position:fixed;z-index:11;-webkit-box-shadow:0 15px 25px 0 rgba(0,0,0,.03),0 20px 45px 5px rgba(0,0,0,.2);box-shadow:0 15px 25px 0 rgba(0,0,0,.03),0 20px 45px 5px rgba(0,0,0,.2);-webkit-animation:fade-in-white .3s ease-in-out;animation:fade-in-white .3s ease-in-out;-webkit-animation:jelly .5s ease-in-out;animation:jelly .5s ease-in-out;border-radius:5px;overflow-y:auto;max-height:80%}.modal-container .modal-header{padding:20px}.modal-container .modal-header h3{display:inline-block;font-size:20px;color:#3a3a3a;margin:0}.modal-container .modal-header .icon{float:right;cursor:pointer}.modal-container .modal-body{padding:20px}.modal-container .modal-body .control-group .control{width:100%}@media only screen and (max-width:770px){.modal-container{max-width:80%;left:10%;margin-left:0}}.label{background:#e7e7e7;border-radius:2px;padding:8px;color:#000311;display:inline-block}.label.label-sm{padding:5px}.label.label-md{padding:8px}.label.label-lg{padding:11px}.label.label-xl{padding:14px}.badge{border-radius:50px;color:#fff;padding:8px;white-space:nowrap}.badge.badge-sm{padding:5px}.badge.badge-md{padding:3px 10px}.badge.badge-lg{padding:11px}.badge.badge-xl{padding:14px}.badge.badge-success{background-color:#4caf50}.badge.badge-info{background-color:#0041ff}.badge.badge-danger{background-color:#fc6868}.badge.badge-warning{background-color:#ffc107}.image-wrapper{margin-bottom:20px;margin-top:10px;display:inline-block;width:100%}.image-wrapper .image-item{width:200px;height:200px;margin-right:20px;background:#f8f9fa;border-radius:3px;display:inline-block;position:relative;background-image:url("../images/placeholder-icon.svg");background-repeat:no-repeat;background-position:50%;margin-bottom:20px;float:left}.image-wrapper .image-item img.preview{width:100%;height:100%}.image-wrapper .image-item input{display:none}.image-wrapper .image-item .remove-image{background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,.08)),to(rgba(0,0,0,.24)));background-image:linear-gradient(-180deg,rgba(0,0,0,.08),rgba(0,0,0,.24));border-radius:0 0 4px 4px;position:absolute;bottom:0;width:100%;padding:10px;text-align:center;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.24);margin-right:20px;cursor:pointer}.image-wrapper .image-item:hover .remove-image{display:block}.image-wrapper .image-item.has-image{background-image:none}.vue-swatches__trigger{border:1px solid #d3d3d3}.helper-container{display:block}.helper-container .group code{font-weight:700}div.rad-info-box{width:fit-content;text-align:center;box-shadow:1px 1px 2px 0 #ccc;padding:20px;box-shadow:0 2px 5px 0 rgba(0,0,0,.26);font-weight:700;background:#fff!important} \ No newline at end of file +.active .cms-icon,.active.configuration-icon,.catalog-icon,.cms-icon,.configuration-icon,.customer-icon,.dashboard-icon,.promotion-icon,.sales-icon,.settings-icon{width:48px;height:48px;display:inline-block;background-size:cover}.icon{display:inline-block;background-size:cover}.dashboard-icon{background-image:url(../images/Icon-Dashboard.svg)}.sales-icon{background-image:url(../images/Icon-Sales.svg)}.catalog-icon{background-image:url(../images/Icon-Catalog.svg)}.customer-icon{background-image:url(../images/Icon-Customers.svg)}.configuration-icon{background-image:url(../images/Icon-Configure.svg)}.settings-icon{background-image:url(../images/Icon-Settings.svg)}.promotion-icon{background-image:url(../images/icon-promotion.svg)}.cms-icon{background-image:url(../images/Icon-CMS.svg)}.angle-right-icon{background-image:url(../images/Angle-Right.svg);width:17px;height:17px}.angle-left-icon{background-image:url(../images/Angle-Left.svg);width:17px;height:17px}.arrow-down-icon{background-image:url(../images/Arrow-Down-Light.svg);width:14px;height:8px}.arrow-right-icon{background-image:url(../images/Arrow-Right.svg);width:18px;height:18px}.white-cross-sm-icon{background-image:url(../images/Icon-Sm-Cross-White.svg);width:18px;height:18px}.accordian-up-icon{background-image:url(../images/Accordion-Arrow-Up.svg);width:24px;height:24px}.accordian-down-icon{background-image:url(../images/Accordion-Arrow-Down.svg);width:24px;height:24px}.cross-icon{background-image:url(../images/Icon-Crossed.svg);width:18px;height:18px}.trash-icon{background-image:url(../images/Icon-Trash.svg);width:24px;height:24px}.remove-icon{background-image:url(../images/Icon-remove.svg);width:24px;height:24px}.pencil-lg-icon{background-image:url(../images/Icon-Pencil-Large.svg);width:24px;height:24px}.eye-icon{background-image:url(../images/Icon-eye.svg);width:24px;height:24px}.search-icon{background-image:url(../images/icon-search.svg);width:24px;height:24px}.sortable-icon{background-image:url(../images/Icon-Sortable.svg);width:24px;height:24px}.sort-down-icon,.sort-up-icon{background-image:url(../images/Icon-Sort-Down.svg);width:18px;height:18px}.sort-up-icon{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.primary-back-icon{background-image:url(../images/Icon-Back-Primary.svg);width:24px;height:24px}.checkbox-dash-icon{background-image:url(../images/Checkbox-Dash.svg);width:24px;height:24px}.account-icon{background-image:url(../images/icon-account.svg);width:24px;height:24px}.expand-icon{background-image:url(../images/Expand-Light.svg);width:18px;height:18px}.expand-on-icon{background-image:url(../images/Expand-Light-On.svg);width:18px;height:18px}.dark-left-icon{background-image:url(../images/arrow-left-dark.svg);width:18px;height:18px}.light-right-icon{background-image:url(../images/arrow-right-light.svg);width:18px;height:18px}.folder-icon{background-image:url(../images/Folder-Icon.svg);width:24px;height:24px}.star-icon{background-image:url(../images/Star-Icon.svg);width:24px;height:24px}.arrow-down-white-icon{background-image:url(../images/down-arrow-white.svg);width:17px;height:13px}.arrow-up-white-icon{background-image:url(../images/up-arrow-white.svg);width:17px;height:13px}.profile-pic-icon{background-image:url(../images/Profile-Pic.svg);width:60px;height:60px}.graph-up-icon{background-image:url(../images/Icon-Graph-Green.svg);width:24px;height:24px}.graph-down-icon{background-image:url(../images/Icon-Graph-Red.svg);width:24px;height:24px}.no-result-icon{background-image:url(../images/limited-icon.svg);width:52px;height:47px}.note-icon{background-image:url(../images/icon-note.svg)}.list-icon,.note-icon{width:24px;height:24px}.list-icon{background-image:url(../images/Icon-Listing.svg)}.active .dashboard-icon{background-image:url(../images/Icon-Dashboard-Active.svg)}.active .sales-icon{background-image:url(../images/Icon-Sales-Active.svg)}.active .catalog-icon{background-image:url(../images/Icon-Catalog-Active.svg)}.active .customer-icon{background-image:url(../images/Icon-Customers-Active.svg)}.active .settings-icon{background-image:url(../images/Icon-Settings-Active.svg)}.active .configuration-icon{background-image:url(../images/Icon-Configure-Active.svg)}.active .promotion-icon{background-image:url(../images/icon-promotion-active.svg)}.active .cms-icon{background-image:url(../images/Icon-CMS-Active.svg)}.active>.arrow-down-icon{background-image:url(../images/Arrow-Down.svg);width:14px;height:8px}.active>.expand-icon{background-image:url(../images/Expand-Light-On.svg)}.active.dashboard-icon{background-image:url(../images/Icon-Dashboard-Active.svg)}.active.customer-icon{background-image:url(../images/Icon-Customers-Active.svg)}.active.sales-icon{background-image:url(../images/Icon-Sales-Active.svg)}.active.settings-icon{background-image:url(../images/Icon-Settings-Active.svg)}.active.configuration-icon{background-image:url(../images/Icon-Configure-Active.svg)}.active.arrow-down-icon{background-image:url(../images/Arrow-Down.svg);width:14px;height:8px}.active.expand-icon{background-image:url(../images/Expand-Light-On.svg)}.icon-404{background-image:url(../images/404-image.svg);width:255px;height:255px}.export-icon{background-image:url(../images/Icon-Export.svg);width:32px;height:32px}.import-icon{background-image:url(../images/Icon-Import.svg);width:32px;height:32px}.star-blue-icon{width:17px;height:17px;background-image:url(../images/Icon-star.svg)}.grid-container{display:block;width:100%}.filter-row-one{display:-webkit-inline-box;display:inline-flex;width:100%;-webkit-box-pack:justify;justify-content:space-between;-webkit-box-align:center;align-items:center;margin-bottom:20px}.filter-row-one .dropdown-filters{position:absolute;right:25px}.filter-row-two{-webkit-box-align:start;align-items:flex-start;flex-wrap:wrap;margin-bottom:10px}.filter-row-two,.search-filter{display:-webkit-inline-box;display:inline-flex}.search-filter .control{font-size:15px;border:2px solid #c7c7c7;border-right:none;border-top-right-radius:0;border-bottom-right-radius:0;border-radius:3px;height:36px;width:280px;padding-left:10px}.search-filter .contorl:focus{border-color:#0041ff}.search-filter .icon-wrapper{border:2px solid #c7c7c7;border-radius:3px;border-top-left-radius:0;border-bottom-left-radius:0;height:36px;width:36px;margin-left:-1px}.search-filter .icon-wrapper .search-icon{margin-top:3px;margin-left:3px}.grid-dropdown-header{display:-webkit-inline-box;display:inline-flex;-webkit-box-pack:justify;justify-content:space-between;-webkit-box-align:center;align-items:center;height:36px;width:200px;border:2px solid #c7c7c7;border-radius:3px;color:#8e8e8e;padding:0 5px}.grid-dropdown-header .arrow-icon-down{float:right}.dropdown-list.dropdown-container{padding:15px;width:100%;top:43px}.dropdown-list.dropdown-container ul li .control-group{margin-bottom:15px}.dropdown-list.dropdown-container .apply-filter{padding:10px;width:100%}.filter-tag{-webkit-box-pack:justify;justify-content:space-between;margin-right:20px}.filter-tag,.filter-tag .wrapper{display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-direction:row;-webkit-box-align:center;align-items:center;font-size:14px;height:28px;border-radius:2px}.filter-tag .wrapper{margin-left:10px;padding:5px 10px;background:#e7e7e7;color:#000311;letter-spacing:-.22px}.filter-tag .wrapper .icon.cross-icon{margin-left:10px;cursor:pointer}@-webkit-keyframes jelly{0%{-webkit-transform:translateY(0) scale(.7);transform:translateY(0) scale(.7);opacity:0}70%{-webkit-transform:translateY(5px) scale(1.05);transform:translateY(5px) scale(1.05);opacity:1}to{-webkit-transform:translateY(0) scale(1);transform:translateY(0) scale(1);opacity:1}}@keyframes jelly{0%{-webkit-transform:translateY(0) scale(.7);transform:translateY(0) scale(.7);opacity:0}70%{-webkit-transform:translateY(5px) scale(1.05);transform:translateY(5px) scale(1.05);opacity:1}to{-webkit-transform:translateY(0) scale(1);transform:translateY(0) scale(1);opacity:1}}@-webkit-keyframes jelly-out{0%{-webkit-transform:translateY(0) scale(1);transform:translateY(0) scale(1);opacity:1}30%{-webkit-transform:translateY(-5px) scale(1.05);transform:translateY(-5px) scale(1.05);opacity:1}to{-webkit-transform:translateY(0) scale(.7);transform:translateY(0) scale(.7);opacity:0}}@keyframes jelly-out{0%{-webkit-transform:translateY(0) scale(1);transform:translateY(0) scale(1);opacity:1}30%{-webkit-transform:translateY(-5px) scale(1.05);transform:translateY(-5px) scale(1.05);opacity:1}to{-webkit-transform:translateY(0) scale(.7);transform:translateY(0) scale(.7);opacity:0}}*{box-sizing:border-box;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}:focus{outline:none}.mb-10{margin-bottom:10px}.mb-15{margin-bottom:15px}.mb-20{margin-bottom:20px}.mb-25{margin-bottom:25px}.mb-30{margin-bottom:30px}.mb-35{margin-bottom:35px}.mb-40{margin-bottom:40px}.mb-45{margin-bottom:45px}.mb-50{margin-bottom:50px}.mb-60{margin-bottom:60px}.mb-70{margin-bottom:70px}.mb-80{margin-bottom:80px}.mb-90{margin-bottom:90px}.mt-5{margin-top:5px}.mt-10{margin-top:10px}.mt-15{margin-top:15px}.mt-20{margin-top:20px}.mt-25{margin-top:25px}.mt-30{margin-top:30px}.mt-35{margin-top:35px}.mt-40{margin-top:40px}.mt-45{margin-top:45px}.mt-50{margin-top:50px}.mt-60{margin-top:60px}.mt-70{margin-top:70px}.mt-80{margin-top:80px}.mt-90{margin-top:90px}body{letter-spacing:-.26px;line-height:19px}a:active,a:focus,a:hover,a:link,a:visited{text-decoration:none;color:#0041ff}::-moz-selection{background-color:rgba(0,64,255,.6);color:#fff}::selection{background-color:rgba(0,64,255,.6);color:#fff}textarea{resize:none}ul{margin:0;padding:0;list-style:none}h1{font-size:28px;margin-top:0}h1,h2{color:#3a3a3a}h2{font-size:24px}h3{font-size:20px}h3,h4{color:#3a3a3a}h4{font-size:16px}h5{font-size:12px;color:#3a3a3a}.hide{display:none!important}.row{display:-webkit-box;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;flex-direction:row;-webkit-box-pack:justify;justify-content:space-between;-webkit-box-align:center;align-items:center}.btn{box-shadow:0 1px 4px 0 rgba(0,0,0,.2),0 0 8px 0 rgba(0,0,0,.1);border-radius:3px;border:none;color:#fff;cursor:pointer;-webkit-transition:.2s cubic-bezier(.4,0,.2,1);transition:.2s cubic-bezier(.4,0,.2,1);font:inherit;display:inline-block}.btn:active,.btn:focus,.btn:hover{opacity:.75;border:none}.btn.btn-sm{padding:6px 12px}.btn.btn-md{padding:8px 16px}.btn.btn-lg{padding:10px 20px}.btn.btn-xl{padding:12px 24px;font-size:16px}.btn.btn-primary{background:#0041ff;color:#fff}.btn.btn-black{background:#000;color:#fff}.btn.btn-white{background:#fff;color:#000}.btn:disabled,.btn[disabled=disabled],.btn[disabled=disabled]:active,.btn[disabled=disabled]:hover{cursor:not-allowed;background:#b1b1ae;box-shadow:none;opacity:1}.dropdown-btn{min-width:150px;text-align:left;background:#fff;border:2px solid #c7c7c7;border-radius:3px;font-size:14px;padding:8px 35px 8px 10px;cursor:pointer;position:relative}.dropdown-btn:active,.dropdown-btn:focus,.dropdown-btn:hover{opacity:.75;border:2px solid #c7c7c7}.dropdown-btn .icon{position:absolute;right:10px;top:50%;margin-top:-4px}.dropdown-toggle{cursor:pointer}.dropdown-open{position:relative}.dropdown-list{width:200px;margin-bottom:20px;box-shadow:0 2px 4px 0 rgba(0,0,0,.16),0 0 9px 0 rgba(0,0,0,.16);border-radius:3px;background-color:#fff;position:absolute;display:none;z-index:10;text-align:left}.dropdown-list.bottom-left{top:42px;left:0}.dropdown-list.bottom-right{top:42px;right:0}.dropdown-list.top-left{bottom:0;left:42px}.dropdown-list.top-right{bottom:0;right:42px}.dropdown-list .search-box{padding:20px;border-bottom:1px solid #e8e8e8}.dropdown-list .search-box .control{background:#fff;border:2px solid #c7c7c7;border-radius:3px;width:100%;height:36px;display:inline-block;vertical-align:middle;-webkit-transition:.2s cubic-bezier(.4,0,.2,1);transition:.2s cubic-bezier(.4,0,.2,1);padding:0 10px;font-size:15px}.dropdown-list .search-box .control:focus{border-color:#0041ff}.dropdown-list .dropdown-container{padding:20px;overflow-y:auto}.dropdown-list .dropdown-container label{font-size:15px;display:inline-block;text-transform:uppercase;color:#9e9e9e;font-weight:700;padding-bottom:5px}.dropdown-list .dropdown-container ul{margin:0;list-style-type:none;padding:0}.dropdown-list .dropdown-container ul li{padding:5px 0}.dropdown-list .dropdown-container ul li a:active,.dropdown-list .dropdown-container ul li a:focus,.dropdown-list .dropdown-container ul li a:link,.dropdown-list .dropdown-container ul li a:visited{color:#333;display:block}.dropdown-list .dropdown-container ul li a:hover{color:#0041ff}.dropdown-list .dropdown-container ul li .checkbox{margin:0}.dropdown-list .dropdown-container ul li .control-group label{color:#3a3a3a;font-size:15px;font-weight:500;text-transform:capitalize;width:100%}.dropdown-list .dropdown-container .btn{width:100%;margin-top:10px}.section .secton-title{font-size:18px;color:#8e8e8e;padding:15px 0;border-bottom:1px solid #e8e8e8}.section .section-content{display:block;padding:20px 0}.section .section-content .row{display:block;padding:7px 0}.section .section-content .row .title{width:200px}.section .section-content .row .title,.section .section-content .row .value{color:#3a3a3a;letter-spacing:-.26px;display:inline-block}.table{width:100%}.table table{border-collapse:collapse;text-align:left;width:100%}.table table thead th{font-weight:700;padding:12px 10px;background:#f8f9fa;color:#3a3a3a}.table table tbody td{padding:10px;border-bottom:1px solid #d3d3d3;color:#3a3a3a;vertical-align:top}.table table tbody td.actions .action{display:-webkit-inline-box;display:inline-flex}.table table tbody td.actions .icon{cursor:pointer;vertical-align:middle}.table table tbody td.empty{text-align:center}.table table tbody tr:last-child td{border-bottom:none}.table .control-group{width:100%;margin-bottom:0;min-width:140px}.table .control-group .control{width:100%;margin:0}.pagination .page-item{background:#fff;border:2px solid #c7c7c7;border-radius:3px;padding:7px 14px;margin-right:5px;font-size:16px;display:inline-block;color:#8e8e8e;vertical-align:middle;text-decoration:none}.pagination .page-item.next,.pagination .page-item.previous{padding:6px 9px}.pagination .page-item.active{background:#0041ff;color:#fff;border-color:#0041ff}.pagination .page-item .icon{vertical-align:middle;margin-bottom:3px}.checkbox{position:relative;display:block}.checkbox input{left:0;opacity:0;position:absolute;top:0;height:24px;width:24px;z-index:100}.checkbox .checkbox-view{background-image:url(../images/Checkbox.svg);height:24px;width:24px;display:inline-block!important;vertical-align:middle;margin:0 5px 0 0}.checkbox input:checked+.checkbox-view{background-image:url(../images/Checkbox-Checked.svg)}.checkbox input:disabled+.checkbox-view{opacity:.5;cursor:not-allowed}.radio{position:relative;display:block;margin:10px 5px 5px 0}.radio input{left:0;opacity:0;position:absolute;top:0;z-index:100}.radio .radio-view{background-image:url(../images/controls.svg);background-position:-21px 0;height:20px;width:20px;display:inline-block!important;vertical-align:middle;margin:0 5px 0 0}.radio input:checked+.radio-view{background-position:-21px -21px}.radio input:disabled+.radio-view{opacity:.5;cursor:not-allowed}.control-group{display:block;margin-bottom:25px;font-size:15px;color:#333;width:750px;max-width:100%;position:relative}.control-group label{display:block;color:#3a3a3a}.control-group label.required:after{content:"*";color:#fc6868;font-weight:700;display:inline-block}.control-group textarea.control{height:100px;padding:10px}.control-group .control{background:#fff;border:2px solid #c7c7c7;border-radius:3px;width:70%;height:36px;display:inline-block;vertical-align:middle;-webkit-transition:.2s cubic-bezier(.4,0,.2,1);transition:.2s cubic-bezier(.4,0,.2,1);padding:0 10px;font-size:15px;margin-top:10px;margin-bottom:5px}.control-group .control:focus{border-color:#0041ff}.control-group .control[disabled=disabled]{border-color:#d3d3d3;background-color:#d3d3d3;cursor:not-allowed}.control-group .control[multiple]{height:100px}.control-group.date:after,.control-group.datetime:after{background-image:url(../images/Icon-Calendar.svg);width:24px;height:24px;content:"";display:inline-block;vertical-align:middle;margin-left:-34px;margin-top:2px;pointer-events:none}.control-group .control-info{display:block;font-size:14px;color:#6f6f6f;font-style:italic}.control-group .control-error{display:none;color:#ff5656;margin-top:5px}.control-group.has-error .control{border-color:#fc6868}.control-group.has-error .control-error{display:block}.control-group.price .currency-code{vertical-align:middle;display:inline-block}.control-group .switch{position:relative;display:inline-block;width:60px;height:34px;margin-top:10px;margin-bottom:5px}.control-group .switch input{opacity:0;width:0;height:0}.control-group .slider{cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#8e8e8e}.control-group .slider,.control-group .slider:before{position:absolute;-webkit-transition:.2s;transition:.2s}.control-group .slider:before{content:"";height:26px;width:26px;left:4px;bottom:4px;background-color:#fff}.control-group input:checked+.slider{background-color:#0041ff}.control-group input:focus+.slider{box-shadow:0 0 1px #0041ff}.control-group input:checked+.slider:before{-webkit-transform:translateX(26px);transform:translateX(26px)}.control-group .slider.round{border-radius:34px}.control-group .slider.round:before{border-radius:50%}.button-group{margin-top:20px;margin-bottom:20px}.alert-wrapper{width:300px;top:10px;right:10px;position:fixed;z-index:100;text-align:left}.alert-wrapper .alert{width:300px;padding:15px;border-radius:3px;display:inline-block;box-shadow:0 4px 15.36px .64px rgba(0,0,0,.1),0 2px 6px 0 rgba(0,0,0,.12);position:relative;-webkit-animation:jelly .5s ease-in-out;animation:jelly .5s ease-in-out;-webkit-transform-origin:center top;transform-origin:center top;z-index:500;margin-bottom:10px}.alert-wrapper .alert.alert-error{background:#fc6868}.alert-wrapper .alert.alert-info{background:#204d74}.alert-wrapper .alert.alert-success{background:#4caf50}.alert-wrapper .alert.alert-warning{background:#ffc107}.alert-wrapper .alert .icon{position:absolute;right:10px;top:10px;cursor:pointer}.alert-wrapper .alert p{color:#fff;margin:0;padding:0;font-size:15px}.tabs ul{border-bottom:1px solid #e8e8e8}.tabs ul li{display:inline-block}.tabs ul li a{padding:15px 20px;cursor:pointer;margin:0 2px;text-align:center;color:#000311;display:block}.tabs ul li.active a{border-bottom:3px solid #0041ff}.accordian,accordian{display:inline-block;width:100%}.accordian .accordian-header,.accordian div[slot*=header],accordian .accordian-header,accordian div[slot*=header]{width:100%;display:inline-block;font-size:18px;color:#3a3a3a;border-top:1px solid #e8e8e8;border-bottom:1px solid #e8e8e8;padding:20px 15px;cursor:pointer;margin-top:-1px}.accordian .accordian-header .expand-icon,.accordian div[slot*=header] .expand-icon,accordian .accordian-header .expand-icon,accordian div[slot*=header] .expand-icon{background-image:url(../images/Expand-Light.svg);margin-right:10px;margin-top:3px}.accordian .accordian-header h1,.accordian div[slot*=header] h1,accordian .accordian-header h1,accordian div[slot*=header] h1{margin:0;font-size:20px;font-weight:500;display:inline-block}.accordian .accordian-header .icon,.accordian div[slot*=header] .icon,accordian .accordian-header .icon,accordian div[slot*=header] .icon{float:right}.accordian .accordian-header .icon.left,.accordian div[slot*=header] .icon.left,accordian .accordian-header .icon.left,accordian div[slot*=header] .icon.left{float:left}.accordian.error .accordian-header,accordian.error .accordian-header{color:#ff5656}.accordian .accordian-content,.accordian div[slot*=body],accordian .accordian-content,accordian div[slot*=body]{width:100%;padding:20px 15px;display:none;-webkit-transition:all .3s ease;transition:all .3s ease}.accordian.active>.accordian-content,accordian.active>.accordian-content{display:inline-block}.accordian.active>.accordian-header .expand-icon,accordian.active>.accordian-header .expand-icon{background-image:url(../images/Expand-Light-On.svg)}.tree-container .tree-item{padding-left:30px;display:inline-block;margin-top:10px;width:100%}.tree-container .tree-item>.tree-item{display:none}.tree-container .tree-item.active>.tree-item{display:inline-block}.tree-container .tree-item .checkbox,.tree-container .tree-item .radio{margin:0;display:inline-block}.tree-container .tree-item .expand-icon{display:inline-block;margin-right:10px;cursor:pointer;background-image:url(../images/Expand-Light.svg);width:18px;height:18px;vertical-align:middle}.tree-container .tree-item .folder-icon{vertical-align:middle;margin-right:10px}.tree-container .tree-item.active>.expand-icon{background-image:url(../images/Expand-Light-On.svg)}.tree-container>.tree-item{padding-left:0}.panel{box-shadow:0 2px 25px 0 rgba(0,0,0,.15);border-radius:5px;background:#fff}.panel .panel-content{padding:20px}modal{display:none}.modal-open{overflow:hidden}.modal-overlay{display:none;overflow-y:auto;z-index:10;top:0;right:0;bottom:0;left:0;position:fixed;background:#000;opacity:.7}.modal-open .modal-overlay{display:block}.modal-container{background:#fff;top:100px;width:600px;max-width:80%;left:50%;margin-left:-300px;position:fixed;z-index:11;box-shadow:0 15px 25px 0 rgba(0,0,0,.03),0 20px 45px 5px rgba(0,0,0,.2);-webkit-animation:fade-in-white .3s ease-in-out;animation:fade-in-white .3s ease-in-out;-webkit-animation:jelly .5s ease-in-out;animation:jelly .5s ease-in-out;border-radius:5px;overflow-y:auto;max-height:80%}.modal-container .modal-header{padding:20px}.modal-container .modal-header h3{display:inline-block;font-size:20px;color:#3a3a3a;margin:0}.modal-container .modal-header .icon{float:right;cursor:pointer}.modal-container .modal-body{padding:20px}.modal-container .modal-body .control-group .control{width:100%}@media only screen and (max-width:770px){.modal-container{max-width:80%;left:10%;margin-left:0}}.label{background:#e7e7e7;border-radius:2px;padding:8px;color:#000311;display:inline-block}.label.label-sm{padding:5px}.label.label-md{padding:8px}.label.label-lg{padding:11px}.label.label-xl{padding:14px}.badge{border-radius:50px;color:#fff;padding:8px;white-space:nowrap}.badge.badge-sm{padding:5px}.badge.badge-md{padding:3px 10px}.badge.badge-lg{padding:11px}.badge.badge-xl{padding:14px}.badge.badge-success{background-color:#4caf50}.badge.badge-info{background-color:#0041ff}.badge.badge-danger{background-color:#fc6868}.badge.badge-warning{background-color:#ffc107}.image-wrapper{margin-bottom:20px;margin-top:10px;display:inline-block;width:100%}.image-wrapper .image-item{width:200px;height:200px;margin-right:20px;background:#f8f9fa;border-radius:3px;display:inline-block;position:relative;background-image:url(../images/placeholder-icon.svg);background-repeat:no-repeat;background-position:50%;margin-bottom:20px;float:left}.image-wrapper .image-item img.preview{width:100%;height:100%}.image-wrapper .image-item input{display:none}.image-wrapper .image-item .remove-image{background-image:-webkit-gradient(linear,left top,left bottom,from(rgba(0,0,0,.08)),to(rgba(0,0,0,.24)));background-image:linear-gradient(-180deg,rgba(0,0,0,.08),rgba(0,0,0,.24));border-radius:0 0 4px 4px;position:absolute;bottom:0;width:100%;padding:10px;text-align:center;color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.24);margin-right:20px;cursor:pointer}.image-wrapper .image-item:hover .remove-image{display:block}.image-wrapper .image-item.has-image{background-image:none}.vue-swatches__trigger{border:1px solid #d3d3d3}.helper-container{display:block}.helper-container .group code{font-weight:700} \ No newline at end of file diff --git a/packages/Webkul/Ui/publishable/assets/js/ui.js b/packages/Webkul/Ui/publishable/assets/js/ui.js index 651cff564..e39843ecf 100644 --- a/packages/Webkul/Ui/publishable/assets/js/ui.js +++ b/packages/Webkul/Ui/publishable/assets/js/ui.js @@ -1 +1 @@ -!function(t){var e={};function n(r){if(e[r])return e[r].exports;var i=e[r]={i:r,l:!1,exports:{}};return t[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:r})},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="/",n(n.s=0)}({"+CM9":function(t,e,n){"use strict";var r=n("Ds5P"),i=n("ot5s")(!1),o=[].indexOf,a=!!o&&1/[1].indexOf(1,-0)<0;r(r.P+r.F*(a||!n("NNrz")(o)),"Array",{indexOf:function(t){return a?o.apply(this,arguments)||0:i(this,t,arguments[1])}})},"+E39":function(t,e,n){t.exports=!n("S82l")(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},"+Mt+":function(t,e,n){"use strict";var r=n("Ds5P"),i=n("7gX0"),o=n("OzIq"),a=n("7O1s"),s=n("nphH");r(r.P+r.R,"Promise",{finally:function(t){var e=a(this,i.Promise||o.Promise),n="function"==typeof t;return this.then(n?function(n){return s(e,t()).then(function(){return n})}:t,n?function(n){return s(e,t()).then(function(){throw n})}:t)}})},"+ZMJ":function(t,e,n){var r=n("lOnJ");t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,i){return t.call(e,n,r,i)}}return function(){return t.apply(e,arguments)}}},"+vXH":function(t,e,n){n("77Ug")("Float64",8,function(t){return function(e,n,r){return t(this,e,n,r)}})},"+wdr":function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default={data:function(){return{sample:"",image_file:"",file:null,newImage:""}},mounted:function(){this.sample="";var t=this.$el.getElementsByTagName("input")[0],e=this;t.onchange=function(){var n=new FileReader;n.readAsDataURL(t.files[0]),n.onload=function(t){this.img=document.getElementsByTagName("input")[0],this.img.src=t.target.result,e.newImage=this.img.src,e.changePreview()}}},methods:{removePreviewImage:function(){this.sample=""},changePreview:function(){this.sample=this.newImage}},computed:{getInputImage:function(){console.log(this.imageData)}}}},"+yjc":function(t,e,n){var r=n("UKM+");n("3i66")("isSealed",function(t){return function(e){return!r(e)||!!t&&t(e)}})},"/whu":function(t,e){t.exports=function(t){if(void 0==t)throw TypeError("Can't call method on "+t);return t}},0:function(t,e,n){n("J66Q"),n("Oy72"),t.exports=n("MT9B")},"07k+":function(t,e,n){for(var r,i=n("OzIq"),o=n("2p1q"),a=n("ulTY"),s=a("typed_array"),c=a("view"),u=!(!i.ArrayBuffer||!i.DataView),l=u,f=0,p="Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array".split(",");f<9;)(r=i[p[f++]])?(o(r.prototype,s,!0),o(r.prototype,c,!0)):l=!1;t.exports={ABV:u,CONSTR:l,TYPED:s,VIEW:c}},"0Rih":function(t,e,n){"use strict";var r=n("OzIq"),i=n("Ds5P"),o=n("R3AP"),a=n("A16L"),s=n("1aA0"),c=n("vmSO"),u=n("9GpA"),l=n("UKM+"),f=n("zgIt"),p=n("qkyc"),d=n("yYvK"),h=n("kic5");t.exports=function(t,e,n,v,g,m){var y=r[t],b=y,w=g?"set":"add",x=b&&b.prototype,_={},k=function(t){var e=x[t];o(x,t,"delete"==t?function(t){return!(m&&!l(t))&&e.call(this,0===t?0:t)}:"has"==t?function(t){return!(m&&!l(t))&&e.call(this,0===t?0:t)}:"get"==t?function(t){return m&&!l(t)?void 0:e.call(this,0===t?0:t)}:"add"==t?function(t){return e.call(this,0===t?0:t),this}:function(t,n){return e.call(this,0===t?0:t,n),this})};if("function"==typeof b&&(m||x.forEach&&!f(function(){(new b).entries().next()}))){var S=new b,D=S[w](m?{}:-0,1)!=S,C=f(function(){S.has(1)}),O=p(function(t){new b(t)}),E=!m&&f(function(){for(var t=new b,e=5;e--;)t[w](e,e);return!t.has(-0)});O||((b=e(function(e,n){u(e,b,t);var r=h(new y,e,b);return void 0!=n&&c(n,g,r[w],r),r})).prototype=x,x.constructor=b),(C||E)&&(k("delete"),k("has"),g&&k("get")),(E||D)&&k(w),m&&x.clear&&delete x.clear}else b=v.getConstructor(e,t,g,w),a(b.prototype,n),s.NEED=!0;return d(b,t),_[t]=b,i(i.G+i.W+i.F*(b!=y),_),m||v.setStrong(b,t,g),b}},"0pGU":function(t,e,n){"use strict";var r=n("DIVP");t.exports=function(){var t=r(this),e="";return t.global&&(e+="g"),t.ignoreCase&&(e+="i"),t.multiline&&(e+="m"),t.unicode&&(e+="u"),t.sticky&&(e+="y"),e}},"11aO":function(t,e,n){var r=n("VU/8")(n("LxYr"),null,!1,null,null,null);t.exports=r.exports},"13ON":function(t,e){t.exports={render:function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",[n("div",{staticClass:"tabs"},[n("ul",t._l(t.tabs,function(e){return n("li",{class:{active:e.isActive},on:{click:function(n){return t.selectTab(e)}}},[n("a",[t._v(t._s(e.name))])])}),0)]),t._v(" "),n("div",{staticClass:"tabs-content"},[t._t("default")],2)])},staticRenderFns:[]}},"1A13":function(t,e,n){"use strict";var r=n("49qz")(!0);n("uc2A")(String,"String",function(t){this._t=String(t),this._i=0},function(){var t,e=this._t,n=this._i;return n>=e.length?{value:void 0,done:!0}:(t=r(e,n),this._i+=t.length,{value:t,done:!1})})},"1ETD":function(t,e,n){var r=n("kkCw")("match");t.exports=function(t){var e=/./;try{"/./"[t](e)}catch(n){try{return e[r]=!1,!"/./"[t](e)}catch(t){}}return!0}},"1aA0":function(t,e,n){var r=n("ulTY")("meta"),i=n("UKM+"),o=n("WBcL"),a=n("lDLk").f,s=0,c=Object.isExtensible||function(){return!0},u=!n("zgIt")(function(){return c(Object.preventExtensions({}))}),l=function(t){a(t,r,{value:{i:"O"+ ++s,w:{}}})},f=t.exports={KEY:r,NEED:!1,fastKey:function(t,e){if(!i(t))return"symbol"==typeof t?t:("string"==typeof t?"S":"P")+t;if(!o(t,r)){if(!c(t))return"F";if(!e)return"E";l(t)}return t[r].i},getWeak:function(t,e){if(!o(t,r)){if(!c(t))return!0;if(!e)return!1;l(t)}return t[r].w},onFreeze:function(t){return u&&f.NEED&&c(t)&&!o(t,r)&&l(t),t}}},"1ip3":function(t,e,n){var r=n("Ds5P");r(r.S,"Math",{log10:function(t){return Math.log(t)*Math.LOG10E}})},"1uLP":function(t,e,n){var r=n("Ds5P");r(r.G+r.W+r.F*!n("07k+").ABV,{DataView:n("LrcN").DataView})},"2JMG":function(t,e,n){var r=n("VU/8")(n("G3lE"),null,!1,null,null,null);t.exports=r.exports},"2VSL":function(t,e,n){var r=n("BbyF"),i=n("xAdt"),o=n("/whu");t.exports=function(t,e,n,a){var s=String(o(t)),c=s.length,u=void 0===n?" ":String(n),l=r(e);if(l<=c||""==u)return s;var f=l-c,p=i.call(u,Math.ceil(f/u.length));return p.length>f&&(p=p.slice(0,f)),a?p+s:s+p}},"2p1q":function(t,e,n){var r=n("lDLk"),i=n("fU25");t.exports=n("bUqO")?function(t,e,n){return r.f(t,e,i(1,n))}:function(t,e,n){return t[e]=n,t}},"31/P":function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};e.default={name:"tree-view",inheritAttrs:!1,props:{inputType:String,nameField:String,idField:String,captionField:String,childrenField:String,valueField:String,items:{type:[Array,String,Object],required:!1,default:null},value:{type:Array,required:!1,default:null},behavior:{type:String,required:!1,default:"reactive"},savedValues:{type:Array,required:!1,default:null}},created:function(){-1!==this.savedValues.indexOf(this.items[this.valueField])&&this.value.push(this.items)},computed:{caption:function(){return this.items[this.captionField]},allChildren:function(){var t=this,e=[];return function n(i){if(i[t.childrenField]&&t.getLength(i[t.childrenField])>0)if("object"==r(i[t.childrenField]))for(var o in i[t.childrenField])n(i[t.childrenField][o]);else i[t.childrenField].forEach(function(t){return n(t)});else e.push(i)}(this.items),e},hasChildren:function(){return!!this.items[this.childrenField]&&this.getLength(this.items[this.childrenField])>0},hasSelection:function(){return!!this.value&&this.value.length>0},isAllChildrenSelected:function(){var t=this;return this.hasChildren&&this.hasSelection&&this.allChildren.every(function(e){return t.value.some(function(n){return n[t.idField]===e[t.idField]})})},isSomeChildrenSelected:function(){var t=this;return this.hasChildren&&this.hasSelection&&this.allChildren.some(function(e){return t.value.some(function(n){return n[t.idField]===e[t.idField]})})}},methods:{getLength:function(t){if("object"==(void 0===t?"undefined":r(t))){var e=0;for(var n in t)e++;return e}return t.length},generateRoot:function(){var t=this;return"checkbox"==this.inputType?"reactive"==this.behavior?this.$createElement("tree-checkbox",{props:{id:this.items[this.idField],label:this.caption,nameField:this.nameField,modelValue:this.items[this.valueField],inputValue:this.hasChildren?this.isSomeChildrenSelected:this.value,value:this.hasChildren?this.isAllChildrenSelected:this.items},on:{change:function(e){t.hasChildren?(t.isAllChildrenSelected?t.allChildren.forEach(function(e){var n=t.value.indexOf(e);t.value.splice(n,1)}):t.allChildren.forEach(function(e){var n=!1;t.value.forEach(function(t){t.key==e.key&&(n=!0)}),n||t.value.push(e)}),t.$emit("input",t.value)):t.$emit("input",e)}}}):this.$createElement("tree-checkbox",{props:{id:this.items[this.idField],label:this.caption,nameField:this.nameField,modelValue:this.items[this.valueField],inputValue:this.value,value:this.items}}):"radio"==this.inputType?this.$createElement("tree-radio",{props:{id:this.items[this.idField],label:this.caption,nameField:this.nameField,modelValue:this.items[this.valueField],value:this.savedValues}}):void 0},generateChild:function(t){var e=this;return this.$createElement("tree-item",{on:{input:function(t){e.$emit("input",t)}},props:{items:t,value:this.value,savedValues:this.savedValues,nameField:this.nameField,inputType:this.inputType,captionField:this.captionField,childrenField:this.childrenField,valueField:this.valueField,idField:this.idField,behavior:this.behavior}})},generateChildren:function(){var t=this,e=[];if(this.items[this.childrenField])if("object"==r(this.items[this.childrenField]))for(var n in this.items[this.childrenField])e.push(this.generateChild(this.items[this.childrenField][n]));else this.items[this.childrenField].forEach(function(n){e.push(t.generateChild(n))});return e},generateIcon:function(){var t=this;return this.$createElement("i",{class:["expand-icon"],on:{click:function(e){t.$el.classList.toggle("active")}}})},generateFolderIcon:function(){return this.$createElement("i",{class:["icon","folder-icon"]})}},render:function(t){return t("div",{class:["tree-item","active",this.hasChildren?"has-children":""]},[this.generateIcon(),this.generateFolderIcon(),this.generateRoot()].concat(function(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e1&&s.call(r[0],n,function(){for(i=1;i=u?t?"":void 0:(o=s.charCodeAt(c))<55296||o>56319||c+1===u||(a=s.charCodeAt(c+1))<56320||a>57343?t?s.charAt(c):o:t?s.slice(c,c+2):a-56320+(o-55296<<10)+65536}}},"4IZP":function(t,e){t.exports=Object.is||function(t,e){return t===e?0!==t||1/t==1/e:t!=t&&e!=e}},"4Q0w":function(t,e,n){var r=n("kkCw")("toPrimitive"),i=Date.prototype;r in i||n("2p1q")(i,r,n("jB26"))},"4RlI":function(t,e,n){"use strict";n("y325")("blink",function(t){return function(){return t(this,"blink","","")}})},"4ZU1":function(t,e,n){var r=n("lDLk"),i=n("Ds5P"),o=n("DIVP"),a=n("s4j0");i(i.S+i.F*n("zgIt")(function(){Reflect.defineProperty(r.f({},1,{value:1}),1,{value:2})}),"Reflect",{defineProperty:function(t,e,n){o(t),e=a(e,!0),o(n);try{return r.f(t,e,n),!0}catch(t){return!1}}})},"52Wt":function(t,e,n){n("77Ug")("Int8",1,function(t){return function(e,n,r){return t(this,e,n,r)}})},"5iw+":function(t,e,n){"use strict";n("y325")("strike",function(t){return function(){return t(this,"strike","","")}})},"6wXy":function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default={props:{title:String,id:String,className:String,active:Boolean},inject:["$validator"],data:function(){return{isActive:!1,imageData:"",hasError:!1}},mounted:function(){var t=this;eventBus.$on("onFormError",function(){$(t.$el).find(".control-group").each(function(e,n){$(n).hasClass("has-error")&&(t.hasError=!0)})}),this.isActive=this.active},methods:{toggleAccordian:function(){this.isActive=!this.isActive}},computed:{iconClass:function(){return{"accordian-down-icon":!this.isActive,"accordian-up-icon":this.isActive}}}}},"73qY":function(t,e,n){t.exports=n("VWgF")("native-function-to-string",Function.toString)},"77Pl":function(t,e,n){var r=n("EqjI");t.exports=function(t){if(!r(t))throw TypeError(t+" is not an object!");return t}},"77Ug":function(t,e,n){"use strict";if(n("bUqO")){var r=n("V3l/"),i=n("OzIq"),o=n("zgIt"),a=n("Ds5P"),s=n("07k+"),c=n("LrcN"),u=n("rFzY"),l=n("9GpA"),f=n("fU25"),p=n("2p1q"),d=n("A16L"),h=n("oeih"),v=n("BbyF"),g=n("8D8H"),m=n("zo/l"),y=n("s4j0"),b=n("WBcL"),w=n("wC1N"),x=n("UKM+"),_=n("FryR"),k=n("9vb1"),S=n("7ylX"),D=n("KOrd"),C=n("WcO1").f,O=n("SHe9"),E=n("ulTY"),M=n("kkCw"),P=n("LhTa"),F=n("ot5s"),I=n("7O1s"),T=n("WgSQ"),A=n("bN1p"),L=n("qkyc"),j=n("CEne"),N=n("zCYm"),R=n("DPsE"),V=n("lDLk"),z=n("x9zv"),U=V.f,B=z.f,q=i.RangeError,Y=i.TypeError,W=i.Uint8Array,H=Array.prototype,$=c.ArrayBuffer,G=c.DataView,K=P(0),X=P(2),J=P(3),Z=P(4),Q=P(5),tt=P(6),et=F(!0),nt=F(!1),rt=T.values,it=T.keys,ot=T.entries,at=H.lastIndexOf,st=H.reduce,ct=H.reduceRight,ut=H.join,lt=H.sort,ft=H.slice,pt=H.toString,dt=H.toLocaleString,ht=M("iterator"),vt=M("toStringTag"),gt=E("typed_constructor"),mt=E("def_constructor"),yt=s.CONSTR,bt=s.TYPED,wt=s.VIEW,xt=P(1,function(t,e){return Ct(I(t,t[mt]),e)}),_t=o(function(){return 1===new W(new Uint16Array([1]).buffer)[0]}),kt=!!W&&!!W.prototype.set&&o(function(){new W(1).set({})}),St=function(t,e){var n=h(t);if(n<0||n%e)throw q("Wrong offset!");return n},Dt=function(t){if(x(t)&&bt in t)return t;throw Y(t+" is not a typed array!")},Ct=function(t,e){if(!(x(t)&> in t))throw Y("It is not a typed array constructor!");return new t(e)},Ot=function(t,e){return Et(I(t,t[mt]),e)},Et=function(t,e){for(var n=0,r=e.length,i=Ct(t,r);r>n;)i[n]=e[n++];return i},Mt=function(t,e,n){U(t,e,{get:function(){return this._d[n]}})},Pt=function(t){var e,n,r,i,o,a,s=_(t),c=arguments.length,l=c>1?arguments[1]:void 0,f=void 0!==l,p=O(s);if(void 0!=p&&!k(p)){for(a=p.call(s),r=[],e=0;!(o=a.next()).done;e++)r.push(o.value);s=r}for(f&&c>2&&(l=u(l,arguments[2],2)),e=0,n=v(s.length),i=Ct(this,n);n>e;e++)i[e]=f?l(s[e],e):s[e];return i},Ft=function(){for(var t=0,e=arguments.length,n=Ct(this,e);e>t;)n[t]=arguments[t++];return n},It=!!W&&o(function(){dt.call(new W(1))}),Tt=function(){return dt.apply(It?ft.call(Dt(this)):Dt(this),arguments)},At={copyWithin:function(t,e){return R.call(Dt(this),t,e,arguments.length>2?arguments[2]:void 0)},every:function(t){return Z(Dt(this),t,arguments.length>1?arguments[1]:void 0)},fill:function(t){return N.apply(Dt(this),arguments)},filter:function(t){return Ot(this,X(Dt(this),t,arguments.length>1?arguments[1]:void 0))},find:function(t){return Q(Dt(this),t,arguments.length>1?arguments[1]:void 0)},findIndex:function(t){return tt(Dt(this),t,arguments.length>1?arguments[1]:void 0)},forEach:function(t){K(Dt(this),t,arguments.length>1?arguments[1]:void 0)},indexOf:function(t){return nt(Dt(this),t,arguments.length>1?arguments[1]:void 0)},includes:function(t){return et(Dt(this),t,arguments.length>1?arguments[1]:void 0)},join:function(t){return ut.apply(Dt(this),arguments)},lastIndexOf:function(t){return at.apply(Dt(this),arguments)},map:function(t){return xt(Dt(this),t,arguments.length>1?arguments[1]:void 0)},reduce:function(t){return st.apply(Dt(this),arguments)},reduceRight:function(t){return ct.apply(Dt(this),arguments)},reverse:function(){for(var t,e=Dt(this).length,n=Math.floor(e/2),r=0;r1?arguments[1]:void 0)},sort:function(t){return lt.call(Dt(this),t)},subarray:function(t,e){var n=Dt(this),r=n.length,i=m(t,r);return new(I(n,n[mt]))(n.buffer,n.byteOffset+i*n.BYTES_PER_ELEMENT,v((void 0===e?r:m(e,r))-i))}},Lt=function(t,e){return Ot(this,ft.call(Dt(this),t,e))},jt=function(t){Dt(this);var e=St(arguments[1],1),n=this.length,r=_(t),i=v(r.length),o=0;if(i+e>n)throw q("Wrong length!");for(;o255?255:255&r),i.v[d](n*e+i.o,r,_t)}(this,n,t)},enumerable:!0})};b?(h=n(function(t,n,r,i){l(t,h,u,"_d");var o,a,s,c,f=0,d=0;if(x(n)){if(!(n instanceof $||"ArrayBuffer"==(c=w(n))||"SharedArrayBuffer"==c))return bt in n?Et(h,n):Pt.call(h,n);o=n,d=St(r,e);var m=n.byteLength;if(void 0===i){if(m%e)throw q("Wrong length!");if((a=m-d)<0)throw q("Wrong length!")}else if((a=v(i)*e)+d>m)throw q("Wrong length!");s=a/e}else s=g(n),o=new $(a=s*e);for(p(t,"_d",{b:o,o:d,l:a,e:s,v:new G(o)});f0),"Math",{asinh:function t(e){return isFinite(e=+e)&&0!=e?e<0?-t(-e):Math.log(e+Math.sqrt(e*e+1)):e}})},"7KvD":function(t,e){var n=t.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},"7O1s":function(t,e,n){var r=n("DIVP"),i=n("XSOZ"),o=n("kkCw")("species");t.exports=function(t,e){var n,a=r(t).constructor;return void 0===a||void 0==(n=r(a)[o])?e:i(n)}},"7aQn":function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.default={name:"tree-view",inheritAttrs:!1,props:{inputType:{type:String,required:!1,default:"checkbox"},nameField:{type:String,required:!1,default:"permissions"},idField:{type:String,required:!1,default:"id"},valueField:{type:String,required:!1,default:"value"},captionField:{type:String,required:!1,default:"name"},childrenField:{type:String,required:!1,default:"children"},items:{type:[Array,String,Object],required:!1,default:function(){return[]}},behavior:{type:String,required:!1,default:"reactive"},value:{type:[Array,String,Object],required:!1,default:function(){return[]}}},data:function(){return{finalValues:[]}},computed:{savedValues:function(){return this.value?"radio"==this.inputType?[this.value]:"string"==typeof this.value?JSON.parse(this.value):this.value:[]}},methods:{generateChildren:function(){var t=[],e="string"==typeof this.items?JSON.parse(this.items):this.items;for(var n in e)t.push(this.generateTreeItem(e[n]));return t},generateTreeItem:function(t){var e=this;return this.$createElement("tree-item",{props:{items:t,value:this.finalValues,savedValues:this.savedValues,nameField:this.nameField,inputType:this.inputType,captionField:this.captionField,childrenField:this.childrenField,valueField:this.valueField,idField:this.idField,behavior:this.behavior},on:{input:function(t){e.finalValues=t}}})}},render:function(t){return t("div",{class:["tree-container"]},[this.generateChildren()])}}},"7gX0":function(t,e){var n=t.exports={version:"2.6.9"};"number"==typeof __e&&(__e=n)},"7ylX":function(t,e,n){var r=n("DIVP"),i=n("twxM"),o=n("QKXm"),a=n("mZON")("IE_PROTO"),s=function(){},c=function(){var t,e=n("jhxf")("iframe"),r=o.length;for(e.style.display="none",n("d075").appendChild(e),e.src="javascript:",(t=e.contentWindow.document).open(),t.write(" - - - @endpush -@stop \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/views/promotions/cart-rule/edit.blade.php b/packages/Webkul/Admin/src/Resources/views/promotions/cart-rule/edit.blade.php deleted file mode 100644 index 27312c327..000000000 --- a/packages/Webkul/Admin/src/Resources/views/promotions/cart-rule/edit.blade.php +++ /dev/null @@ -1,740 +0,0 @@ -@extends('admin::layouts.content') - -@section('page_title') - {{ __('admin::app.promotion.edit-cart-rule') }} -@stop - -@section('content') - -
- -
- - @push('scripts') - - - - @endpush -@stop \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/create.blade.php b/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/create.blade.php new file mode 100644 index 000000000..c687601ac --- /dev/null +++ b/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/create.blade.php @@ -0,0 +1,612 @@ +@extends('admin::layouts.content') + +@section('page_title') + {{ __('admin::app.promotions.cart-rules.add-title') }} +@stop + +@section('content') +
+ + + +
+@stop + +@push('scripts') + @parent + + + + + + +@endpush \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/edit.blade.php b/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/edit.blade.php new file mode 100644 index 000000000..4af87ddf2 --- /dev/null +++ b/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/edit.blade.php @@ -0,0 +1,751 @@ +@extends('admin::layouts.content') + +@section('page_title') + {{ __('admin::app.promotions.cart-rules.edit-title') }} +@stop + +@section('content') +
+ + + +
+@stop + +@push('scripts') + @parent + + + + + + + + +@endpush \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/views/promotions/cart-rule/index.blade.php b/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/index.blade.php similarity index 60% rename from packages/Webkul/Admin/src/Resources/views/promotions/cart-rule/index.blade.php rename to packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/index.blade.php index cf172412a..d07bbfaef 100644 --- a/packages/Webkul/Admin/src/Resources/views/promotions/cart-rule/index.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/index.blade.php @@ -1,7 +1,7 @@ @extends('admin::layouts.content') @section('page_title') - {{ __('admin::app.promotion.cart-rule') }} + {{ __('admin::app.promotions.cart-rules.title') }} @stop @section('content') @@ -9,12 +9,12 @@
diff --git a/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rule/create.blade.php b/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rule/create.blade.php deleted file mode 100644 index ca386c453..000000000 --- a/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rule/create.blade.php +++ /dev/null @@ -1,415 +0,0 @@ -@extends('admin::layouts.content') - -@section('page_title') - {{ __('admin::app.promotion.add-catalog-rule') }} -@stop - -@section('content') -
- -
- - @push('scripts') - - - - @endpush -@stop \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rule/edit.blade.php b/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rule/edit.blade.php deleted file mode 100644 index f7b68da7b..000000000 --- a/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rule/edit.blade.php +++ /dev/null @@ -1,414 +0,0 @@ -@extends('admin::layouts.content') - -@section('page_title') - {{ __('admin::app.promotion.edit-catalog-rule') }} -@stop - -@section('content') -
- -
- - @push('scripts') - - - - @endpush -@stop \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rule/index.blade.php b/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rule/index.blade.php deleted file mode 100644 index 6790810ea..000000000 --- a/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rule/index.blade.php +++ /dev/null @@ -1,35 +0,0 @@ -@extends('admin::layouts.content') - -@section('page_title') - {{ __('admin::app.promotion.catalog-rule') }} -@stop - -@section('content') - -
- - -
- @inject('catalogRuleGrid','Webkul\Admin\DataGrids\CatalogRuleDataGrid') - {!! $catalogRuleGrid->render() !!} -
-
-@endsection \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rules/create.blade.php b/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rules/create.blade.php new file mode 100644 index 000000000..30745564b --- /dev/null +++ b/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rules/create.blade.php @@ -0,0 +1,528 @@ +@extends('admin::layouts.content') + +@section('page_title') + {{ __('admin::app.promotions.catalog-rules.add-title') }} +@stop + +@section('content') +
+ + + +
+@stop + +@push('scripts') + @parent + + + + + + +@endpush \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rules/edit.blade.php b/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rules/edit.blade.php new file mode 100644 index 000000000..d1a6aed4a --- /dev/null +++ b/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rules/edit.blade.php @@ -0,0 +1,533 @@ +@extends('admin::layouts.content') + +@section('page_title') + {{ __('admin::app.promotions.catalog-rules.edit-title') }} +@stop + +@section('content') +
+ + + +
+@stop + +@push('scripts') + @parent + + + + + + +@endpush \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rules/index.blade.php b/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rules/index.blade.php new file mode 100644 index 000000000..0139be19f --- /dev/null +++ b/packages/Webkul/Admin/src/Resources/views/promotions/catalog-rules/index.blade.php @@ -0,0 +1,27 @@ +@extends('admin::layouts.content') + +@section('page_title') + {{ __('admin::app.promotions.catalog-rules.title') }} +@stop + +@section('content') + +
+ + +
+ @inject('catalogRuleGrid','Webkul\Admin\DataGrids\CatalogRuleDataGrid') + {!! $catalogRuleGrid->render() !!} +
+
+@endsection \ No newline at end of file diff --git a/packages/Webkul/CartRule/src/Contracts/CartRule.php b/packages/Webkul/CartRule/src/Contracts/CartRule.php new file mode 100644 index 000000000..bbc60e2e2 --- /dev/null +++ b/packages/Webkul/CartRule/src/Contracts/CartRule.php @@ -0,0 +1,7 @@ +increments('id'); $table->string('name')->nullable(); $table->string('description')->nullable(); - $table->datetime('starts_from')->nullable(); - $table->datetime('ends_till')->nullable(); + $table->date('starts_from')->nullable(); + $table->date('ends_till')->nullable(); $table->boolean('status')->default(0); - $table->integer('per_customer')->unsigned()->default(0); - $table->boolean('is_guest')->default(0); - $table->boolean('use_coupon')->default(0); - $table->integer('usage_limit')->unsigned()->default(0); - $table->json('conditions')->nullable(); - $table->json('actions')->nullable(); - $table->boolean('end_other_rules')->default(0); - $table->integer('priority')->unsigned()->default(0); - $table->boolean('uses_attribute_conditions')->default(0); - $table->longtext('product_ids')->nullable(); - $table->integer('sort_order')->unsigned()->default(0); - $table->string('action_type')->nullable(); - $table->decimal('disc_amount', 12, 4)->default(0); - $table->decimal('disc_quantity', 12, 4)->default(1); - $table->string('disc_threshold')->default(1); $table->integer('coupon_type')->default(1); - $table->boolean('auto_generation')->default(0); + $table->boolean('use_auto_generation')->default(0); + $table->integer('usage_per_customer')->default(0); + $table->integer('uses_per_coupon')->default(0); + $table->integer('times_used')->unsigned()->default(0); + $table->boolean('condition_type')->default(1); + $table->json('conditions')->nullable(); + $table->boolean('end_other_rules')->default(0); + $table->boolean('uses_attribute_conditions')->default(0); + $table->string('action_type')->nullable(); + $table->decimal('discount_amount', 12, 4)->default(0); + $table->integer('discount_quantity')->default(1); + $table->string('discount_step')->default(1); $table->boolean('apply_to_shipping')->default(0); $table->boolean('free_shipping')->default(0); + $table->integer('sort_order')->unsigned()->default(0); $table->timestamps(); }); } diff --git a/packages/Webkul/Discount/src/Database/Migrations/2019_05_13_024340_create_cart_rule_channels_table.php b/packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024322_create_cart_rule_channels_table.php similarity index 91% rename from packages/Webkul/Discount/src/Database/Migrations/2019_05_13_024340_create_cart_rule_channels_table.php rename to packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024322_create_cart_rule_channels_table.php index 3808c6545..067a452fa 100644 --- a/packages/Webkul/Discount/src/Database/Migrations/2019_05_13_024340_create_cart_rule_channels_table.php +++ b/packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024322_create_cart_rule_channels_table.php @@ -14,12 +14,13 @@ class CreateCartRuleChannelsTable extends Migration public function up() { Schema::create('cart_rule_channels', function (Blueprint $table) { - $table->increments('id'); $table->integer('cart_rule_id')->unsigned(); - $table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade'); $table->integer('channel_id')->unsigned(); + + $table->primary(['cart_rule_id', 'channel_id']); + + $table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade'); $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); - $table->timestamps(); }); } diff --git a/packages/Webkul/Discount/src/Database/Migrations/2019_05_13_024419_create_cart_rule_customer_groups_table.php b/packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024323_create_cart_rule_customer_groups_table.php similarity index 90% rename from packages/Webkul/Discount/src/Database/Migrations/2019_05_13_024419_create_cart_rule_customer_groups_table.php rename to packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024323_create_cart_rule_customer_groups_table.php index 4396b999a..312237d98 100644 --- a/packages/Webkul/Discount/src/Database/Migrations/2019_05_13_024419_create_cart_rule_customer_groups_table.php +++ b/packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024323_create_cart_rule_customer_groups_table.php @@ -14,12 +14,14 @@ class CreateCartRuleCustomerGroupsTable extends Migration public function up() { Schema::create('cart_rule_customer_groups', function (Blueprint $table) { - $table->increments('id'); $table->integer('cart_rule_id')->unsigned(); - $table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade'); $table->integer('customer_group_id')->unsigned(); + + + $table->primary(['cart_rule_id', 'customer_group_id']); + + $table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade'); $table->foreign('customer_group_id')->references('id')->on('customer_groups')->onDelete('cascade'); - $table->timestamps(); }); } diff --git a/packages/Webkul/Discount/src/Database/Migrations/2019_05_30_141207_create_cart_rule_cart_table.php b/packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024324_create_cart_rule_translations_table.php similarity index 54% rename from packages/Webkul/Discount/src/Database/Migrations/2019_05_30_141207_create_cart_rule_cart_table.php rename to packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024324_create_cart_rule_translations_table.php index 82c7505a0..9c71333d7 100644 --- a/packages/Webkul/Discount/src/Database/Migrations/2019_05_30_141207_create_cart_rule_cart_table.php +++ b/packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024324_create_cart_rule_translations_table.php @@ -4,7 +4,7 @@ use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; -class CreateCartRuleCartTable extends Migration +class CreateCartRuleTranslationsTable extends Migration { /** * Run the migrations. @@ -13,13 +13,13 @@ class CreateCartRuleCartTable extends Migration */ public function up() { - Schema::create('cart_rule_cart', function (Blueprint $table) { + Schema::create('cart_rule_translations', function (Blueprint $table) { $table->increments('id'); - $table->integer('cart_rule_id')->unsigned()->nullable(); + $table->string('locale'); + $table->text('label')->nullable(); + $table->integer('cart_rule_id')->unsigned(); + $table->unique(['cart_rule_id', 'locale']); $table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade'); - $table->integer('cart_id')->unsigned()->nullable(); - $table->foreign('cart_id')->references('id')->on('cart')->onDelete('cascade'); - $table->timestamps(); }); } @@ -30,6 +30,6 @@ class CreateCartRuleCartTable extends Migration */ public function down() { - Schema::dropIfExists('cart_rule_cart'); + Schema::dropIfExists('cart_rule_translations'); } } diff --git a/packages/Webkul/Discount/src/Database/Migrations/2019_05_23_175727_create_cart_rule_customers_table.php b/packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024325_create_cart_rule_customers_table.php similarity index 84% rename from packages/Webkul/Discount/src/Database/Migrations/2019_05_23_175727_create_cart_rule_customers_table.php rename to packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024325_create_cart_rule_customers_table.php index fbe323ab1..a16452c6f 100644 --- a/packages/Webkul/Discount/src/Database/Migrations/2019_05_23_175727_create_cart_rule_customers_table.php +++ b/packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024325_create_cart_rule_customers_table.php @@ -15,12 +15,13 @@ class CreateCartruleCustomersTable extends Migration { Schema::create('cart_rule_customers', function (Blueprint $table) { $table->increments('id'); + $table->bigInteger('times_used')->unsigned()->default(0); + $table->integer('cart_rule_id')->unsigned(); $table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade'); + $table->integer('customer_id')->unsigned(); $table->foreign('customer_id')->references('id')->on('customers')->onDelete('cascade'); - $table->bigInteger('usage_throttle')->unsigned()->default(0); - $table->timestamps(); }); } @@ -31,6 +32,6 @@ class CreateCartruleCustomersTable extends Migration */ public function down() { - Schema::dropIfExists('cart_rule_customers'); + Schema::dropIfExists('cartrule_customers'); } } diff --git a/packages/Webkul/Discount/src/Database/Migrations/2019_05_23_180457_create_cart_rule_coupons_table.php b/packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024326_create_cart_rule_coupons_table.php similarity index 80% rename from packages/Webkul/Discount/src/Database/Migrations/2019_05_23_180457_create_cart_rule_coupons_table.php rename to packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024326_create_cart_rule_coupons_table.php index 67eea0030..89741800e 100644 --- a/packages/Webkul/Discount/src/Database/Migrations/2019_05_23_180457_create_cart_rule_coupons_table.php +++ b/packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024326_create_cart_rule_coupons_table.php @@ -15,15 +15,16 @@ class CreateCartruleCouponsTable extends Migration { Schema::create('cart_rule_coupons', function (Blueprint $table) { $table->increments('id'); - $table->integer('cart_rule_id')->unsigned(); - $table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade'); - $table->string('prefix')->nullable(); - $table->string('suffix')->nullable(); $table->string('code')->nullable(); $table->integer('usage_limit')->unsigned()->default(0); $table->integer('usage_per_customer')->unsigned()->default(0); - $table->integer('usage_throttle')->unsigned()->default(0); + $table->integer('times_used')->unsigned()->default(0); $table->integer('type')->unsigned()->default(0); + $table->boolean('is_primary')->default(0); + $table->date('expired_at')->nullable(); + + $table->integer('cart_rule_id')->unsigned(); + $table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade'); $table->timestamps(); }); } @@ -35,6 +36,6 @@ class CreateCartruleCouponsTable extends Migration */ public function down() { - Schema::dropIfExists('cart_rule_coupons'); + Schema::dropIfExists('cartrule_coupons'); } } diff --git a/packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024327_create_cart_rule_coupon_usage_table.php b/packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024327_create_cart_rule_coupon_usage_table.php new file mode 100644 index 000000000..ae0339b0a --- /dev/null +++ b/packages/Webkul/CartRule/src/Database/Migrations/2019_05_13_024327_create_cart_rule_coupon_usage_table.php @@ -0,0 +1,37 @@ +increments('id'); + $table->integer('times_used')->default(0); + + $table->integer('cart_rule_coupon_id')->unsigned(); + $table->foreign('cart_rule_coupon_id')->references('id')->on('cart_rule_coupons')->onDelete('cascade'); + + $table->integer('customer_id')->unsigned(); + $table->foreign('customer_id')->references('id')->on('customers')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('cart_rule_coupon_usage'); + } +} diff --git a/packages/Webkul/CartRule/src/Helpers/CartRule.php b/packages/Webkul/CartRule/src/Helpers/CartRule.php new file mode 100644 index 000000000..faef6fa22 --- /dev/null +++ b/packages/Webkul/CartRule/src/Helpers/CartRule.php @@ -0,0 +1,494 @@ +cartRuleRepository = $cartRuleRepository; + + $this->cartRuleCouponRepository = $cartRuleCouponRepository; + + $this->cartRuleCouponUsageRepository = $cartRuleCouponUsageRepository; + + $this->cartRuleCustomerRepository = $cartRuleCustomerRepository; + + $this->customerGroupRepository = $customerGroupRepository; + + $this->validator = $validator; + } + + /** + * Collect discount on cart + * + * @return void + */ + public function collect() + { + $cart = Cart::getCart(); + + $this->calculateCartItemTotals($cart->items()->get()); + + foreach ($cart->items()->get() as $item) { + $this->process($item); + } + + $this->processShippingDiscount($cart); + + $this->processFreeShippingDiscount($cart); + + $this->validateCouponCode(); + } + + /** + * Returns cart rules + * + * @return Collection + */ + public function getCartRules() + { + static $cartRules; + + if ($cartRules) + return $cartRules; + + $customerGroupId = null; + + if (Cart::getCurrentCustomer()->check()) { + $customerGroupId = Cart::getCurrentCustomer()->user()->customer_group_id; + } else { + if ($customerGuestGroup = $this->customerGroupRepository->findOneByField('code', 'guest')) + $customerGroupId = $customerGuestGroup->id; + } + + $cartRules = $this->cartRuleRepository->scopeQuery(function($query) use ($customerGroupId) { + return $query->leftJoin('cart_rule_customer_groups', 'cart_rules.id', '=', 'cart_rule_customer_groups.cart_rule_id') + ->leftJoin('cart_rule_channels', 'cart_rules.id', '=', 'cart_rule_channels.cart_rule_id') + ->where('cart_rule_customer_groups.customer_group_id', $customerGroupId) + ->where('cart_rule_channels.channel_id', core()->getCurrentChannel()->id) + ->where(function ($query1) { + $query1->where('cart_rules.starts_from', '<=', Carbon::now()->format('Y-m-d'))->orWhereNull('cart_rules.starts_from'); + }) + ->where(function ($query2) { + $query2->where('cart_rules.ends_till', '>=', Carbon::now()->format('Y-m-d'))->orWhereNull('cart_rules.ends_till'); + }) + ->orderBy('sort_order', 'asc'); + })->findWhere(['status' => 1]); + + return $cartRules; + } + + /** + * Check if cart rule can be applied + * + * @param CartRule $rule + * @return boolean + */ + public function canProcessRule($rule) + { + $cart = Cart::getCart(); + + if ($rule->coupon_type) { + if (strlen($cart->coupon_code)) { + $coupon = $this->cartRuleCouponRepository->findOneWhere([ + 'cart_rule_id' => $rule->id, + 'code' => $cart->coupon_code, + ]); + + if ($coupon) { + if ($coupon->usage_limit && $coupon->times_used >= $coupon->usage_limit) + return false; + + if ($cart->customer_id && $coupon->usage_per_customer) { + $couponUsage = $this->cartRuleCouponUsageRepository->findOneWhere([ + 'cart_rule_coupon_id' => $coupon->id, + 'customer_id' => $cart->customer_id + ]); + + if ($couponUsage && $couponUsage->times_used >= $coupon->usage_per_customer) + return false; + } + } else { + return false; + } + } else { + return false; + } + } + + if ($rule->usage_per_customer) { + $ruleCustomer = $this->cartRuleCustomerRepository->findOneWhere([ + 'cart_rule_id' => $rule->id, + 'customer_id' => $cart->customer_id, + ]); + + if ($ruleCustomer && $ruleCustomer->times_used >= $rule->usage_per_customer) + return false; + } + + return true; + } + + /** + * Cart item discount calculation process + * + * @param CartItem $item + * @return void + */ + public function process($item) + { + $item->discount_percent = 0; + $item->discount_amount = 0; + $item->base_discount_amount = 0; + + $cart = $item->cart; + + $cart->applied_cart_rule_ids = null; + + $appliedRuleIds = []; + + foreach ($this->getCartRules() as $rule) { + if (! $this->canProcessRule($rule)) + continue; + + if (! $this->validator->validate($rule, $item)) + continue; + + $quantity = $rule->discount_quantity ? min($item->quantity, $rule->discount_quantity) : $item->quantity; + + switch ($rule->action_type) { + case 'by_percent': + $rulePercent = min(100, $rule->discount_amount); + + $discountAmount = ($quantity * $item->price - $item->discount_amount) * ($rulePercent / 100); + + $baseDiscountAmount = ($quantity * $item->base_price - $item->base_discount_amount) * ($rulePercent / 100); + + if (! $rule->discount_quantity || $rule->discount_quantity > $quantity) { + $discountPercent = min(100, $item->discount_percent + $rulePercent); + + $item->discount_percent = $discountPercent; + } + + break; + + case 'by_fixed': + $discountAmount = $quantity * core()->convertPrice($rule->discount_amount); + + $baseDiscountAmount = $quantity * $rule->discount_amount; + + break; + + case 'cart_fixed': + if ($this->itemTotals[$rule->id]['total_items'] <= 1) { + $discountAmount = core()->convertPrice($rule->discount_amount); + + $baseDiscountAmount = min($item->base_price * $quantity, $rule->discount_amount); + } else { + $discountRate = $item->base_price * $quantity / $this->itemTotals[$rule->id]['base_total_price']; + + $maxDiscount = $rule->discount_amount * $discountRate; + + $discountAmount = core()->convertPrice($maxDiscount); + + $baseDiscountAmount = min($item->base_price * $quantity, $maxDiscount); + } + + $discountAmount = min($item->price * $quantity, $discountAmount); + + break; + + case 'buy_x_get_y': + if (! $rule->discount_step || $rule->discount_amount > $rule->discount_step) + break; + + $buyAndDiscountQty = $rule->discount_step + $rule->discount_amount; + + $qtyPeriod = floor($quantity / $buyAndDiscountQty); + + $freeQty = $quantity - $qtyPeriod * $buyAndDiscountQty; + + $discountQty = $qtyPeriod * $rule->discount_amount; + + if ($freeQty > $rule->discount_step) + $discountQty += $freeQty - $rule->discount_step; + + $discountAmount = $discountQty * $item->price; + + $baseDiscountAmount = $discountQty * $item->base_price; + + break; + } + + $item->discount_amount = min($item->discount_amount + $discountAmount, $item->price * $quantity); + $item->base_discount_amount = min($item->base_discount_amount + $baseDiscountAmount, $item->base_price * $quantity); + + $appliedRuleIds[$rule->id] = $rule->id; + + if ($rule->end_other_rules) + break; + } + + $item->applied_cart_rule_ids = join(',', $appliedRuleIds); + + $item->save(); + + $cartAppliedCartRuleIds = array_merge(explode(',', $cart->applied_cart_rule_ids), $appliedRuleIds); + + $cartAppliedCartRuleIds = array_filter($cartAppliedCartRuleIds); + + $cartAppliedCartRuleIds = array_unique($cartAppliedCartRuleIds); + + $cart->applied_cart_rule_ids = join(',', $cartAppliedCartRuleIds); + + $cart->save(); + } + + /** + * Cart shipping discount calculation process + * + * @param Cart $cart + * @return void + */ + public function processShippingDiscount($cart) + { + if (! $selectedShipping = $cart->selected_shipping_rate) + return; + + $selectedShipping->discount_amount = 0; + $selectedShipping->base_discount_amount = 0; + + $appliedRuleIds = []; + + foreach ($this->getCartRules() as $rule) { + if (! $this->canProcessRule($rule)) + continue; + + if (! $this->validator->validate($rule, $cart)) + continue; + + if (! $rule || ! $rule->apply_to_shipping) + continue; + + $discountAmount = $baseDiscountAmount = 0; + + switch ($rule->action_type) { + case 'by_percent': + $rulePercent = min(100, $rule->discount_amount); + + $discountAmount = ($selectedShipping->price - $selectedShipping->discount_amount) * $rulePercent / 100; + + $baseDiscountAmount = ($selectedShipping->base_price - $selectedShipping->base_discount_amount) * $rulePercent / 100; + + break; + + case 'by_fixed': + $discountAmount = core()->convertPrice($rule->discount_amount); + + $baseDiscountAmount = $rule->discount_amount; + + break; + } + + $selectedShipping->discount_amount = min($selectedShipping->discount_amount + $discountAmount, $selectedShipping->price); + + $selectedShipping->base_discount_amount = min( + $selectedShipping->base_discount_amount + $baseDiscountAmount, + $selectedShipping->base_price + ); + + $selectedShipping->save(); + + $appliedRuleIds[$rule->id] = $rule->id; + + if ($rule->end_other_rules) + break; + } + + $cartAppliedCartRuleIds = array_merge(explode(',', $cart->applied_cart_rule_ids), $appliedRuleIds); + + $cartAppliedCartRuleIds = array_filter($cartAppliedCartRuleIds); + + $cartAppliedCartRuleIds = array_unique($cartAppliedCartRuleIds); + + $cart->applied_cart_rule_ids = join(',', $cartAppliedCartRuleIds); + + $cart->save(); + + return $this; + } + + /** + * Cart free shipping discount calculation process + * + * @param Cart $cart + * @return void + */ + public function processFreeShippingDiscount($cart) + { + if (! $selectedShipping = $cart->selected_shipping_rate) + return; + + $selectedShipping->discount_amount = 0; + + $selectedShipping->base_discount_amount = 0; + + $appliedRuleIds = []; + + foreach ($this->getCartRules() as $rule) { + if (! $this->canProcessRule($rule)) + continue; + + if (! $this->validator->validate($rule, $cart)) + continue; + + if (! $rule || ! $rule->free_shipping) + continue; + + $selectedShipping->price = 0; + + $selectedShipping->base_price = 0; + + $selectedShipping->save(); + + $appliedRuleIds[$rule->id] = $rule->id; + + if ($rule->end_other_rules) + break; + } + + $cartAppliedCartRuleIds = array_merge(explode(',', $cart->applied_cart_rule_ids), $appliedRuleIds); + + $cartAppliedCartRuleIds = array_filter($cartAppliedCartRuleIds); + + $cartAppliedCartRuleIds = array_unique($cartAppliedCartRuleIds); + + $cart->applied_cart_rule_ids = join(',', $cartAppliedCartRuleIds); + + $cart->save(); + } + + /** + * Calculate cart item totals for each rule + * + * @param mixed $items + * @return Validator + */ + public function calculateCartItemTotals($items) + { + foreach ($this->getCartRules() as $rule) { + if ($rule->action_type == 'cart_fixed') { + $totalPrice = $totalBasePrice = $validCount = 0; + + foreach ($items as $item) { + if (! $this->canProcessRule($rule, $item)) + continue; + + $quantity = $rule->discount_quantity ? min($item->quantity, $rule->discount_quantity) : $item->quantity; + + $totalBasePrice += $item->base_price * $quantity; + + $validCount++; + } + + $this->itemTotals[$rule->id] = [ + 'base_total_price' => $totalBasePrice, + 'total_items' => $validCount, + ]; + } + } + } + + /** + * Check if coupon code is valid or not, if not remove from cart + * + * @return void + */ + public function validateCouponCode() + { + $cart = Cart::getCart(); + + if (! $cart->coupon_code) + return; + + $coupon = $this->cartRuleCouponRepository->findOneByField('code', $cart->coupon_code); + + if (! $coupon || ! in_array($coupon->cart_rule_id, explode(',', $cart->applied_cart_rule_ids))) + Cart::removeCouponCode(); + } +} \ No newline at end of file diff --git a/packages/Webkul/CartRule/src/Http/Controllers/CartRuleController.php b/packages/Webkul/CartRule/src/Http/Controllers/CartRuleController.php new file mode 100644 index 000000000..dc90a01b5 --- /dev/null +++ b/packages/Webkul/CartRule/src/Http/Controllers/CartRuleController.php @@ -0,0 +1,206 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class CartRuleController extends Controller +{ + /** + * Initialize _config, a default request parameter with route + * + * @param array + */ + protected $_config; + + /** + * To hold Cart repository instance + * + * @var CartRuleRepository + */ + protected $cartRuleRepository; + + /** + * To hold CartRuleCouponRepository repository instance + * + * @var CartRuleCouponRepository + */ + protected $cartRuleCouponRepository; + + /** + * Create a new controller instance. + * + * @param \Webkul\CartRule\Repositories\CartRuleRepository $cartRuleRepository + * @param \Webkul\CartRule\Repositories\CartRuleCouponRepository $cartRuleCouponRepository + * @return void + */ + public function __construct( + CartRuleRepository $cartRuleRepository, + CartRuleCouponRepository $cartRuleCouponRepository + ) + { + $this->_config = request('_config'); + + $this->cartRuleRepository = $cartRuleRepository; + + $this->cartRuleCouponRepository = $cartRuleCouponRepository; + } + + /** + * Display a listing of the resource. + * + * @return \Illuminate\Http\Response + */ + public function index() + { + return view($this->_config['view']); + } + + /** + * Show the form for creating a new resource. + * + * @return \Illuminate\Http\Response + */ + public function create() + { + return view($this->_config['view']); + } + + /** + * Store a newly created resource in storage. + * + * @return \Illuminate\Http\Response + */ + public function store() + { + $this->validate(request(), [ + 'name' => 'required', + 'channels' => 'required|array|min:1', + 'customer_groups' => 'required|array|min:1', + 'coupon_type' => 'required', + 'use_auto_generation' => 'required_if:coupon_type,==,1', + 'coupon_code' => 'required_if:use_auto_generation,==,0', + 'starts_from' => 'nullable|date', + 'ends_till' => 'nullable|date|after_or_equal:starts_from', + 'action_type' => 'required', + 'discount_amount' => 'required|numeric' + ]); + + $data = request()->all(); + + Event::fire('promotions.cart_rule.create.before'); + + $cartRule = $this->cartRuleRepository->create($data); + + Event::fire('promotions.cart_rule.create.after', $cartRule); + + session()->flash('success', trans('admin::app.response.create-success', ['name' => 'Cart Rule'])); + + return redirect()->route($this->_config['redirect']); + } + + /** + * Show the form for editing the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function edit($id) + { + $cartRule = $this->cartRuleRepository->findOrFail($id); + + return view($this->_config['view'], compact('cartRule')); + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function update(Request $request, $id) + { + $this->validate(request(), [ + 'name' => 'required', + 'channels' => 'required|array|min:1', + 'customer_groups' => 'required|array|min:1', + 'coupon_type' => 'required', + 'use_auto_generation' => 'required_if:coupon_type,==,1', + 'coupon_code' => 'required_if:use_auto_generation,==,0', + 'starts_from' => 'nullable|date', + 'ends_till' => 'nullable|date|after_or_equal:starts_from', + 'action_type' => 'required', + 'discount_amount' => 'required|numeric' + ]); + + $cartRule = $this->cartRuleRepository->findOrFail($id); + + Event::fire('promotions.cart_rule.update.before', $cartRule); + + $cartRule = $this->cartRuleRepository->update(request()->all(), $id); + + Event::fire('promotions.cart_rule.update.after', $cartRule); + + session()->flash('success', trans('admin::app.response.update-success', ['name' => 'Cart Rule'])); + + return redirect()->route($this->_config['redirect']); + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function destroy($id) + { + $cartRule = $this->cartRuleRepository->findOrFail($id); + + try { + Event::fire('promotions.cart_rule.delete.before', $id); + + $this->cartRuleRepository->delete($id); + + Event::fire('promotions.cart_rule.delete.after', $id); + + session()->flash('success', trans('admin::app.response.delete-success', ['name' => 'Cart Rule'])); + + return response()->json(['message' => true], 200); + } catch(\Exception $e) { + session()->flash('error', trans('admin::app.response.delete-failed', ['name' => 'Cart Rule'])); + } + + return response()->json(['message' => false], 400); + } + + /** + * Generate coupon code for cart rule + * + * @return \Illuminate\Http\JsonResponse + */ + public function generateCoupons() + { + $this->validate(request(), [ + 'coupon_qty' => 'required|integer|min:1', + 'code_length' => 'required|integer|min:10', + 'code_format' => 'required' + ]); + + if (! request('id')) + return response()->json(['message' => trans('admin::app.promotions.cart-rules.cart-rule-not-defind-error')], 400); + + $this->cartRuleCouponRepository->generateCoupons(request()->all(), request('id')); + + return response()->json(['message' => trans('admin::app.response.create-success', ['name' => 'Cart rule coupons'])]); + } +} \ No newline at end of file diff --git a/packages/Webkul/CartRule/src/Http/Controllers/CartRuleCouponController.php b/packages/Webkul/CartRule/src/Http/Controllers/CartRuleCouponController.php new file mode 100644 index 000000000..7da633cb8 --- /dev/null +++ b/packages/Webkul/CartRule/src/Http/Controllers/CartRuleCouponController.php @@ -0,0 +1,55 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class CartRuleCouponController extends Controller +{ + /** + * To hold CartRuleCouponRepository repository instance + * + * @var CartRuleCouponRepository + */ + protected $cartRuleCouponRepository; + + /** + * Create a new controller instance. + * + * @param \Webkul\CartRule\Repositories\CartRuleCouponRepository $cartRuleCouponRepository + * @return void + */ + public function __construct(CartRuleCouponRepository $cartRuleCouponRepository) + { + $this->cartRuleCouponRepository = $cartRuleCouponRepository; + } + + /** + * Mass Delete the coupons + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function massDelete() + { + $couponIds = explode(',', request()->input('indexes')); + + foreach ($couponIds as $couponId) { + $coupon = $this->cartRuleCouponRepository->find($couponId); + + if ($coupon) + $this->cartRuleCouponRepository->delete($couponId); + } + + session()->flash('success', trans('admin::app.promotions.cart-rules.mass-delete-success')); + + return redirect()->back(); + } +} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Http/Controllers/Controller.php b/packages/Webkul/CartRule/src/Http/Controllers/Controller.php similarity index 87% rename from packages/Webkul/Discount/src/Http/Controllers/Controller.php rename to packages/Webkul/CartRule/src/Http/Controllers/Controller.php index dc4b61e7c..259457d89 100644 --- a/packages/Webkul/Discount/src/Http/Controllers/Controller.php +++ b/packages/Webkul/CartRule/src/Http/Controllers/Controller.php @@ -1,9 +1,9 @@ + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class Cart +{ + +} \ No newline at end of file diff --git a/packages/Webkul/CartRule/src/Listeners/Order.php b/packages/Webkul/CartRule/src/Listeners/Order.php new file mode 100755 index 000000000..f22fdfa35 --- /dev/null +++ b/packages/Webkul/CartRule/src/Listeners/Order.php @@ -0,0 +1,139 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class Order +{ + /** + * CartRuleRepository object + * + * @var CartRuleRepository + */ + protected $cartRuleRepository; + + /** + * CartRuleCustomerRepository object + * + * @var CartRuleCustomerRepository + */ + protected $cartRuleCustomerRepository; + + /** + * CartRuleCouponRepository object + * + * @var CartRuleCouponRepository + */ + protected $cartRuleCouponRepository; + + /** + * CartRuleCouponUsageRepository object + * + * @var CartRuleCouponUsageRepository + */ + protected $cartRuleCouponUsageRepository; + + /** + * Create a new listener instance. + * + * @param Webkul\CartRule\Repositories\CartRuleRepository $cartRuleRepository + * @param Webkul\CartRule\Repositories\CartRuleCustomerRepository $cartRuleCustomerRepository + * @param Webkul\CartRule\Repositories\CartRuleCouponRepository $cartRuleCouponRepository + * @param Webkul\CartRule\Repositories\CartRuleCouponUsageRepository $cartRuleCouponUsageRepository + * @return void + */ + public function __construct( + CartRuleRepository $cartRuleRepository, + CartRuleCustomerRepository $cartRuleCustomerRepository, + CartRuleCouponRepository $cartRuleCouponRepository, + CartRuleCouponUsageRepository $cartRuleCouponUsageRepository + ) + { + $this->cartRuleRepository = $cartRuleRepository; + + $this->cartRuleCustomerRepository = $cartRuleCustomerRepository; + + $this->cartRuleCouponRepository = $cartRuleCouponRepository; + + $this->cartRuleCouponUsageRepository = $cartRuleCouponUsageRepository; + } + + /** + * Save cart rule and cart rule coupon properties after place order + * + * @param Order $order + * @return void + */ + public function manageCartRule($order) + { + if (! $order->discount_amount) + return; + + $cartRuleIds = explode(',', $order->applied_cart_rule_ids); + + $cartRuleIds = array_unique($cartRuleIds); + + foreach ($cartRuleIds as $ruleId) { + $rule = $this->cartRuleRepository->find($ruleId); + + if (! $rule) + continue; + + $rule->update(['times_used' => $rule->times_used + 1]); + + if (! $order->customer_id) + continue; + + $ruleCustomer = $this->cartRuleCustomerRepository->findOneWhere([ + 'customer_id' => $order->customer_id, + 'cart_rule_id' => $ruleId + ]); + + if ($ruleCustomer) { + $this->cartRuleCustomerRepository->update(['times_used' => $ruleCustomer->times_used + 1], $ruleCustomer->id); + } else { + $this->cartRuleCustomerRepository->create([ + 'customer_id' => $order->customer_id, + 'cart_rule_id' => $ruleId, + 'times_used' => 1 + ]); + } + } + + if (! $order->coupon_code) + return; + + $coupon = $this->cartRuleCouponRepository->findOneByField('code', $order->coupon_code); + + if ($coupon) { + $this->cartRuleCouponRepository->update(['times_used' => $coupon->times_used + 1], $coupon->id); + + if ($order->customer_id) { + $couponUsage = $this->cartRuleCouponUsageRepository->findOneWhere([ + 'customer_id' => $order->customer_id, + 'cart_rule_coupon_id' => $coupon->id + ]); + + if ($couponUsage) { + $this->cartRuleCouponUsageRepository->update(['times_used' => $couponUsage->times_used + 1], $couponUsage->id); + } else { + $this->cartRuleCouponUsageRepository->create([ + 'customer_id' => $order->customer_id, + 'cart_rule_coupon_id' => $coupon->id, + 'times_used' => 1 + ]); + } + } + } + } +} \ No newline at end of file diff --git a/packages/Webkul/CartRule/src/Models/CartRule.php b/packages/Webkul/CartRule/src/Models/CartRule.php new file mode 100644 index 000000000..6392a1c59 --- /dev/null +++ b/packages/Webkul/CartRule/src/Models/CartRule.php @@ -0,0 +1,66 @@ + 'array', + ]; + + // public $translatedAttributes = ['name']; + + /** + * Get the channels that owns the cart rule. + */ + public function channels() + { + return $this->belongsToMany(ChannelProxy::modelClass(), 'cart_rule_channels'); + } + + /** + * Get the customer groups that owns the cart rule. + */ + public function customer_groups() + { + return $this->belongsToMany(CustomerGroupProxy::modelClass(), 'cart_rule_customer_groups'); + } + + /** + * Get the coupons that owns the cart rule. + */ + public function coupons() + { + return $this->hasOne(CartRuleCouponProxy::modelClass()); + } + + /** + * Get primary coupon code for cart rule. + */ + public function coupon_code() + { + return $this->coupons()->where('is_primary', 1); + } + + /** + * Get primary coupon code for cart rule. + */ + public function getCouponCodeAttribute() + { + $coupon = $this->coupon_code()->first(); + + if (! $coupon) + return; + + return $coupon->code; + } +} \ No newline at end of file diff --git a/packages/Webkul/CartRule/src/Models/CartRuleCoupon.php b/packages/Webkul/CartRule/src/Models/CartRuleCoupon.php new file mode 100644 index 000000000..045af59a1 --- /dev/null +++ b/packages/Webkul/CartRule/src/Models/CartRuleCoupon.php @@ -0,0 +1,19 @@ +belongsTo(CartRuleProxy::modelClass()); + } +} \ No newline at end of file diff --git a/packages/Webkul/CartRule/src/Models/CartRuleCouponProxy.php b/packages/Webkul/CartRule/src/Models/CartRuleCouponProxy.php new file mode 100644 index 000000000..4a8f20030 --- /dev/null +++ b/packages/Webkul/CartRule/src/Models/CartRuleCouponProxy.php @@ -0,0 +1,10 @@ +loadMigrationsFrom(__DIR__ . '/../Database/Migrations'); + + $this->app->register(EventServiceProvider::class); + } + + /** + * Register services. + * + * @return void + */ + public function register() + { + } +} \ No newline at end of file diff --git a/packages/Webkul/CartRule/src/Providers/EventServiceProvider.php b/packages/Webkul/CartRule/src/Providers/EventServiceProvider.php new file mode 100755 index 000000000..a935da915 --- /dev/null +++ b/packages/Webkul/CartRule/src/Providers/EventServiceProvider.php @@ -0,0 +1,19 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class CartRuleCouponRepository extends Repository +{ + /** + * @var array + */ + protected $charsets = [ + 'alphanumeric' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', + 'alphabetical' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + 'numeric' => '0123456789' + ]; + + /** + * Specify Model class name + * + * @return mixed + */ + function model() + { + return 'Webkul\CartRule\Contracts\CartRuleCoupon'; + } + + /** + * Creates coupons for cart rule + * + * @param array $data + * @param integer $cartRuleId + * @return void + */ + public function generateCoupons($data, $cartRuleId) + { + $cartRule = app('Webkul\CartRule\Repositories\CartRuleRepository')->findOrFail($cartRuleId); + + for ($i = 0; $i < $data['coupon_qty']; $i++) { + parent::create([ + 'cart_rule_id' => $cartRuleId, + 'code' => $data['code_prefix'] . $this->getRandomString($data['code_format'], $data['code_length']) . $data['code_suffix'], + 'usage_limit' => $cartRule->uses_per_coupon ?? 0, + 'usage_per_customer' => $cartRule->usage_per_customer ?? 0, + 'is_primary' => 0, + 'expired_at' => $cartRule->ends_till ?: null + ]); + } + } + + /** + * Creates coupons for cart rule + * + * @param string $format + * @param integer $length + * @return string + */ + public function getRandomString($format, $length) + { + $couponCode = ''; + + for ($i = 0; $i < $length; $i++) { + $couponCode .= $this->charsets[$format][rand(0, strlen($this->charsets[$format]) - 1)]; + } + + return $couponCode; + } +} \ No newline at end of file diff --git a/packages/Webkul/CartRule/src/Repositories/CartRuleCouponUsageRepository.php b/packages/Webkul/CartRule/src/Repositories/CartRuleCouponUsageRepository.php new file mode 100755 index 000000000..5d6350ba8 --- /dev/null +++ b/packages/Webkul/CartRule/src/Repositories/CartRuleCouponUsageRepository.php @@ -0,0 +1,24 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class CartRuleCouponUsageRepository extends Repository +{ + /** + * Specify Model class name + * + * @return mixed + */ + function model() + { + return 'Webkul\CartRule\Contracts\CartRuleCouponUsage'; + } +} \ No newline at end of file diff --git a/packages/Webkul/CartRule/src/Repositories/CartRuleCustomerRepository.php b/packages/Webkul/CartRule/src/Repositories/CartRuleCustomerRepository.php new file mode 100755 index 000000000..e3218eb94 --- /dev/null +++ b/packages/Webkul/CartRule/src/Repositories/CartRuleCustomerRepository.php @@ -0,0 +1,24 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class CartRuleCustomerRepository extends Repository +{ + /** + * Specify Model class name + * + * @return mixed + */ + function model() + { + return 'Webkul\CartRule\Contracts\CartRuleCustomer'; + } +} \ No newline at end of file diff --git a/packages/Webkul/CartRule/src/Repositories/CartRuleRepository.php b/packages/Webkul/CartRule/src/Repositories/CartRuleRepository.php new file mode 100755 index 000000000..80847ee67 --- /dev/null +++ b/packages/Webkul/CartRule/src/Repositories/CartRuleRepository.php @@ -0,0 +1,478 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class CartRuleRepository extends Repository +{ + /** + * AttributeFamilyRepository object + * + * @var AttributeFamilyRepository + */ + protected $attributeFamilyRepository; + + /** + * AttributeRepository object + * + * @var AttributeRepository + */ + protected $attributeRepository; + + /** + * CategoryRepository class + * + * @var CategoryRepository + */ + protected $categoryRepository; + + /** + * CartRuleCouponRepository object + * + * @var CartRuleCouponRepository + */ + protected $cartRuleCouponRepository; + + /** + * TaxCategoryRepository class + * + * @var TaxCategoryRepository + */ + protected $taxCategoryRepository; + + /** + * CountryRepository class + * + * @var CountryRepository + */ + protected $countryRepository; + + /** + * CountryStateRepository class + * + * @var CountryStateRepository + */ + protected $countryStateRepository; + + /** + * Create a new repository instance. + * + * @param Webkul\Attribute\Repositories\AttributeFamilyRepository $attributeFamilyRepository + * @param Webkul\Attribute\Repositories\AttributeRepository $attributeRepository + * @param Webkul\Category\Repositories\CategoryRepository $categoryRepository + * @param Webkul\CartRule\Repositories\CartRuleCouponRepository $cartRuleCouponRepository + * @param Webkul\Tax\Repositories\TaxCategoryRepository $taxCategoryRepository + * @param Webkul\Core\Repositories\CountryRepository $countryRepository + * @param Webkul\Core\Repositories\CountryStateRepository $countryStateRepository + * @param Illuminate\Container\Container $app + * @return void + */ + public function __construct( + AttributeFamilyRepository $attributeFamilyRepository, + AttributeRepository $attributeRepository, + CategoryRepository $categoryRepository, + CartRuleCouponRepository $cartRuleCouponRepository, + TaxCategoryRepository $taxCategoryRepository, + CountryRepository $countryRepository, + CountryStateRepository $countryStateRepository, + App $app + ) + { + $this->attributeFamilyRepository = $attributeFamilyRepository; + + $this->attributeRepository = $attributeRepository; + + $this->categoryRepository = $categoryRepository; + + $this->cartRuleCouponRepository = $cartRuleCouponRepository; + + $this->taxCategoryRepository = $taxCategoryRepository; + + $this->countryRepository = $countryRepository; + + $this->countryStateRepository = $countryStateRepository; + + parent::__construct($app); + } + + /** + * Specify Model class name + * + * @return mixed + */ + function model() + { + return 'Webkul\CartRule\Contracts\CartRule'; + } + + /** + * @param array $data + * @return mixed + */ + public function create(array $data) + { + $data['starts_from'] = $data['starts_from'] ?: null; + + $data['ends_till'] = $data['ends_till'] ?: null; + + $data['status'] = ! isset($data['status']) ? 0 : 1; + + $cartRule = parent::create($data); + + $cartRule->channels()->sync($data['channels']); + + $cartRule->customer_groups()->sync($data['customer_groups']); + + if ($data['coupon_type'] && ! $data['use_auto_generation']) { + $this->cartRuleCouponRepository->create([ + 'cart_rule_id' => $cartRule->id, + 'code' => $data['coupon_code'], + 'usage_limit' => $data['usage_per_customer'] ?? 0, + 'usage_per_customer' => $data['usage_per_customer'] ?? 0, + 'is_primary' => 1, + 'expired_at' => $data['ends_till'] ?: null + ]); + } + + return $cartRule; + } + + /** + * @param array $data + * @param array $id + * @param string $attribute + * @return mixed + */ + public function update(array $data, $id, $attribute = "id") + { + $data['starts_from'] = $data['starts_from'] ?: null; + + $data['ends_till'] = $data['ends_till'] ?: null; + + $data['status'] = ! isset($data['status']) ? 0 : 1; + + $data['conditions'] = $data['conditions'] ?? []; + + $cartRule = $this->find($id); + + parent::update($data, $id, $attribute); + + $cartRule->channels()->sync($data['channels']); + + $cartRule->customer_groups()->sync($data['customer_groups']); + + if ($data['coupon_type']) { + if (! $data['use_auto_generation']) { + $cartRuleCoupon = $this->cartRuleCouponRepository->findOneWhere(['is_primary' => 1, 'cart_rule_id' => $cartRule->id]); + + if ($cartRuleCoupon) { + $this->cartRuleCouponRepository->update([ + 'code' => $data['coupon_code'], + 'usage_limit' => $data['uses_per_coupon'] ?? 0, + 'usage_per_customer' => $data['usage_per_customer'] ?? 0, + 'expired_at' => $data['ends_till'] ?: null + ], $cartRuleCoupon->id); + } else { + $this->cartRuleCouponRepository->create([ + 'cart_rule_id' => $cartRule->id, + 'code' => $data['coupon_code'], + 'usage_limit' => $data['uses_per_coupon'] ?? 0, + 'usage_per_customer' => $data['usage_per_customer'] ?? 0, + 'is_primary' => 1, + 'expired_at' => $data['ends_till'] ?: null + ]); + } + } else { + $this->cartRuleCouponRepository->deleteWhere(['is_primary' => 1, 'cart_rule_id' => $cartRule->id]); + + $this->cartRuleCouponRepository->getModel()->where('cart_rule_id', $cartRule->id)->update([ + 'usage_limit' => $data['uses_per_coupon'] ?? 0, + 'usage_per_customer' => $data['usage_per_customer'] ?? 0, + 'expired_at' => $data['ends_till'] ?: null + ]); + } + } else { + $cartRuleCoupon = $this->cartRuleCouponRepository->deleteWhere(['is_primary' => 1, 'cart_rule_id' => $cartRule->id]); + } + + return $cartRule; + } + + /** + * Returns attributes for cart rule conditions + * + * @return array + */ + public function getConditionAttributes() + { + $attributes = [ + [ + 'key' => 'cart', + 'label' => trans('admin::app.promotions.cart-rules.cart-attribute'), + 'children' => [ + [ + 'key' => 'cart|base_sub_total', + 'type' => 'price', + 'label' => trans('admin::app.promotions.cart-rules.subtotal') + ], [ + 'key' => 'cart|items_qty', + 'type' => 'integer', + 'label' => trans('admin::app.promotions.cart-rules.total-items-qty') + ], [ + 'key' => 'cart|payment_method', + 'type' => 'select', + 'options' => $this->getPaymentMethods(), + 'label' => trans('admin::app.promotions.cart-rules.payment-method') + ], [ + 'key' => 'cart|shipping_method', + 'type' => 'select', + 'options' => $this->getShippingMethods(), + 'label' => trans('admin::app.promotions.cart-rules.shipping-method') + ], [ + 'key' => 'cart|postcode', + 'type' => 'text', + 'label' => trans('admin::app.promotions.cart-rules.shipping-postcode') + ], [ + 'key' => 'cart|state', + 'type' => 'select', + 'options' => $this->groupedStatesByCountries(), + 'label' => trans('admin::app.promotions.cart-rules.shipping-state') + ], [ + 'key' => 'cart|country', + 'type' => 'select', + 'options' => $this->getCountries(), + 'label' => trans('admin::app.promotions.cart-rules.shipping-country') + ] + ] + ], [ + 'key' => 'cart_item', + 'label' => trans('admin::app.promotions.cart-rules.cart-item-attribute'), + 'children' => [ + [ + 'key' => 'cart_item|base_price', + 'type' => 'price', + 'label' => trans('admin::app.promotions.cart-rules.price-in-cart') + ], [ + 'key' => 'cart_item|quantity', + 'type' => 'integer', + 'label' => trans('admin::app.promotions.cart-rules.qty-in-cart') + ], [ + 'key' => 'cart_item|base_total_weight', + 'type' => 'decimal', + 'label' => trans('admin::app.promotions.cart-rules.total-weight') + ], [ + 'key' => 'cart_item|base_total', + 'type' => 'price', + 'label' => trans('admin::app.promotions.cart-rules.subtotal') + ] + ] + ], [ + 'key' => 'product', + 'label' => trans('admin::app.promotions.cart-rules.product-attribute'), + 'children' => [ + [ + 'key' => 'product|category_ids', + 'type' => 'multiselect', + 'label' => trans('admin::app.promotions.cart-rules.categories'), + 'options' => $categories = $this->categoryRepository->getCategoryTree() + ], [ + 'key' => 'product|children::category_ids', + 'type' => 'multiselect', + 'label' => trans('admin::app.promotions.cart-rules.children-categories'), + 'options' => $categories + ], [ + 'key' => 'product|parent::category_ids', + 'type' => 'multiselect', + 'label' => trans('admin::app.promotions.cart-rules.parent-categories'), + 'options' => $categories + ], [ + 'key' => 'product|attribute_family_id', + 'type' => 'select', + 'label' => trans('admin::app.promotions.cart-rules.attribute_family'), + 'options' => $this->getAttributeFamilies() + ] + ] + ] + ]; + + foreach ($this->attributeRepository->findWhereNotIn('type', ['textarea', 'image', 'file']) as $attribute) { + $attributeType = $attribute->type; + + if ($attribute->code == 'tax_category_id') { + $options = $this->getTaxCategories(); + } else { + $options = $attribute->options; + } + + if ($attribute->validation == 'decimal') + $attributeType = 'decimal'; + + if ($attribute->validation == 'numeric') + $attributeType = 'integer'; + + $attributes[2]['children'][] = [ + 'key' => 'product|' . $attribute->code, + 'type' => $attribute->type, + 'label' => $attribute->name, + 'options' => $options + ]; + + $attributes[2]['children'][] = [ + 'key' => 'product|children::' . $attribute->code, + 'type' => $attribute->type, + 'label' => trans('admin::app.promotions.cart-rules.attribute-name-children-only', ['attribute_name' => $attribute->name]), + 'options' => $options + ]; + + $attributes[2]['children'][] = [ + 'key' => 'product|parent::' . $attribute->code, + 'type' => $attribute->type, + 'label' => trans('admin::app.promotions.cart-rules.attribute-name-parent-only', ['attribute_name' => $attribute->name]), + 'options' => $options + ]; + } + + return $attributes; + } + + /** + * Returns all payment methods + * + * @return array + */ + public function getPaymentMethods() + { + $methods = []; + + foreach (config('paymentmethods') as $paymentMethod) { + $object = app($paymentMethod['class']); + + $methods[] = [ + 'id' => $object->getCode(), + 'admin_name' => $object->getTitle() + ]; + } + + return $methods; + } + + /** + * Returns all shipping methods + * + * @return array + */ + public function getShippingMethods() + { + $methods = []; + + foreach (config('carriers') as $shippingMethod) { + $object = app($shippingMethod['class']); + + $methods[] = [ + 'id' => $object->getCode(), + 'admin_name' => $object->getTitle() + ]; + } + + return $methods; + } + + /** + * Returns all countries + * + * @return array + */ + public function getTaxCategories() + { + $taxCategories = []; + + foreach ($this->taxCategoryRepository->all() as $taxCategory) { + $taxCategories[] = [ + 'id' => $taxCategory->id, + 'admin_name' => $taxCategory->name, + ]; + } + + return $taxCategories; + } + + /** + * Returns all attribute families + * + * @return array + */ + public function getAttributeFamilies() + { + $attributeFamilies = []; + + foreach ($this->attributeFamilyRepository->all() as $attributeFamily) { + $attributeFamilies[] = [ + 'id' => $attributeFamily->id, + 'admin_name' => $attributeFamily->name, + ]; + } + + return $attributeFamilies; + } + + /** + * Returns all countries + * + * @return array + */ + public function getCountries() + { + $countries = []; + + foreach ($this->countryRepository->all() as $country) { + $countries[] = [ + 'id' => $country->code, + 'admin_name' => $country->name, + ]; + } + + return $countries; + } + + /** + * Retrieve all grouped states by country code + * + * @return array + */ + public function groupedStatesByCountries() + { + $collection = []; + + foreach ($this->countryRepository->all() as $country) { + $countryStates = $this->countryStateRepository->findWhere( + ['country_id' => $country->id], + ['code', 'default_name as admin_name'] + )->toArray(); + + if (! count($countryStates)) + continue; + + $collection[] = [ + 'id' => $country->code, + 'admin_name' => $country->name, + 'states' => $countryStates + ]; + } + + return $collection; + } +} \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Console/Commands/PriceRuleIndex.php b/packages/Webkul/CatalogRule/src/Console/Commands/PriceRuleIndex.php new file mode 100644 index 000000000..4f856c979 --- /dev/null +++ b/packages/Webkul/CatalogRule/src/Console/Commands/PriceRuleIndex.php @@ -0,0 +1,53 @@ +catalogRuleIndexHelper = $catalogRuleIndexHelper; + + parent::__construct(); + } + + /** + * Execute the console command. + * + * @return mixed + */ + public function handle() + { + // $this->catalogRuleIndexHelper->reindexComplete(); + } +} \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Contracts/CatalogRule.php b/packages/Webkul/CatalogRule/src/Contracts/CatalogRule.php new file mode 100644 index 000000000..c322bdc78 --- /dev/null +++ b/packages/Webkul/CatalogRule/src/Contracts/CatalogRule.php @@ -0,0 +1,7 @@ +json('products_selection')->nullable(); - }); + Schema::dropIfExists('catalog_rule_customer_groups'); + + Schema::dropIfExists('catalog_rule_channels'); + + Schema::dropIfExists('catalog_rule_products'); + + Schema::dropIfExists('catalog_rule_products_price'); + + Schema::dropIfExists('catalog_rules'); } /** @@ -25,8 +31,6 @@ class AddProductsSelectionColumnInCartRulesTable extends Migration */ public function down() { - Schema::table('cart_rules', function (Blueprint $table) { - $table->dropColumn('products_selection'); - }); + // } } diff --git a/packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130433_create_catalog_rules_table.php b/packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_03_184613_create_catalog_rules_table.php similarity index 62% rename from packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130433_create_catalog_rules_table.php rename to packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_03_184613_create_catalog_rules_table.php index 69a4a8bcc..049a531ce 100644 --- a/packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130433_create_catalog_rules_table.php +++ b/packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_03_184613_create_catalog_rules_table.php @@ -15,16 +15,17 @@ class CreateCatalogRulesTable extends Migration { Schema::create('catalog_rules', function (Blueprint $table) { $table->increments('id'); - $table->string('name'); - $table->text('description'); - $table->datetime('starts_from')->nullable(); - $table->datetime('ends_till')->nullable(); + $table->string('name')->nullable(); + $table->string('description')->nullable(); + $table->date('starts_from')->nullable(); + $table->date('ends_till')->nullable(); $table->boolean('status')->default(0); + $table->boolean('condition_type')->default(1); $table->json('conditions')->nullable(); - $table->json('actions')->nullable(); $table->boolean('end_other_rules')->default(0); - $table->string('action_code')->nullable(); - $table->decimal('discount_amount', 20, 4)->default(0.0000); + $table->string('action_type')->nullable(); + $table->decimal('discount_amount', 12, 4)->default(0); + $table->integer('sort_order')->unsigned()->default(0); $table->timestamps(); }); } diff --git a/packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130458_create_catalog_rule_channels_table.php b/packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_03_184651_create_catalog_rule_channels_table.php similarity index 91% rename from packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130458_create_catalog_rule_channels_table.php rename to packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_03_184651_create_catalog_rule_channels_table.php index 32e0ea36e..8f0053237 100644 --- a/packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130458_create_catalog_rule_channels_table.php +++ b/packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_03_184651_create_catalog_rule_channels_table.php @@ -14,12 +14,13 @@ class CreateCatalogRuleChannelsTable extends Migration public function up() { Schema::create('catalog_rule_channels', function (Blueprint $table) { - $table->increments('id'); - $table->integer('channel_id')->unsigned(); - $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); $table->integer('catalog_rule_id')->unsigned(); + $table->integer('channel_id')->unsigned(); + + $table->primary(['catalog_rule_id', 'channel_id']); + $table->foreign('catalog_rule_id')->references('id')->on('catalog_rules')->onDelete('cascade'); - $table->timestamps(); + $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); }); } diff --git a/packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130451_create_catalog_rule_customer_groups_table.php b/packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_03_184732_create_catalog_rule_customer_groups_table.php similarity index 86% rename from packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130451_create_catalog_rule_customer_groups_table.php rename to packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_03_184732_create_catalog_rule_customer_groups_table.php index 7337cef44..5670c6a80 100644 --- a/packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130451_create_catalog_rule_customer_groups_table.php +++ b/packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_03_184732_create_catalog_rule_customer_groups_table.php @@ -14,12 +14,14 @@ class CreateCatalogRuleCustomerGroupsTable extends Migration public function up() { Schema::create('catalog_rule_customer_groups', function (Blueprint $table) { - $table->increments('id'); - $table->integer('customer_group_id')->unsigned(); - $table->foreign('customer_group_id')->references('id')->on('customer_groups')->onDelete('cascade'); $table->integer('catalog_rule_id')->unsigned(); + $table->integer('customer_group_id')->unsigned(); + + + $table->primary(['catalog_rule_id', 'customer_group_id'], 'catalog_rule_id_customer_group_id_primary'); + $table->foreign('catalog_rule_id')->references('id')->on('catalog_rules')->onDelete('cascade'); - $table->timestamps(); + $table->foreign('customer_group_id')->references('id')->on('customer_groups')->onDelete('cascade'); }); } diff --git a/packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130550_create_catalog_rule_products_table.php b/packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_06_101110_create_catalog_rule_products_table.php similarity index 80% rename from packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130550_create_catalog_rule_products_table.php rename to packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_06_101110_create_catalog_rule_products_table.php index 2f456559e..8628050ac 100644 --- a/packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130550_create_catalog_rule_products_table.php +++ b/packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_06_101110_create_catalog_rule_products_table.php @@ -14,20 +14,25 @@ class CreateCatalogRuleProductsTable extends Migration public function up() { Schema::create('catalog_rule_products', function (Blueprint $table) { - $table->bigIncrements('id'); - $table->integer('catalog_rule_id')->unsigned(); - $table->foreign('catalog_rule_id')->references('id')->on('catalog_rules')->onDelete('cascade'); + $table->increments('id'); $table->datetime('starts_from')->nullable(); $table->datetime('ends_till')->nullable(); - $table->integer('customer_group_id')->unsigned(); - $table->foreign('customer_group_id')->references('id')->on('customer_groups')->onDelete('cascade'); - $table->integer('channel_id')->unsigned(); - $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); + $table->boolean('end_other_rules')->default(0); + $table->string('action_type')->nullable(); + $table->decimal('discount_amount', 12, 4)->default(0); + $table->integer('sort_order')->unsigned()->default(0); + $table->integer('product_id')->unsigned(); $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade'); - $table->string('action_code')->nullable(); - $table->decimal('action_amount', 20, 4)->default(0.0000); - $table->timestamps(); + + $table->integer('customer_group_id')->unsigned(); + $table->foreign('customer_group_id')->references('id')->on('customer_groups')->onDelete('cascade'); + + $table->integer('catalog_rule_id')->unsigned(); + $table->foreign('catalog_rule_id')->references('id')->on('catalog_rules')->onDelete('cascade'); + + $table->integer('channel_id')->unsigned(); + $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); }); } @@ -40,4 +45,4 @@ class CreateCatalogRuleProductsTable extends Migration { Schema::dropIfExists('catalog_rule_products'); } -} \ No newline at end of file +} diff --git a/packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130583_create_catalog_rule_products_price_table.php b/packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_06_110507_create_catalog_rule_product_prices_table.php similarity index 76% rename from packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130583_create_catalog_rule_products_price_table.php rename to packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_06_110507_create_catalog_rule_product_prices_table.php index a5af74b08..dab445de0 100644 --- a/packages/Webkul/Discount/src/Database/Migrations/2019_08_08_130583_create_catalog_rule_products_price_table.php +++ b/packages/Webkul/CatalogRule/src/Database/Migrations/2019_12_06_110507_create_catalog_rule_product_prices_table.php @@ -4,7 +4,7 @@ use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; -class CreateCatalogRuleProductsPriceTable extends Migration +class CreateCatalogRuleProductPricesTable extends Migration { /** * Run the migrations. @@ -13,20 +13,24 @@ class CreateCatalogRuleProductsPriceTable extends Migration */ public function up() { - Schema::create('catalog_rule_products_price', function (Blueprint $table) { - $table->bigIncrements('id'); - $table->integer('channel_id')->unsigned(); - $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); - $table->integer('customer_group_id')->unsigned(); - $table->foreign('customer_group_id')->references('id')->on('customer_groups')->onDelete('cascade'); - $table->integer('product_id')->unsigned(); - $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade'); - $table->integer('catalog_rule_id')->unsigned(); - $table->foreign('catalog_rule_id')->references('id')->on('catalog_rules')->onDelete('cascade'); - $table->decimal('rule_price', 20, 4)->default(0.0000); + Schema::create('catalog_rule_product_prices', function (Blueprint $table) { + $table->increments('id'); + $table->decimal('price', 12, 4)->default(0); + $table->date('rule_date'); $table->datetime('starts_from')->nullable(); $table->datetime('ends_till')->nullable(); - $table->timestamps(); + + $table->integer('product_id')->unsigned(); + $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade'); + + $table->integer('customer_group_id')->unsigned(); + $table->foreign('customer_group_id')->references('id')->on('customer_groups')->onDelete('cascade'); + + $table->integer('catalog_rule_id')->unsigned(); + $table->foreign('catalog_rule_id')->references('id')->on('catalog_rules')->onDelete('cascade'); + + $table->integer('channel_id')->unsigned(); + $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); }); } @@ -37,6 +41,6 @@ class CreateCatalogRuleProductsPriceTable extends Migration */ public function down() { - Schema::dropIfExists('catalog_rule_products_price'); + Schema::dropIfExists('catalog_rule_product_prices'); } } diff --git a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleIndex.php b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleIndex.php new file mode 100644 index 000000000..3d8336caf --- /dev/null +++ b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleIndex.php @@ -0,0 +1,138 @@ +catalogRuleRepository = $catalogRuleRepository; + + $this->catalogRuleProductHelper = $catalogRuleProductHelper; + + $this->catalogRuleProductPriceHelper = $catalogRuleProductPriceHelper; + } + + /** + * Full reindex + * + * @return void + */ + public function reindexComplete() + { + try { + $this->cleanIndexes(); + + foreach ($this->getCatalogRules() as $rule) { + $this->catalogRuleProductHelper->insertRuleProduct($rule); + } + + $this->catalogRuleProductPriceHelper->indexRuleProductPrice(1000); + } catch (\Exception $e) { + + } + } + + /** + * Full reindex + * + * @param Product $product + * @return void + */ + public function reindexProduct($product) + { + try { + $productIds = []; + + if ($product->type == 'configurable') { + $productIds = $product->variants()->pluck('id')->toArray(); + } else { + $productIds[] = $product->id; + } + + $this->cleanIndexes($productIds); + + foreach ($this->getCatalogRules() as $rule) { + $this->catalogRuleProductHelper->insertRuleProduct($rule, 1000, $product); + } + + $this->catalogRuleProductPriceHelper->indexRuleProductPrice(1000, $product); + } catch (\Exception $e) { + + } + } + + /** + * Deletes catalog rule product and catalog rule product price indexes + * + * @param array $productIds + * @return void + */ + public function cleanIndexes($productIds = []) + { + $this->catalogRuleProductHelper->cleanProductIndex($productIds); + + $this->catalogRuleProductPriceHelper->cleanProductPriceIndex($productIds); + } + + /** + * Returns catalog rules + * + * @return Collection + */ + public function getCatalogRules() + { + static $catalogRules; + + if ($catalogRules) + return $catalogRules; + + $catalogRules = $this->catalogRuleRepository->scopeQuery(function($query) { + return $query->where(function ($query1) { + $query1->where('catalog_rules.starts_from', '<=', Carbon::now()->format('Y-m-d'))->orWhereNull('catalog_rules.starts_from'); + }) + ->where(function ($query2) { + $query2->where('catalog_rules.ends_till', '>=', Carbon::now()->format('Y-m-d'))->orWhereNull('catalog_rules.ends_till'); + }) + ->orderBy('sort_order', 'asc'); + })->findWhere(['status' => 1]); + + return $catalogRules; + } +} \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php new file mode 100644 index 000000000..31a046554 --- /dev/null +++ b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php @@ -0,0 +1,236 @@ +attributeRepository = $attributeRepository; + + $this->productRepository = $productRepository; + + $this->catalogRuleProductRepository = $catalogRuleProductRepository; + + $this->validator = $validator; + } + + /** + * Collect discount on cart + * + * @param CatalogRule $rule + * @param integer $batchCount + * @return void + */ + public function insertRuleProduct($rule, $batchCount = 1000, $product = null) + { + $productIds = $this->getMatchingProductIds($rule, $product); + + $rows = []; + + $startsFrom = $rule->starts_from ? Carbon::createFromTimeString($rule->starts_from . " 00:00:01") : null; + + $endsTill = $rule->ends_till ? Carbon::createFromTimeString($rule->ends_till . " 23:59:59") : null; + + foreach ($productIds as $productId) { + foreach ($rule->channels()->pluck('id') as $channelId) { + foreach ($rule->customer_groups()->pluck('id') as $customerGroupId) { + $rows[] = [ + 'starts_from' => $startsFrom, + 'ends_till' => $endsTill, + 'catalog_rule_id' => $rule->id, + 'channel_id' => $channelId, + 'customer_group_id' => $customerGroupId, + 'product_id' => $productId, + 'discount_amount' => $rule->discount_amount, + 'action_type' => $rule->action_type, + 'end_other_rules' => $rule->end_other_rules, + 'sort_order' => $rule->sort_order, + ]; + + if (count($rows) == $batchCount) { + $this->catalogRuleProductRepository->getModel()->insert($rows); + + $rows = []; + } + } + } + } + + if (! empty($rows)) + $this->catalogRuleProductRepository->getModel()->insert($rows); + } + + /** + * Get array of product ids which are matched by rule + * + * @param CatalogRule $rule + * @param Product $product + * @return array + */ + public function getMatchingProductIds($rule, $product = null) + { + $qb = $this->productRepository->scopeQuery(function($query) use($rule, $product) { + $qb = $query->distinct() + ->addSelect('products.*') + ->leftJoin('product_flat', 'products.id', '=', 'product_flat.product_id') + ->leftJoin('channels', 'product_flat.channel', '=', 'channels.code') + ->where('product_flat.status', 1) + ->whereIn('channels.id', $rule->channels()->pluck('id')->toArray()); + + if ($product) + $qb->where('products.id', $product->id); + + foreach ($rule->conditions as $condition) { + if (! $condition['attribute'] || ! $condition['value']) + continue; + + $chunks = explode('|', $condition['attribute']); + + $qb = $this->addAttributeToSelect(end($chunks), $qb); + } + + return $qb; + }); + + $validatedProductIds = []; + + foreach ($qb->get() as $product) { + if ($this->validator->validate($rule, $product)) { + if ($product->type == 'configurable') { + $validatedProductIds = array_merge($validatedProductIds, $product->variants()->pluck('id')->toArray()); + } else { + $validatedProductIds[] = $product->id; + } + } + } + + return array_unique($validatedProductIds); + } + + /** + * Add product attribute condition to query + * + * @param string $attributeCode + * @param QueryBuilder $query + * @return QueryBuilder + */ + public function addAttributeToSelect($attributeCode, $query) + { + $attribute = $this->attributeRepository->findOneByField('code', $attributeCode); + + if (! $attribute) + return $query; + + $query = $query->leftJoin('product_attribute_values as ' . 'pav_' . $attribute->code, function($qb) use($attribute) { + $qb = $qb->where('pav_' . $attribute->code . '.channel', $attribute->value_per_channel ? core()->getDefaultChannelCode() : null) + ->where('pav_' . $attribute->code . '.locale', $attribute->value_per_locale ? app()->getLocale() : null); + + $qb->on('products.id', 'pav_' . $attribute->code . '.product_id') + ->where('pav_' . $attribute->code . '.attribute_id', $attribute->id); + }); + + $query = $query->addSelect('pav_' . $attribute->code . '.' . ProductAttributeValue::$attributeTypeFields[$attribute->type] . ' as ' . $attribute->code); + + return $query; + } + + /** + * Returns catalog rule products + * + * @param Product $product + * @return Collection + */ + public function getCatalogRuleProducts($product = null) + { + $results = $this->catalogRuleProductRepository->scopeQuery(function($query) use($product) { + $qb = $query->distinct() + ->select('catalog_rule_products.*') + ->leftJoin('product_flat', 'catalog_rule_products.product_id', '=', 'product_flat.product_id') + ->where('product_flat.status', 1) + ->addSelect('product_flat.price') + ->orderBy('channel_id', 'asc') + ->orderBy('customer_group_id', 'asc') + ->orderBy('product_id', 'asc') + ->orderBy('catalog_rule_id', 'asc'); + + if ($product) { + if ($product->type == 'configurable') { + $qb->whereIn('catalog_rule_products.product_id', $product->variants()->pluck('id')->toArray()); + } else { + $qb->where('catalog_rule_products.product_id', $product->id); + } + } + + return $qb; + })->get(); + + return $results; + } + + /** + * Returns catalog rules + * + * @param CatalogRule $rule + * @return void + */ + public function cleanProductIndex($productIds = []) + { + if (count($productIds)) { + $this->catalogRuleProductRepository->getModel()->whereIn('product_id', $productIds)->delete(); + } else { + $this->catalogRuleProductRepository->deleteWhere([ + ['product_id', 'like', '%%'] + ]); + } + } +} \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProductPrice.php b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProductPrice.php new file mode 100644 index 000000000..358b37cd5 --- /dev/null +++ b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProductPrice.php @@ -0,0 +1,217 @@ +catalogRuleProductPriceRepository = $catalogRuleProductPriceRepository; + + $this->catalogRuleProductHelper = $catalogRuleProductHelper; + + $this->customerGroupRepository = $customerGroupRepository; + } + + /** + * Return current logged in customer + * + * @return Customer | Boolean + */ + public function getCurrentCustomer() + { + $guard = request()->has('token') ? 'api' : 'customer'; + + return auth()->guard($guard); + } + + /** + * Collect discount on cart + * + * @param integer $batchCount + * @param Product $product + * @return void + */ + public function indexRuleProductPrice($batchCount, $product = null) + { + $dates = [ + 'current' => $currentDate = Carbon::now(), + 'previous' => (clone $currentDate)->subDays('1')->setTime(23, 59, 59), + 'next' => (clone $currentDate)->addDays('1')->setTime(0, 0, 0), + ]; + + $prices = $endRuleFlags = []; + + $previousKey = null; + + $catalogRuleProducts = $this->catalogRuleProductHelper->getCatalogRuleProducts($product); + + foreach ($catalogRuleProducts as $row) { + $productKey = $row->product_id . '-' . $row->channel_id . '-' . $row->customer_group_id; + + if ($previousKey && $previousKey != $productKey) { + $endRuleFlags = []; + + if (count($prices) > $batchCount) { + $this->catalogRuleProductPriceRepository->getModel()->insert($prices); + + $prices = []; + } + } + + foreach ($dates as $key => $date) { + if ((! $row->starts_from || $date >= $row->starts_from) + && (! $row->ends_till || $date <= $row->ends_till)) + { + $priceKey = $date->getTimestamp() . '-' . $productKey; + + if (isset($endRuleFlags[$priceKey])) + continue; + + if (! isset($prices[$priceKey])) { + $prices[$priceKey] = [ + 'rule_date' => $date, + 'catalog_rule_id' => $row->catalog_rule_id, + 'channel_id' => $row->channel_id, + 'customer_group_id' => $row->customer_group_id, + 'product_id' => $row->product_id, + 'price' => $this->calculate($row), + 'starts_from' => $row->starts_from, + 'ends_till' => $row->ends_till, + ]; + } else { + $prices[$priceKey]['price'] = $this->calculate($row, $prices[$priceKey]); + + $prices[$priceKey]['starts_from'] = max($prices[$priceKey]['starts_from'], $row->starts_from); + + $prices[$priceKey]['ends_till'] = min($prices[$priceKey]['ends_till'], $row->ends_till); + } + + if ($row->end_other_rules) + $endRuleFlags[$priceKey] = true; + } + } + + $previousKey = $productKey; + } + + $this->catalogRuleProductPriceRepository->getModel()->insert($prices); + } + + /** + * Calculates product price based on rule + * + * @param array $rule + * @param Product|null $productData + * @return float + */ + public function calculate($rule, $productData = null) + { + $price = $productData && isset($productData['price']) ? $productData['price'] : $rule->price; + + switch ($rule->action_type) { + case 'to_fixed': + $price = min($rule->discount_amount, $price); + + break; + + case 'to_percent': + $price = $price * $rule->discount_amount / 100; + + break; + + case 'by_fixed': + $price = max(0, $price - $rule->discount_amount); + + break; + + case 'by_percent': + $price = $price * (1 - $rule->discount_amount / 100); + + break; + } + + return $price; + } + + /** + * Clean product price index + * + * @param array $productIds + * @return void + */ + public function cleanProductPriceIndex($productIds = []) + { + if (count($productIds)) { + $this->catalogRuleProductPriceRepository->getModel()->whereIn('product_id', $productIds)->delete(); + } else { + $this->catalogRuleProductPriceRepository->deleteWhere([ + ['product_id', 'like', '%%'] + ]); + } + } + + /** + * Get catalog rules product price for specific date, channel and customer group + * + * @param Product $product + * @return void + */ + public function getRulePrice($product) + { + if ($this->getCurrentCustomer()->check()) { + $customerGroupId = $this->getCurrentCustomer()->user()->customer_group_id; + } else { + $customerGroup = $this->customerGroupRepository->findOneByField('code', 'guest'); + + if (! $customerGroup) + return; + + $customerGroupId = $customerGroup->id; + } + + return $this->catalogRuleProductPriceRepository->findOneWhere([ + 'product_id' => $product->id, + 'channel_id' => core()->getCurrentChannel()->id, + 'customer_group_id' => $customerGroupId, + 'rule_date' => Carbon::now()->format('Y-m-d'), + ]); + } +} \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Http/Controllers/CatalogRuleController.php b/packages/Webkul/CatalogRule/src/Http/Controllers/CatalogRuleController.php new file mode 100644 index 000000000..3bcceb50f --- /dev/null +++ b/packages/Webkul/CatalogRule/src/Http/Controllers/CatalogRuleController.php @@ -0,0 +1,183 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class CatalogRuleController extends Controller +{ + /** + * Initialize _config, a default request parameter with route + * + * @param array + */ + protected $_config; + + /** + * To hold Catalog repository instance + * + * @var CatalogRuleRepository + */ + protected $catalogRuleRepository; + + /** + * CatalogRuleIndex + * + * @var CatalogRuleIndex + */ + protected $catalogRuleIndexHelper; + + /** + * Create a new controller instance. + * + * @param \Webkul\CatalogRule\Repositories\CatalogRuleRepository $catalogRuleRepository + * @param \Webkul\CatalogRule\Helpers\CatalogRuleIndex $catalogRuleIndexHelper + * @return void + */ + public function __construct( + CatalogRuleRepository $catalogRuleRepository, + CatalogRuleIndex $catalogRuleIndexHelper + ) + { + $this->_config = request('_config'); + + $this->catalogRuleRepository = $catalogRuleRepository; + + $this->catalogRuleIndexHelper = $catalogRuleIndexHelper; + } + + /** + * Display a listing of the resource. + * + * @return \Illuminate\Http\Response + */ + public function index() + { + return view($this->_config['view']); + } + + /** + * Show the form for creating a new resource. + * + * @return \Illuminate\Http\Response + */ + public function create() + { + return view($this->_config['view']); + } + + /** + * Store a newly created resource in storage. + * + * @return \Illuminate\Http\Response + */ + public function store() + { + $this->validate(request(), [ + 'name' => 'required', + 'channels' => 'required|array|min:1', + 'customer_groups' => 'required|array|min:1', + 'starts_from' => 'nullable|date', + 'ends_till' => 'nullable|date|after_or_equal:starts_from', + 'action_type' => 'required', + 'discount_amount' => 'required|numeric' + ]); + + $data = request()->all(); + + Event::fire('promotions.catalog_rule.create.before'); + + $catalogRule = $this->catalogRuleRepository->create($data); + + Event::fire('promotions.catalog_rule.create.after', $catalogRule); + + $this->catalogRuleIndexHelper->reindexComplete(); + + session()->flash('success', trans('admin::app.response.create-success', ['name' => 'Catalog Rule'])); + + return redirect()->route($this->_config['redirect']); + } + + /** + * Show the form for editing the specified resource. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function edit($id) + { + $catalogRule = $this->catalogRuleRepository->findOrFail($id); + + return view($this->_config['view'], compact('catalogRule')); + } + + /** + * Update the specified resource in storage. + * + * @param \Illuminate\Http\Request $request + * @param int $id + * @return \Illuminate\Http\Response + */ + public function update(Request $request, $id) + { + $this->validate(request(), [ + 'name' => 'required', + 'channels' => 'required|array|min:1', + 'customer_groups' => 'required|array|min:1', + 'starts_from' => 'nullable|date', + 'ends_till' => 'nullable|date|after_or_equal:starts_from', + 'action_type' => 'required', + 'discount_amount' => 'required|numeric' + ]); + + $catalogRule = $this->catalogRuleRepository->findOrFail($id); + + Event::fire('promotions.catalog_rule.update.before', $catalogRule); + + $catalogRule = $this->catalogRuleRepository->update(request()->all(), $id); + + Event::fire('promotions.catalog_rule.update.after', $catalogRule); + + $this->catalogRuleIndexHelper->reindexComplete(); + + session()->flash('success', trans('admin::app.response.update-success', ['name' => 'Catalog Rule'])); + + return redirect()->route($this->_config['redirect']); + } + + /** + * Remove the specified resource from storage. + * + * @param int $id + * @return \Illuminate\Http\Response + */ + public function destroy($id) + { + $catalogRule = $this->catalogRuleRepository->findOrFail($id); + + try { + Event::fire('promotions.catalog_rule.delete.before', $id); + + $this->catalogRuleRepository->delete($id); + + Event::fire('promotions.catalog_rule.delete.after', $id); + + session()->flash('success', trans('admin::app.response.delete-success', ['name' => 'Catalog Rule'])); + + return response()->json(['message' => true], 200); + } catch(\Exception $e) { + session()->flash('error', trans('admin::app.response.delete-failed', ['name' => 'Catalog Rule'])); + } + + return response()->json(['message' => false], 400); + } +} \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Http/Controllers/Controller.php b/packages/Webkul/CatalogRule/src/Http/Controllers/Controller.php new file mode 100644 index 000000000..78181ceb7 --- /dev/null +++ b/packages/Webkul/CatalogRule/src/Http/Controllers/Controller.php @@ -0,0 +1,13 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class Product +{ + /** + * Product Repository Object + * + * @var Object + */ + protected $catalogRuleIndexHelper; + + /** + * Create a new listener instance. + * + * @param Webkul\CatalogRule\Helpers\CatalogRuleIndex $catalogRuleIndexHelper + * @return void + */ + public function __construct(CatalogRuleIndex $catalogRuleIndexHelper) + { + $this->catalogRuleIndexHelper = $catalogRuleIndexHelper; + } + + /** + * @param Product $product + * @return void + */ + public function createProductRuleIndex($product) + { + $this->catalogRuleIndexHelper->reindexProduct($product); + } +} \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Models/CatalogRule.php b/packages/Webkul/CatalogRule/src/Models/CatalogRule.php new file mode 100644 index 000000000..00e991506 --- /dev/null +++ b/packages/Webkul/CatalogRule/src/Models/CatalogRule.php @@ -0,0 +1,33 @@ + 'array' + ]; + + /** + * Get the channels that owns the catalog rule. + */ + public function channels() + { + return $this->belongsToMany(ChannelProxy::modelClass(), 'catalog_rule_channels'); + } + + /** + * Get the customer groups that owns the catalog rule. + */ + public function customer_groups() + { + return $this->belongsToMany(CustomerGroupProxy::modelClass(), 'catalog_rule_customer_groups'); + } +} \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Models/CatalogRuleProduct.php b/packages/Webkul/CatalogRule/src/Models/CatalogRuleProduct.php new file mode 100644 index 000000000..dfa513113 --- /dev/null +++ b/packages/Webkul/CatalogRule/src/Models/CatalogRuleProduct.php @@ -0,0 +1,13 @@ +loadMigrationsFrom(__DIR__ . '/../Database/Migrations'); + + Event::listen('catalog.product.update.after', 'Webkul\CatalogRule\Listeners\Product@createProductRuleIndex'); + } + + /** + * Register services. + * + * @return void + */ + public function register() + { + $this->registerCommands(); + } + + /** + * Register the console commands of this package + */ + protected function registerCommands() + { + if ($this->app->runningInConsole()) + $this->commands([PriceRuleIndex::class]); + } +} \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Providers/ModuleServiceProvider.php b/packages/Webkul/CatalogRule/src/Providers/ModuleServiceProvider.php new file mode 100644 index 000000000..778b8a1d9 --- /dev/null +++ b/packages/Webkul/CatalogRule/src/Providers/ModuleServiceProvider.php @@ -0,0 +1,14 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class CatalogRuleProductPriceRepository extends Repository +{ + /** + * Specify Model class name + * + * @return mixed + */ + function model() + { + return 'Webkul\CatalogRule\Contracts\CatalogRuleProductPrice'; + } +} \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Repositories/CatalogRuleProductRepository.php b/packages/Webkul/CatalogRule/src/Repositories/CatalogRuleProductRepository.php new file mode 100644 index 000000000..565781c29 --- /dev/null +++ b/packages/Webkul/CatalogRule/src/Repositories/CatalogRuleProductRepository.php @@ -0,0 +1,24 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class CatalogRuleProductRepository extends Repository +{ + /** + * Specify Model class name + * + * @return mixed + */ + function model() + { + return 'Webkul\CatalogRule\Contracts\CatalogRuleProduct'; + } +} \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Repositories/CatalogRuleRepository.php b/packages/Webkul/CatalogRule/src/Repositories/CatalogRuleRepository.php new file mode 100644 index 000000000..16a59b5ee --- /dev/null +++ b/packages/Webkul/CatalogRule/src/Repositories/CatalogRuleRepository.php @@ -0,0 +1,225 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class CatalogRuleRepository extends Repository +{ + /** + * AttributeFamilyRepository object + * + * @var AttributeFamilyRepository + */ + protected $attributeFamilyRepository; + + /** + * AttributeRepository object + * + * @var AttributeRepository + */ + protected $attributeRepository; + + /** + * CategoryRepository class + * + * @var CategoryRepository + */ + protected $categoryRepository; + + /** + * TaxCategoryRepository class + * + * @var TaxCategoryRepository + */ + protected $taxCategoryRepository; + + /** + * Create a new repository instance. + * + * @param Webkul\Attribute\Repositories\AttributeFamilyRepository $attributeFamilyRepository + * @param Webkul\Attribute\Repositories\AttributeRepository $attributeRepository + * @param Webkul\Category\Repositories\CategoryRepository $categoryRepository + * @param Webkul\Tax\Repositories\TaxCategoryRepository $taxCategoryRepository + * @param Illuminate\Container\Container $app + * @return void + */ + public function __construct( + AttributeFamilyRepository $attributeFamilyRepository, + AttributeRepository $attributeRepository, + CategoryRepository $categoryRepository, + TaxCategoryRepository $taxCategoryRepository, + App $app + ) + { + $this->attributeFamilyRepository = $attributeFamilyRepository; + + $this->attributeRepository = $attributeRepository; + + $this->categoryRepository = $categoryRepository; + + $this->taxCategoryRepository = $taxCategoryRepository; + + parent::__construct($app); + } + + /** + * Specify Model class name + * + * @return mixed + */ + function model() + { + return 'Webkul\CatalogRule\Contracts\CatalogRule'; + } + + /** + * @param array $data + * @return mixed + */ + public function create(array $data) + { + $data['starts_from'] = $data['starts_from'] ?: null; + + $data['ends_till'] = $data['ends_till'] ?: null; + + $data['status'] = ! isset($data['status']) ? 0 : 1; + + $catalogRule = parent::create($data); + + $catalogRule->channels()->sync($data['channels']); + + $catalogRule->customer_groups()->sync($data['customer_groups']); + + return $catalogRule; + } + + /** + * @param array $data + * @param array $id + * @param string $attribute + * @return mixed + */ + public function update(array $data, $id, $attribute = "id") + { + $data['starts_from'] = $data['starts_from'] ?: null; + + $data['ends_till'] = $data['ends_till'] ?: null; + + $data['status'] = ! isset($data['status']) ? 0 : 1; + + $data['conditions'] = $data['conditions'] ?? []; + + $catalogRule = $this->find($id); + + parent::update($data, $id, $attribute); + + $catalogRule->channels()->sync($data['channels']); + + $catalogRule->customer_groups()->sync($data['customer_groups']); + + return $catalogRule; + } + + /** + * Returns attributes for catalog rule conditions + * + * @return array + */ + public function getConditionAttributes() + { + $attributes = [ + [ + 'key' => 'product', + 'label' => trans('admin::app.promotions.catalog-rules.product-attribute'), + 'children' => [ + [ + 'key' => 'product|category_ids', + 'type' => 'multiselect', + 'label' => trans('admin::app.promotions.catalog-rules.categories'), + 'options' => $this->categoryRepository->getCategoryTree() + ], [ + 'key' => 'product|attribute_family_id', + 'type' => 'select', + 'label' => trans('admin::app.promotions.catalog-rules.attribute_family'), + 'options' => $this->getAttributeFamilies() + ] + ] + ] + ]; + + foreach ($this->attributeRepository->findWhereNotIn('type', ['textarea', 'image', 'file']) as $attribute) { + $attributeType = $attribute->type; + + if ($attribute->code == 'tax_category_id') { + $options = $this->getTaxCategories(); + } else { + $options = $attribute->options; + } + + if ($attribute->validation == 'decimal') + $attributeType = 'decimal'; + + if ($attribute->validation == 'numeric') + $attributeType = 'integer'; + + $attributes[0]['children'][] = [ + 'key' => 'product|' . $attribute->code, + 'type' => $attribute->type, + 'label' => $attribute->name, + 'options' => $options + ]; + } + + return $attributes; + } + + /** + * Returns all tax categories + * + * @return array + */ + public function getTaxCategories() + { + $taxCategories = []; + + foreach ($this->taxCategoryRepository->all() as $taxCategory) { + $taxCategories[] = [ + 'id' => $taxCategory->id, + 'admin_name' => $taxCategory->name, + ]; + } + + return $taxCategories; + } + + /** + * Returns all attribute families + * + * @return array + */ + public function getAttributeFamilies() + { + $attributeFamilies = []; + + foreach ($this->attributeFamilyRepository->all() as $attributeFamily) { + $attributeFamilies[] = [ + 'id' => $attributeFamily->id, + 'admin_name' => $attributeFamily->name, + ]; + } + + return $attributeFamilies; + } +} \ No newline at end of file diff --git a/packages/Webkul/Checkout/src/Cart.php b/packages/Webkul/Checkout/src/Cart.php index c640a30d0..7ac80d9fb 100755 --- a/packages/Webkul/Checkout/src/Cart.php +++ b/packages/Webkul/Checkout/src/Cart.php @@ -614,6 +614,8 @@ class Cart { if (! $cart = $this->getCart()) return false; + Event::fire('checkout.cart.collect.totals.before', $cart); + $this->calculateItemsTax(); $cart->grand_total = $cart->base_grand_total = 0; @@ -650,6 +652,8 @@ class Cart { $cart->items_qty = $quantities; $cart->save(); + + Event::fire('checkout.cart.collect.totals.after', $cart); } /** diff --git a/packages/Webkul/Core/src/Config/concord.php b/packages/Webkul/Core/src/Config/concord.php index 311ede347..24c40b47a 100644 --- a/packages/Webkul/Core/src/Config/concord.php +++ b/packages/Webkul/Core/src/Config/concord.php @@ -19,7 +19,8 @@ return [ \Webkul\Sales\Providers\ModuleServiceProvider::class, \Webkul\Tax\Providers\ModuleServiceProvider::class, \Webkul\User\Providers\ModuleServiceProvider::class, - \Webkul\Discount\Providers\ModuleServiceProvider::class, + \Webkul\CatalogRule\Providers\ModuleServiceProvider::class, + \Webkul\CartRule\Providers\ModuleServiceProvider::class, \Webkul\CMS\Providers\ModuleServiceProvider::class ] ]; \ No newline at end of file diff --git a/packages/Webkul/Discount/composer.json b/packages/Webkul/Discount/composer.json deleted file mode 100644 index 78ac3d63e..000000000 --- a/packages/Webkul/Discount/composer.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "bagisto/laravel-discount", - "license": "MIT", - "authors": [ - { - "name": "Prashant Singh", - "email": "prashant.singh852@webkul.com" - } - ], - "require": { - "propaganistas/laravel-intl": "^2.0" - }, - "autoload": { - "psr-4": { - "Webkul\\Discount\\": "src/" - } - }, - "extra": { - "laravel": { - "providers": [ - "Webkul\\Discount\\DiscountServiceProvider" - ], - "aliases": {} - } - }, - "minimum-stability": "dev" -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Actions/Cart/Action.php b/packages/Webkul/Discount/src/Actions/Cart/Action.php deleted file mode 100644 index 2bcacf39d..000000000 --- a/packages/Webkul/Discount/src/Actions/Cart/Action.php +++ /dev/null @@ -1,98 +0,0 @@ -matchedItems = collect(); - } - - abstract public function calculate($rule); - - /** - * To find the eligble items for the current rule, - * - * @param CartRule $rule - * @return Collection $matchedItems - */ - public function getEligibleItems() - { - $rule = $this->rule; - - $cart = \Cart::getCart(); - - $items = $cart->items()->get(); - - if ($this->rule->action_type == 'whole_cart_to_percent' || $this->rule->action_type == 'whole_cart_to_fixed_amount') - $this->matchedItems = $items; - - if (! $rule->uses_attribute_conditions) { - $this->matchedItems = $items; - - return $this->matchedItems; - } else { - $productIDs = explode(',', $rule->product_ids); - - foreach ($items as $item) { - foreach ($productIDs as $productID) { - $childrens = $item->children; - - foreach ($childrens as $children) { - if ($children->product_id == $productID) - $this->matchedItems->push($children); - } - - if ($item->product_id == $productID) - $this->matchedItems->push($item); - } - } - - return $this->matchedItems; - } - } - - /** - * To check the items applicability - */ - public function checkApplicability() - { - $rule = $this->rule; - - $eligibleItems = $this->getEligibleItems($rule); - - $apply = function () use($rule, $eligibleItems) { - if ($rule->action_type == 'percent_of_product') { - return true; - } else { - if ($rule->action_type == 'whole_cart_to_percent' && $rule->uses_attribute_condition) { - $matchingIds = explode(',', $rule->product_ids); - - foreach ($matchingIds as $matchingId) { - foreach ($eligibleItems as $item) { - if (($item->child ? $item->child->product_id : $item->product_id) == $matchingId) - return true; - } - } - - return false; - } else { - return true; - } - } - }; - - return $apply(); - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Actions/Cart/FixedAmount.php b/packages/Webkul/Discount/src/Actions/Cart/FixedAmount.php deleted file mode 100644 index db3907920..000000000 --- a/packages/Webkul/Discount/src/Actions/Cart/FixedAmount.php +++ /dev/null @@ -1,87 +0,0 @@ -rule = $rule; - } - - public function calculate($rule) - { - $impact = collect(); - - $totalDiscount = 0; - - if ($this->checkApplicability()) { - $eligibleItems = $this->getEligibleItems(); - - foreach ($eligibleItems as $item) { - $report = array(); - $report['item_id'] = $item->id; - $report['child_items'] = collect(); - - $itemPrice = $item->base_price; - - $itemQuantity = $item->quantity; - - $discQuantity = $rule->disc_quantity; - $discQuantity = $itemQuantity <= $discQuantity ? $itemQuantity : $discQuantity; - - if ($item->product->getTypeInstance()->isComposite()) { - $isQtyZero = true; - - foreach ($item->children as $children) { - if ($children->quantity > 0) - $isQtyZero = false; - } - - if ($isQtyZero) { - // case for configurable products - $report['product_id'] = $item->children->first()->product_id; - } else { - // composites other than configurable - $report['product_id'] = $item->product_id; - - foreach ($item->children as $children) { - $childBaseTotal = $children->base_total; - - $itemDiscount = $childBaseTotal / ($item->base_total / 100); - - $children->discount = ($itemDiscount / 100) * $rule->disc_amount; - - $children->discount = $children->base_total > $children->discount ? $children->discount : $children->base_total; - - $report['child_items']->push($children); - } - } - } else { - $report['product_id'] = $item->product_id; - } - - $discount = round($rule->disc_amount, 4) * $discQuantity; - $discount = $discount <= $itemPrice * $discQuantity ? $discount : $itemPrice * $discQuantity; - - $report['discount'] = $discount; - $report['formatted_discount'] = core()->currency($discount); - - $impact->push($report); - - $totalDiscount = $totalDiscount + $discount; - - unset($report); - } - } - - $impact->discount = $totalDiscount; - $impact->formatted_discount = core()->currency($impact->discount); - - return $impact; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Actions/Cart/PercentOfProduct.php b/packages/Webkul/Discount/src/Actions/Cart/PercentOfProduct.php deleted file mode 100644 index a21db2d8f..000000000 --- a/packages/Webkul/Discount/src/Actions/Cart/PercentOfProduct.php +++ /dev/null @@ -1,102 +0,0 @@ -rule = $rule; - } - - /** - * To calculate impact of cart rule's action of current items of cart instance - * - * @param CartRule $rule - * - * @return boolean - */ - public function calculate($rule) - { - $impact = collect(); - - $totalDiscount = 0; - - $applicability = $this->checkApplicability(); - - if ($applicability) { - $eligibleItems = $this->getEligibleItems(); - - foreach ($eligibleItems as $item) { - $report = array(); - - $report['item_id'] = $item->id; - $report['child_items'] = collect(); - - $itemPrice = $item->base_price; - $itemQuantity = $item->quantity; - - $discQuantity = $this->rule->disc_quantity; - $discQuantity = $itemQuantity <= $discQuantity ? $itemQuantity : $discQuantity; - - $discountAmount = ($this->rule->disc_amount > 100) ? 100 : $this->rule->disc_amount; - - $discount = $itemPrice * ($discountAmount / 100) * $discQuantity; - $discount = $discount <= $itemPrice * $discQuantity ? $discount : $itemPrice * $discQuantity; - - if ($item->product->getTypeInstance()->isComposite()) { - $isQtyZero = true; - - foreach ($item->children as $children) { - if ($children->quantity > 0) - $isQtyZero = false; - } - - if ($isQtyZero) { - // case for configurable products - $report['product_id'] = $item->children->first()->product_id; - } else { - // composites other than configurable - $report['product_id'] = $item->product_id; - - foreach ($item->children as $children) { - $childBaseTotal = $children->base_total; - - $itemDiscount = $childBaseTotal / ($item->base_total / 100); - - $children->discount = ($itemDiscount / 100) * ($item->base_total * ($this->rule->disc_amount / 100)); - - $children->discount = $children->base_total > $children->discount ? $children->discount : $children->base_total; - - $report['child_items']->push($children); - } - } - } else { - $report['product_id'] = $item->product_id; - } - - $report['discount'] = $discount; - - $report['formatted_discount'] = core()->currency($discount); - - $impact->push($report); - - $totalDiscount = $totalDiscount + $discount; - - unset($report); - } - - $impact->discount = $totalDiscount; - $impact->formatted_discount = core()->currency($impact->discount); - - return $impact; - } - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Actions/Cart/WholeCartToFixed.php b/packages/Webkul/Discount/src/Actions/Cart/WholeCartToFixed.php deleted file mode 100644 index 7fbc39cd4..000000000 --- a/packages/Webkul/Discount/src/Actions/Cart/WholeCartToFixed.php +++ /dev/null @@ -1,24 +0,0 @@ -calculate($rule); - - return $result; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Actions/Cart/WholeCartToPercent.php b/packages/Webkul/Discount/src/Actions/Cart/WholeCartToPercent.php deleted file mode 100644 index ffd334370..000000000 --- a/packages/Webkul/Discount/src/Actions/Cart/WholeCartToPercent.php +++ /dev/null @@ -1,24 +0,0 @@ -calculate($rule); - - return $result; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Actions/Catalog/Action.php b/packages/Webkul/Discount/src/Actions/Catalog/Action.php deleted file mode 100644 index ddd2ddc56..000000000 --- a/packages/Webkul/Discount/src/Actions/Catalog/Action.php +++ /dev/null @@ -1,8 +0,0 @@ -discount_amount; - $price = $product->price; - - if ($discountAmount <= $price) { - $discount = $price - $discountAmount; - - return $discount; - } else { - return $price; - } - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Actions/Catalog/AdjustToPercent.php b/packages/Webkul/Discount/src/Actions/Catalog/AdjustToPercent.php deleted file mode 100644 index 6c085a63a..000000000 --- a/packages/Webkul/Discount/src/Actions/Catalog/AdjustToPercent.php +++ /dev/null @@ -1,19 +0,0 @@ -discount_amount; - - $price = $product->price; - - $discount = ($discountAmount / 100) * $price; - - return $discount; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Actions/Catalog/FixedAmount.php b/packages/Webkul/Discount/src/Actions/Catalog/FixedAmount.php deleted file mode 100644 index d37f65df9..000000000 --- a/packages/Webkul/Discount/src/Actions/Catalog/FixedAmount.php +++ /dev/null @@ -1,20 +0,0 @@ -discount_amount; - $price = $product->price; - - if ($discountAmount <= $price) { - return $discountAmount; - } else { - return $price; - } - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Actions/Catalog/PercentOfOriginal.php b/packages/Webkul/Discount/src/Actions/Catalog/PercentOfOriginal.php deleted file mode 100644 index 4fc7c0408..000000000 --- a/packages/Webkul/Discount/src/Actions/Catalog/PercentOfOriginal.php +++ /dev/null @@ -1,19 +0,0 @@ -discount_amount; - - $price = $product->price; - - $discount = ($discountAmount / 100) * $price; - - return $discount; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Config/discount-rules.php b/packages/Webkul/Discount/src/Config/discount-rules.php deleted file mode 100644 index 7f33b90e5..000000000 --- a/packages/Webkul/Discount/src/Config/discount-rules.php +++ /dev/null @@ -1,18 +0,0 @@ - [ - 'fixed_amount' => 'Webkul\Discount\Actions\Cart\FixedAmount', - 'percent_of_product' => 'Webkul\Discount\Actions\Cart\PercentOfProduct', - 'whole_cart_to_fixed' => 'Webkul\Discount\Actions\Cart\WholeCartToFixed', - 'whole_cart_to_percent' => 'Webkul\Discount\Actions\Cart\WholeCartToPercent' - ], - - 'catalog' => [ - 'fixed_amount' => 'Webkul\Discount\Actions\Catalog\FixedAmount', - 'final_price_to_percent' => 'Webkul\Discount\Actions\Catalog\AdjustToPercent', - 'percent_of_original' => 'Webkul\Discount\Actions\Catalog\PercentOfOriginal', - 'to_discount_value' => 'Webkul\Discount\Actions\Catalog\AdjustToDiscountValue' - ] -]; \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Config/rule-conditions.php b/packages/Webkul/Discount/src/Config/rule-conditions.php deleted file mode 100644 index f12629492..000000000 --- a/packages/Webkul/Discount/src/Config/rule-conditions.php +++ /dev/null @@ -1,174 +0,0 @@ - [ - 'all_are_true' => 'All conditions are true', - 'any_is_true' => 'Any condition is true', - ], - - 'cart' => [ - 'actions' => [ - 'fixed_amount' => 'Apply as fixed amount', - 'percent_of_product' => 'Percentage of product', - 'whole_cart_to_fixed' => 'Adjust whole cart to fixed amount', - 'whole_cart_to_percent' => 'Adjust whole cart to percent' - ], - - 'validation' => [ - 0 => 'percent_of_product', - 1 => 'fixed_amount', - 2 => 'whole_cart_to_percent', - 3 => 'whole_cart_to_fixed' - ], - - 'conditions' => [ - 'numeric' => [ - '=' => 'Equals', - '>=' => 'Greater or equals', - '<=' => 'Lesser or equals', - '>' => 'Greater than', - '<' => 'Lesser than' - ], - - 'string' => [ - '=' => 'Equals', - // '>=' => 'Greater or equals', - // '<=' => 'Lesser or equals', - // '>' => 'Greater than', - // '<' => 'Lesser than', - '{}' => 'Contains', - '!{}' => 'Does not contains' - ], - - 'boolean' => [ - 0 => 'True/Yes', - 1 => 'False/No' - ], - - 'symbols' => [ - '=' => 'equals', - '>=' => 'greater_or_equals', - '<=' => 'lesser_or_equals', - '>' => 'greater_than', - '<' => 'lesser_than', - '{}' => 'contains', - '={}' => 'is_one_of', - '!={}' => 'is_not_one_of', - '!{}' => 'does_not_contains' - ] - ], - - 'attributes' => [ - 0 => [ - 'code' => 'sub_total', - 'name' => 'Sub Total', - 'type' => 'numeric' - ], - 1 => [ - 'code' => 'total_items', - 'name' => 'Total Items', - 'type' => 'numeric' - ], - 2 => [ - 'code' => 'total_weight', - 'name' => 'Total Weight', - 'type' => 'numeric' - ], - 3 => [ - 'code' => 'shipping_method', - 'name' => 'Shipping Method', - 'type' => 'string' - ], - 4 => [ - 'code' => 'payment_method', - 'name' => 'Payment Method', - 'type' => 'string' - ], - 5 => [ - 'code' => 'shipping_postcode', - 'name' => 'Shipping Postcode', - 'type' => 'string' - ], - 6 => [ - 'code' => 'shipping_state', - 'name' => 'Shipping State', - 'type' => 'string' - ], - 7 => [ - 'code' => 'shipping_country', - 'name' => 'Shipping Country', - 'type' => 'string' - ], - 8 => [ - 'code' => 'shipping_city', - 'name' => 'Shipping City', - 'type' => 'string' - ] - ] - ], - - 'catalog' => [ - 'actions' => [ - 'percent_of_original' => 'Percentage of product', - 'fixed_amount' => 'Apply as fixed amount', - 'final_price_to_percent' => 'Adjust price to percentage', - 'to_discount_value' => 'Adjust price to given amount' - ], - - 'validation' => [ - 0 => 'percent_of_product', - 1 => 'fixed_amount', - 2 => 'buy_a_get_b', - 3 => 'fixed_amount_cart' - ], - - 'conditions' => [ - 'numeric' => [ - '=' => 'Equals', - '>=' => 'Greater or equals', - '<=' => 'Lesser or equals', - '>' => 'Greater than', - '<' => 'Lesser than', - ], - - 'string' => [ - '=' => 'Equals', - '>=' => 'Greater or equals', - '<=' => 'Lesser or equals', - '>' => 'Greater than', - '<' => 'Lesser than', - '{}' => 'Contains', - '!{}' => 'Does not contains' - ], - - 'select' => [ - '=' => 'Equals', - '{}' => 'Contains', - '!{}' => 'Does not contains' - ], - - 'multiselect' => [ - '=' => 'Equals', - '{}' => 'Contains', - '!{}' => 'Does not contains' - ], - - 'boolean' => [ - 0 => 'True/Yes', - 1 => 'False/No' - ], - - 'symbols' => [ - '=' => 'equals', - '>=' => 'greater_or_equals', - '<=' => 'lesser_or_equals', - '>' => 'greater_than', - '<' => 'lesser_than', - '{}' => 'contains', - '={}' => 'is_one_of', - '!={}' => 'is_not_one_of', - '!{}' => 'does_not_contains' - ] - ] - ] -]; \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Contracts/CartRule.php b/packages/Webkul/Discount/src/Contracts/CartRule.php deleted file mode 100644 index c6da453eb..000000000 --- a/packages/Webkul/Discount/src/Contracts/CartRule.php +++ /dev/null @@ -1,7 +0,0 @@ -increments('id'); - $table->integer('channel_id')->unsigned()->nullable(); - $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); - $table->integer('locale_id')->unsigned()->nullable(); - $table->foreign('locale_id')->references('id')->on('locales')->onDelete('cascade'); - $table->integer('cart_rule_id')->unsigned()->nullable(); - $table->foreign('cart_rule_id')->references('id')->on('cart_rules')->onDelete('cascade'); - $table->text('label')->nullable(); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('cart_rule_labels'); - } -} diff --git a/packages/Webkul/Discount/src/Database/Migrations/2019_05_24_113949_create_cart_rule_coupons_usage_table.php b/packages/Webkul/Discount/src/Database/Migrations/2019_05_24_113949_create_cart_rule_coupons_usage_table.php deleted file mode 100644 index 60f23900e..000000000 --- a/packages/Webkul/Discount/src/Database/Migrations/2019_05_24_113949_create_cart_rule_coupons_usage_table.php +++ /dev/null @@ -1,39 +0,0 @@ -increments('id'); - $table->integer('coupon_id')->unsigned(); - $table->foreign('coupon_id')->references('id')->on('cart_rules')->onDelete('cascade'); - $table->integer('channel_id')->unsigned(); - $table->foreign('channel_id')->references('id')->on('channels')->onDelete('cascade'); - $table->integer('customer_id')->unsigned(); - $table->foreign('customer_id')->references('id')->on('customers')->onDelete('cascade'); - $table->bigInteger('usage')->unsigned()->default(0); - $table->date('expired_on'); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('cart_rule_coupons_usage'); - } -} diff --git a/packages/Webkul/Discount/src/Database/Migrations/2019_06_25_110122_remove_is_guest_from_cart_rules_table.php b/packages/Webkul/Discount/src/Database/Migrations/2019_06_25_110122_remove_is_guest_from_cart_rules_table.php deleted file mode 100644 index a34fe12d9..000000000 --- a/packages/Webkul/Discount/src/Database/Migrations/2019_06_25_110122_remove_is_guest_from_cart_rules_table.php +++ /dev/null @@ -1,32 +0,0 @@ -dropColumn('is_guest'); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::table('cart_rules', function (Blueprint $table) { - $table->boolean('is_guest')->default(0); - }); - } -} diff --git a/packages/Webkul/Discount/src/Helpers/Cart/ConvertXToProductId.php b/packages/Webkul/Discount/src/Helpers/Cart/ConvertXToProductId.php deleted file mode 100644 index 9c49d609b..000000000 --- a/packages/Webkul/Discount/src/Helpers/Cart/ConvertXToProductId.php +++ /dev/null @@ -1,292 +0,0 @@ -category = $category; - - $this->attribute = $attributeRepository; - - $this->product = $product; - - $this->attributeOptionRepository = $attributeOptionRepository; - - $this->cartRule = $cartRule; - - $this->pav = $pav; - - $this->conditionSymbols = config('pricerules.cart.conditions.symbols'); - } - - /** - * Collects the attribute and category conditions - * - * @param Integer $ruleId - * - * @param Object $attrribute_conditions - */ - public function convertX($ruleId, $attribute_conditions) - { - $attributeConditions = $attribute_conditions; - - $categoryValues = $attributeConditions->categories ?? null; - - $attributeValues = $attributeConditions->attributes ?? null; - - if (! isset($categoryValues) && ! isset($attributeValues)) - return false; - - $categoryResult = collect(); - - if (isset($categoryValues) && count($categoryValues)) - $categoryResult = $this->convertFromCategories($categoryValues); - - $attributeResult = collect(); - - if (isset($attributeValues) && count($attributeValues)) - $attributeResult = $this->convertFromAttributes($attributeValues); - - // now call the function that will find all the unique product ids - $productIDs = $this->findAllUniqueIds($attributeResult, $categoryResult); - - // save the product ids against the cart rules - return $this->saveIDs($ruleId, $productIDs) ? true : false; - } - - /** - * This method will return product id from the attribute and attribute option params - * - * @return array - */ - public function convertFromAttributes($attributeOptions) - { - $products = collect(); - - foreach ($attributeOptions as $attributeOption) { - $selectedOptions = $attributeOption->value; - - if ($attributeOption->type == 'select' || $attributeOption->type == 'multiselect') { - $attribute = $this->attribute->findWhere(['code' => $attributeOption->attribute]); - - $attributeOptions = $attribute->first()->options; - - $selectedAttributeOptions = collect(); - - foreach ($attributeOptions as $attributeOption) { - foreach ($selectedOptions as $key => $value) { - if ($attributeOption->id == $value) - $selectedAttributeOptions->push($attributeOption); - } - } - - foreach($selectedAttributeOptions as $selectedAttributeOption) { - $typeColumn = $this->pav::$attributeTypeFields[$attribute->first()->type]; - - $pavResults = $this->pav->where( - "{$typeColumn}", $selectedAttributeOption->id - )->get(); - - foreach ($pavResults as $pavResult) { - if ($pavResult->product->type == 'simple') - $products->push($pavResult->product); - } - } - } else { - $attribute = $this->attribute->findWhere([ - 'code' => $attributeOption->attribute - ]); - - $pavValues = $attribute->first(); - - $selectedAttributeValues = collect(); - - $foundProducts = collect(); - - if ($attributeOption->attribute == 'sku') { - $testValue = $attributeOption->value; - $testCondition = $attributeOption->condition; - - if ($testCondition == '{}') { - $foundProducts = $this->product->findWhere([ - ['sku', 'like', '%'.$testValue.'%'], - ])->flatten()->all(); - } else if ($testCondition == '!{}') { - $foundProducts = $this->product->findWhere([ - ['sku', 'not like', '%'.$testValue.'%'], - ])->flatten()->all(); - } else if ($testCondition == '=') { - $foundProducts = $this->product->findWhere([ - ['sku', '=', $testValue], - ])->flatten()->all(); - } - } - - foreach($foundProducts as $foundProduct) { - $products->push($foundProduct); - } - } - } - - return $products; - } - - /** - * This method will return product id from the attribute and attribute option params - * - * @param Collection $categories - * - * @return array - */ - public function convertFromCategories($categories) - { - $products = collect(); - - foreach ($categories as $category) { - $data = $this->getAll($category->id); - - if ($data->count()) { - $products->push($data); - - unset($data); - } - } - - return $products->flatten()->all(); - } - - /** - * This method will remove the duplicates from the array and merge all the items into single array - * - * @param array - * - * @return array - */ - public function findAllUniqueIds(...$data) - { - $attributeResult = $data[0] ?? collect(); - $categoryResult = $data[1] ?? collect(); - - // find matched attribute options product ids - $mergedCollection = $attributeResult->merge($categoryResult); - - $productIDs = collect(); - - foreach ($mergedCollection as $merged) { - $productIDs->push($merged->id); - } - - // find all the unique product ids - return $productIDs->unique()->flatten()->all(); - } - - /** - * This method will save the product ids in the datastore - * - * @param integer $ruleId - * - * @param array $productIDs - * - * @return boolean - */ - public function saveIDs($ruleId, $productIDs) - { - $cartRule = $this->cartRule->find($ruleId); - - $productIDs = implode(',', $productIDs); - - return $cartRule->update(['product_ids' => $productIDs]); - } - - /** - * To get all product ids lying in the criteria - * - * @param integer $categoryId - * - * @return Collection - */ - public function getAll($categoryId = null) - { - return app('Webkul\Product\Repositories\ProductFlatRepository')->scopeQuery(function($query) use($categoryId) { - $channel = request()->get('channel') ?: (core()->getCurrentChannelCode() ?: core()->getDefaultChannelCode()); - - $locale = request()->get('locale') ?: app()->getLocale(); - - $qb = $query->distinct() - ->addSelect('product_flat.*') - ->leftJoin('products', 'product_flat.product_id', '=', 'products.id') - ->leftJoin('product_categories', 'products.id', '=', 'product_categories.product_id') - ->where('product_flat.channel', $channel) - ->where('product_flat.locale', $locale) - ->whereNotNull('product_flat.url_key'); - - if ($categoryId) - $qb->where('product_categories.category_id', $categoryId); - - $qb->where('product_flat.status', 1); - - $qb->where('product_flat.visible_individually', 1); - - $queryBuilder = $qb->leftJoin('product_flat as flat_variants', function($qb) use($channel, $locale) { - $qb->on('product_flat.id', '=', 'flat_variants.parent_id') - ->where('flat_variants.channel', $channel) - ->where('flat_variants.locale', $locale); - }); - - $qb = $qb->leftJoin('products as variants', 'products.id', '=', 'variants.parent_id'); - - return $qb->groupBy('product_flat.id'); - })->get(); - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Helpers/Cart/CouponAbleRule.php b/packages/Webkul/Discount/src/Helpers/Cart/CouponAbleRule.php deleted file mode 100644 index 892bcd14e..000000000 --- a/packages/Webkul/Discount/src/Helpers/Cart/CouponAbleRule.php +++ /dev/null @@ -1,57 +0,0 @@ -validateIfAlreadyApplied(); - - $rules = $this->getApplicableRules($code); - - if ($rules->count() == 1) { - $rule = $rules->first(); - - $canApply = $this->canApply($rule); - - if ($canApply) { - $this->save($rule); - - $this->updateCartItemAndCart($rule); - - return true; - } - } else { - return false; - } - - return false; - } - - /** - * Removes the already applied coupon on the current cart instance - * - * @return boolean - */ - public function remove() - { - $cart = Cart::getCart(); - - $existingRule = $this->cartRuleCart->findWhere(['cart_id' => $cart->id]); - - $this->clearDiscount(); - - return true; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Helpers/Cart/Discount.php b/packages/Webkul/Discount/src/Helpers/Cart/Discount.php deleted file mode 100644 index 59436eadc..000000000 --- a/packages/Webkul/Discount/src/Helpers/Cart/Discount.php +++ /dev/null @@ -1,987 +0,0 @@ -cartRule = $cartRule; - - $this->cartRuleCart = $cartRuleCart; - - $this->cartItem = $cartItem; - - $this->rules = config('discount-rules'); - } - - /** - * Abstract method apply - */ - abstract public function apply($code); - - /** - * To find all the suitable rules that can be applied on the current cart - * - * @return collection $rules - */ - public function getApplicableRules($code = null) - { - $rules = collect(); - - if ($code != null) { - $eligibleRules = $this->cartRule->findWhere(['use_coupon' => 1, 'status' => 1]); - - foreach($eligibleRules as $rule) { - if ($rule->coupons->code == $code) { - $rules->push($rule); - - break; - } - } - } else { - $rules = $this->cartRule->findWhere(['use_coupon' => 0, 'status' => 1]); - } - - $filteredRules = collect(); - - // time based constraints - foreach ($rules as $rule) { - if ($this->checkApplicability($rule)) { - if ($rule->starts_from != null && $rule->ends_till == null) { - if (Carbon::parse($rule->starts_from) < now()) { - $rule->impact = $this->calculateImpact($rule); - - $filteredRules->push($rule); - } - } else if ($rule->starts_from == null && $rule->ends_till != null) { - if (Carbon::parse($rule->ends_till) > now()) { - $rule->impact = $this->calculateImpact($rule); - - $filteredRules->push($rule); - } - } else if ($rule->starts_from != null && $rule->ends_till != null) { - if (Carbon::parse($rule->starts_from) < now() && now() < Carbon::parse($rule->ends_till)) { - $rule->impact = $this->calculateImpact($rule); - - $filteredRules->push($rule); - } - } else { - $rule->impact = $this->calculateImpact($rule); - - $filteredRules->push($rule); - } - } - } - - return $filteredRules; - } - - /** - * To find that one rule that is going to be applied on the current cart - * - * @param Collection $rules - * - * @return CartRule $rule - */ - public function breakTie($rules) - { - $result = $this->sortByLeastPriority($rules); - - if (count($result) > 1) { - // check for max impact criteria - if (count($result) > 1) { - $result = $this->findMaxImpact($result); - - if (count($result) > 1) { - $result = $this->findOldestRule($result); - - return $result; - } else if (count($result) == 1) { - return $result->first(); - } else { - return collect(); - } - } else if (count($result) == 1) { - return $result->first(); - } else { - return collect(); - } - } else if (count($result) == 1) { - return $result->first(); - } else { - return collect(); - } - - return collect(); - } - - /** - * To find the oldes rule - * - * @param Collection $rules - * - * @return CartRule $oldestRule - */ - public function findOldestRule($rules) - { - $leastID = 999999999999; - - foreach ($rules as $index => $rule) { - if ($rule->id < $leastID) { - $leastID = $rule->id; - $oldestRule = $rule; - } - } - - return $oldestRule; - } - - /** - * To sort the rules by the least priority - * - * @param Collection $rules - * - * @return Collection $rule - */ - public function sortByLeastPriority($rules) - { - $sortedRules = collect(); - - $minPriority = $rules->min('priority'); - - foreach ($rules as $rule) { - if ($rule->priority == $minPriority) - $sortedRules->push($rule); - } - - return $sortedRules; - } - - /** - * To check where rule ends other rules - * - * @param CartRule $rule - * - * @return $rule - */ - public function isEndRule($rule) - { - if ($rule->end_other_rules) { - return true; - } else { - return false; - } - } - - /** - * To find whether rule can be applied or not - * - * @param CartRule $rule - * - * @return boolean - */ - public function canApply($rule) - { - $cart = \Cart::getCart(); - - $alreadyApplied = $this->cartRuleCart->findWhere(['cart_id' => $cart->id]); - - if ($alreadyApplied->count() && $alreadyApplied->first()->cart_rule->id == $rule->id) { - if ($this->validateRule($alreadyApplied->first()->cart_rule)) { - $this->reassess($alreadyApplied->first()->cart_rule, $cart); - - return false; - } else { - $this->clearDiscount(); - - return true; - } - } else if ($alreadyApplied->count() && $alreadyApplied->first()->cart_rule->id != $rule->id && ! $alreadyApplied->first()->cart_rule->end_other_rules) { - if ($rule->use_coupon) { - if ($alreadyApplied->first()->cart_rule->use_coupon) { - $rules = collect(); - - $alreadyAppliedRule = $alreadyApplied->first()->cart_rule; - $alreadyAppliedRule->impact = $this->calculateImpact($alreadyAppliedRule); - - $rule->impact = $this->calculateImpact($alreadyAppliedRule); - - $rules->push($alreadyAppliedRule); - $rules->push($rule); - - $result = $this->breakTie($rules); - - if ($result->id == $rule->id) { - return true; - } else { - return false; - } - } else { - return true; - } - } else { - // this case will work when non couponable rule is applied and another non couponable rule is created - // again break tie - $rules = collect(); - - $alreadyAppliedRule = $alreadyApplied->first()->cart_rule; - $alreadyAppliedRule->impact = $this->calculateImpact($alreadyAppliedRule); - - $rule->impact = $this->calculateImpact($alreadyAppliedRule); - - $rules->push($alreadyAppliedRule); - $rules->push($rule); - - $result = $this->breakTie($rules); - - if ($result) { - if ($result->id != $rule->id) { - return true; - } else { - return false; - } - } - } - } else { - return true; - } - } - - /** - * To reassess the discount in case no. of items gets changed - * - * @return Void - */ - public function reassess($rule) - { - $rule->impact = $this->calculateImpact($rule); - - $this->updateCartItemAndCart($rule); - - return $rule; - } - - /** - * To return cart rule which has the max impact - * - * @param Collection $rules - * - * @return Collection $rule - */ - public function findMaxImpact($rules) - { - $maxImpact = collect(); - - $maxDiscount = 0; - - if ($rules->count()) { - $maxDiscount = $rules->max('impact.discount'); - - foreach ($rules as $rule) { - if ($rule->impact->discount == $maxDiscount) - $maxImpact = $maxImpact->push($rule); - } - } else { - return collect(); - } - - return $maxImpact; - } - - /** - * To calculate the impact of the rule - * - * @return collection - */ - public function calculateImpact($rule) - { - $impact = $this->getActionInstance($rule); - - $outcome = $impact->calculate($rule); - - return $outcome; - } - - /** - * Return the instance of the related rule's action type - * - * @param CartRule $rule - * - * @return Object - */ - public function getActionInstance($rule) - { - $this->rules = config('discount-rules'); - - $actionType = new $this->rules['cart'][$rule->action_type]($rule); - - return $actionType; - } - - /** - * Checks whether rules is getting applied on current cart instance or not - * - * @param CartRule $rule - * - * @return Boolean - */ - public function checkApplicability($rule) - { - $cart = \Cart::getCart(); - - $timeBased = false; - - $channelBased = false; - - // time based constraints - if ($rule->starts_from != null && $rule->ends_till == null) { - if (Carbon::parse($rule->starts_from) < now()) - $timeBased = true; - } else if ($rule->starts_from == null && $rule->ends_till != null) { - if (Carbon::parse($rule->ends_till) > now()) - $timeBased = true; - } else if ($rule->starts_from != null && $rule->ends_till != null) { - if (Carbon::parse($rule->starts_from) < now() && now() < Carbon::parse($rule->ends_till)) - $timeBased = true; - } else { - $timeBased = true; - } - - // channel based constraints - foreach ($rule->channels as $channel) { - if ($channel->channel_id == core()->getCurrentChannel()->id) - $channelBased = true; - } - - $customerGroupBased = false; - - // customer groups based constraints - if (auth()->guard('customer')->check()) { - foreach ($rule->customer_groups as $customer_group) { - if (auth()->guard('customer')->user()->group->exists()) { - if ($customer_group->customer_group_id == auth()->guard('customer')->user()->group->id) - $customerGroupBased = true; - } - } - } else { - foreach ($rule->customer_groups as $customer_group) { - if ($customer_group->customer_group->code == 'guest') - $customerGroupBased = true; - } - } - - $conditionsBased = true; - - //check conditions - if ($rule->conditions != null) { - $conditions = json_decode(json_decode($rule->conditions)); - - $test_mode = array_last($conditions); - - if ($test_mode->criteria == 'any_is_true') - $conditionsBased = $this->testIfAnyConditionIsTrue($conditions, $cart); - - if ($test_mode->criteria == 'all_are_true') - $conditionsBased = $this->testIfAllConditionAreTrue($conditions, $cart); - } - - $partialMatch = 0; - - if ($rule->uses_attribute_conditions) { - $productIDs = explode(',', $rule->product_ids); - - foreach ($productIDs as $productID) { - foreach ($cart->items as $item) { - if ($item->product_id == $productID) - $partialMatch = 1; - } - } - } - - if ($channelBased && $customerGroupBased && $timeBased && $conditionsBased) { - if ($rule->uses_attribute_conditions == 1 && $partialMatch) { - return true; - } else if ($rule->uses_attribute_conditions == 0) { - return true; - } else { - return false; - } - } else { - return false; - } - } - - /** - * Save the rule in the CartRule for current cart instance - * - * @param CartRule $rule - * - * @return Boolean - */ - public function save($rule) - { - $cart = \Cart::getCart(); - - $alreadyApplied = $this->cartRuleCart->findWhere(['cart_id' => $cart->id]); - - if ($alreadyApplied->count()) { - $result = $alreadyApplied->first()->update(['cart_rule_id' => $rule->id]); - } else { - $result = $this->cartRuleCart->create(['cart_id' => $cart->id, 'cart_rule_id' => $rule->id]); - } - - return $result ? true : false; - } - - /** - * Apply on shipping - * - * @param CartRule $apploedRule - * - * @param Cart $cart - * - * @return void - */ - public function applyOnShipping($appliedRule, $cart) - { - $cart = \Cart::getCart(); - - if (isset($cart->selected_shipping_rate)) { - if ($appliedRule->free_shipping && $cart->selected_shipping_rate->base_price > 0) { - $cart->selected_shipping_rate->update(['price' => 0, 'base_price' => 0]); - } else if ($appliedRule->free_shipping == 0 && $appliedRule->apply_to_shipping && $cart->selected_shipping_rate->base_price > 0) { - $actionType = config('discount-rules')[$appliedRule->action_type]; - - if ($appliedRule->apply_to_shipping) { - $actionInstance = new $actionType; - - $discountOnShipping = $actionInstance->calculateOnShipping($cart); - - $discountOnShipping = ($discountOnShipping / 100) * $cart->selected_shipping_rate->base_price; - - $cart->selected_shipping_rate->update([ - 'price' => $cart->selected_shipping_rate->price - core()->convertPrice($discountOnShipping, $cart->cart_currency_code), - 'base_price' => $cart->selected_shipping_rate->base_price - $discountOnShipping - ]); - } - } - } - } - - /** - * Resets the shipping for the current items in the cart - * - * @param Cart $cart - * - * @return Void - */ - public function resetShipping($cart) - { - $cart = \Cart::getCart(); - - if (isset($cart->selected_shipping_rate->carrier)) { - $shippingRate = config('carriers')[$cart->selected_shipping_rate->carrier]['class']; - - $actualShippingRate = new $shippingRate; - $actualShippingRate = $actualShippingRate->calculate(); - - if (is_array($actualShippingRate)) { - foreach($actualShippingRate as $actualRate) { - if ($actualRate->method == $cart->selected_shipping_rate->method) { - $actualShippingRate = $actualRate; - - break; - } - } - } - - $actualShippingPrice = $actualShippingRate->price; - $actualShippingBasePrice = $actualShippingRate->base_price; - $cartShippingRate = $cart->selected_shipping_rate; - - $cartShippingRate->update(['price' => $actualShippingPrice, 'base_price' => $actualShippingBasePrice]); - } - } - - /** - * Update discount for least worth item - * - * @param CartRule $rule - * - * @return Boolean - */ - public function updateCartItemAndCart($rule) - { - $cart = Cart::getCart(); - - $itemImpacts = $rule->impact; - - foreach ($itemImpacts as $itemImpact) { - $item = $this->cartItem->findOneWhere(['id' => $itemImpact['item_id']]); - - if (isset($itemImpact['child_items']) && $itemImpact['child_items']->count()) { - $totalItemDiscount = 0.0000; - - foreach ($itemImpact['child_items'] as $child) { - $discount = $child->discount; - - $totalItemDiscount = $totalItemDiscount + $discount; - - unset($child->discount); - - $child->update([ - 'discount_amount' => core()->convertPrice($discount, $cart->cart_currency_code), - 'base_discount_amount' => $discount - ]); - - if ($rule->action_type == 'percent_of_product') { - $child->update(['discount_percent' => $rule->discount_amount]); - } - - if ($rule->use_coupon) { - $coupon = $rule->coupons->code; - - $child->update(['coupon_code' => $coupon]); - } - - $this->updateParent($child, $totalItemDiscount, $cartCurrencyCode = $cart->cart_currency_code); - } - } else { - $item->update([ - 'discount_amount' => core()->convertPrice($itemImpact['discount'], $cart->cart_currency_code), - 'base_discount_amount' => $itemImpact['discount'] - ]); - - if ($rule->action_type == 'percent_of_product') { - $item->update(['discount_percent' => $rule->discount_amount]); - } - - if ($rule->use_coupon) { - $coupon = $rule->coupons->code; - - $item->update(['coupon_code' => $coupon]); - } - } - } - - if ($rule->use_coupon) { - $cart->update(['coupon_code' => $rule->coupons->code]); - } - - // if ($rule->free_shipping || $rule->apply_on_shipping) { - // $this->applyOnShipping($rule); - // } - - Cart::collectTotals(); - - return true; - } - - /** - * To update the discount on parent CartItem - */ - private function updateParent($item, $discount, $currencyCode) - { - $parentItem = $this->cartItem->findOneWhere(['id' => $item->parent_id]); - - $parentItem->update([ - 'base_discount_amount' => $discount, - 'discount_amount' => core()->convertPrice($discount, $currencyCode) - ]); - } - - /** - * Removes any cart rule from the current cart instance - * - * @return Boolean - */ - public function clearDiscount() - { - $cart = Cart::getCart(); - - $cartItems = $cart->items; - - // remove all the discount properties from items - foreach ($cartItems as $item) { - $item->update([ - 'coupon_code' => NULL, - 'discount_percent' => 0, - 'discount_amount' => 0, - 'base_discount_amount' => 0 - ]); - } - - // remove all the discount properties from cart - $cart->update([ - 'coupon_code' => NULL, - 'discount_amount' => 0, - 'base_discount_amount' => 0 - ]); - - // find & remove cart rule from cart rule cart resource - $cartRuleCart = $this->cartRuleCart->findWhere(['cart_id' => $cart->id]); - - $cartRuleCart->first()->delete(); - - return true; - } - - /** - * Validate the currently applied cart rule - * - * @param CartRule $rule - * - * @return Boolean - */ - public function validateRule($rule) - { - $applicability = $this->checkApplicability($rule); - - if ($applicability && $rule->status) { - return true; - } else { - return false; - } - } - - /** - * Will validate already applied rule - * - * @return Void - */ - public function validateIfAlreadyApplied() - { - $cart = \Cart::getCart(); - - $alreadyAppliedRule = $this->cartRuleCart->findWhere(['cart_id' => $cart->id]); - - if ($alreadyAppliedRule->count()) { - $alreadyAppliedCartRule = $alreadyAppliedRule->first()->cart_rule; - - $result = $this->validateRule($alreadyAppliedCartRule); - - if (! $result) { - $this->clearDiscount(); - - $alreadyAppliedRule->first()->delete(); - } else { - $this->reassess($alreadyAppliedCartRule); - } - } - } - - /** - * Retreives all the payment methods from application config - * - * @return Array - */ - public function getPaymentMethods() - { - $paymentMethods = config('paymentmethods'); - - return $paymentMethods; - } - - /** - * Retreives all the shippin methods from the application config - * - * @return array - */ - public function getShippingMethods() - { - $shippingMethods = config('carriers'); - - return $shippingMethods; - } - - /** - * Checks the rule against the current cart instance whether rule conditions are applicable - * or not - * - * @param Array $conditions - * - * @param Cart $cart - * - * @return Boolean - */ - protected function testIfAllConditionAreTrue($conditions, $cart) - { - $paymentMethods = $this->getPaymentMethods(); - - $shippingMethods = $this->getShippingMethods(); - - array_pop($conditions); - - $shipping_address = $cart->getShippingAddressAttribute() ?? null; - - $shipping_method = $cart->selected_shipping_rate->method_title ?? null; - - $shipping_country = $shipping_address->country ?? null; - - $shipping_state = $shipping_address->state ?? null; - - $shipping_postcode = $shipping_address->postcode ?? null; - - $shipping_city = $shipping_address->city ?? null; - - $payment_method = isset($cart->payment) ? $paymentMethods[$cart->payment->method]['title'] : null; - - $sub_total = $cart->base_sub_total; - - $total_items = $cart->items_qty; - - $total_weight = 0; - - foreach ($cart->items as $item) { - $total_weight = $total_weight + $item->base_total_weight; - } - - $result = true; - - foreach ($conditions as $condition) { - $result = true; - - if (! isset($condition->attribute) || ! isset($condition->condition) || ! isset($condition->value) || ! isset($condition->type) || ! $condition->value != []) { - $result = false; - - continue; - } - - if (isset($condition->attribute)) { - $actual_value = ${$condition->attribute}; - } else { - $result = false; - } - - if (isset($condition->value)) { - $test_value = $condition->value; - - } else { - $result = false; - } - - if (isset($condition->condition)) { - $test_condition = $condition->condition; - } - else { - $result = false; - } - - if ($condition->type == 'string') { - $actual_value = strtolower($actual_value); - - $test_value = strtolower($test_value); - } - - if ($test_condition == '=') { - if ($actual_value != $test_value) { - $result = false; - - break; - } - } else if ($test_condition == '>=') { - if (! ($actual_value >= $test_value)) { - $result = false; - - break; - } - } else if ($test_condition == '<=') { - if (! ($actual_value <= $test_value)) { - $result = false; - - break; - } - } else if ($test_condition == '>') { - if (! ($actual_value > $test_value)) { - $result = false; - - break; - } - } else if ($test_condition == '<') { - if (! ($actual_value < $test_value)) { - $result = false; - - break; - } - } else if ($test_condition == '{}') { - if (! str_contains($actual_value, $test_value)) { - $result = false; - - break; - } - } else if ($test_condition == '!{}') { - if (str_contains($actual_value, $test_value)) { - $result = false; - - break; - } - } - } - - return $result; - } - - /** - * Checks the rule against the current cart instance whether rule conditions are applicable - * or not - * - * @param Array $conditions - * - * @param Cart $cart - * - * @return Boolean - */ - protected function testIfAnyConditionIsTrue($conditions, $cart) - { - $paymentMethods = $this->getPaymentMethods(); - - $shippingMethods = $this->getShippingMethods(); - - array_pop($conditions); - - $result = false; - - $shipping_address = $cart->getShippingAddressAttribute() ?? null; - - $shipping_method = $cart->selected_shipping_rate->method_title ?? null; - - $shipping_country = $shipping_address->country ?? null; - - $shipping_state = $shipping_address->state ?? null; - - $shipping_postcode = $shipping_address->postcode ?? null; - - $shipping_city = $shipping_address->city ?? null; - - $payment_method = isset($cart->payment) ? $paymentMethods[$cart->payment->method]['title'] : null; - - $sub_total = $cart->base_sub_total; - - $total_items = $cart->items_qty; - - $total_weight = 0; - - foreach($cart->items as $item) { - $total_weight = $total_weight + $item->base_total_weight; - } - - foreach ($conditions as $condition) { - if (! isset($condition->attribute) || ! isset($condition->condition) || ! isset($condition->value)) { - continue; - } - - if (isset($condition->attribute)) { - $actual_value = ${$condition->attribute}; - } else { - $result = false; - } - - if (isset($condition->value)) { - $test_value = $condition->value; - } else { - $result = false; - } - - if (isset($condition->condition)) { - $test_condition = $condition->condition; - } else { - $result = false; - } - - if ($condition->type == 'numeric' || $condition->type == 'string' || $condition->type == 'text') { - if ($condition->type == 'string') { - $actual_value = strtolower($actual_value); - - $test_value = strtolower($test_value); - } - - if ($test_condition == '=') { - if ($actual_value == $test_value) { - $result = true; - - break; - } - } else if ($test_condition == '>=') { - if ($actual_value >= $test_value) { - $result = true; - - break; - } - } else if ($test_condition == '<=') { - if ($actual_value <= $test_value) { - $result = true; - - break; - } - } else if ($test_condition == '>') { - if ($actual_value > $test_value) { - $result = true; - - break; - } - } else if ($test_condition == '<') { - if ($actual_value < $test_value) { - $result = true; - - break; - } - } else if ($test_condition == '{}') { - if (str_contains($actual_value, $test_value)) { - $result = true; - - break; - } - } else if ($test_condition == '!{}') { - if (! str_contains($actual_value, $test_value)) { - $result = true; - - break; - } - } - } - } - - return $result; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Helpers/Cart/NonCouponAbleRule.php b/packages/Webkul/Discount/src/Helpers/Cart/NonCouponAbleRule.php deleted file mode 100644 index 713cce2d4..000000000 --- a/packages/Webkul/Discount/src/Helpers/Cart/NonCouponAbleRule.php +++ /dev/null @@ -1,46 +0,0 @@ -validateIfAlreadyApplied(); - - $rules = $this->getApplicableRules(); - - if ($rules->count() == 1) { - $rule = $rules->first(); - - $canApply = $this->canApply($rule); - - if ($canApply && isset($rule->impact)) { - $result = $this->save($rule); - - $this->updateCartItemAndCart($rule); - } - } else if ($rules->count() > 1) { - $rule = $this->breakTie($rules); - - $canApply = $this->canApply($rule); - - if ($canApply) { - $this->save($rule); - - $this->updateCartItemAndCart($rule); - } - } else { - return false; - } - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Helpers/Cart/ValidatesDiscount.php b/packages/Webkul/Discount/src/Helpers/Cart/ValidatesDiscount.php deleted file mode 100644 index f6b0b68c3..000000000 --- a/packages/Webkul/Discount/src/Helpers/Cart/ValidatesDiscount.php +++ /dev/null @@ -1,26 +0,0 @@ -validateIfAlreadyApplied(); - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Helpers/Catalog/Apply.php b/packages/Webkul/Discount/src/Helpers/Catalog/Apply.php deleted file mode 100644 index 962d65389..000000000 --- a/packages/Webkul/Discount/src/Helpers/Catalog/Apply.php +++ /dev/null @@ -1,541 +0,0 @@ - @prashant-webkul - * @copyright 2019 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class Apply extends Sale -{ - /** - * To hold the catalog rule repository instance - */ - protected $catalogRule; - - /** - * To maintain the list of deceased rules and remove their records if present - */ - protected $activeRules; - - /** - * To maintain the list of deceased rules and remove their records if present - */ - protected $deceased; - - /** - * Holds convertXToProductId instance - */ - protected $convertX; - - /** - * Hold catalog rule products repository instance - */ - protected $catalogRuleProduct; - - /** - * Hold catalog rule products price repository instance - */ - protected $catalogRuleProductPrice; - - /** - * Hold ProductRepository instance - */ - protected $product; - - /** - * To hold the rule classes - */ - protected $rules; - - /** - * @param CatalogRule $catalogRule - */ - public function __construct( - CatalogRule $catalogRule, - ConvertX $convertX, - CatalogRuleProducts $catalogRuleProduct, - CatalogRuleProductsPrice $catalogRuleProductPrice, - Product $product - ) { - $this->catalogRule = $catalogRule; - - $this->convertX = $convertX; - - $this->catalogRuleProduct = $catalogRuleProduct; - - $this->catalogRuleProductPrice = $catalogRuleProductPrice; - - $this->product = $product; - - $this->active = collect(); - - $this->activeRules = collect(); - - $this->deceased = collect(); - - $this->rules = config('discount-rules.catalog'); - } - - /** - * To apply the new catalog rules and sync previous rules changes, - */ - public function apply() - { - $rules = $this->catalogRule->all(); - - foreach ($rules as $rule) { - $validated = $this->checkApplicability($rule); - - if ($validated) { - $this->active->push($rule->id); - - $this->activeRules->push($rule); - } else { - $this->deceased->push($rule->id); - } - } - - if ($this->active->count()) { - $productIDs = array(); - - foreach ($this->activeRules as $rule) { - $productIDs = $this->getProductIds($rule); - - if ($productIDs) { - $productIDs = $this->expandProducts($productIDs); - - $this->setSale($rule, $productIDs); - } - } - } else { - // handle the deceased rules here or call the declutter handler over here - // dd($this->deceased); - } - } - - /** - * To set the sale price for products falling catalog rule criteria - * - * @param CatalogRule $catalogRule - * - * @return Void - */ - public function setSale($rule, $productIDs) - { - if (is_array($productIDs)) { - // apply on selected products - foreach ($productIDs as $productID) { - // catalog rule product resource is updated here - $this->createOrUpdateCatalogRuleProduct($rule, $productID); - - // catalog rule product price resource is updated here - $this->createOrUpdateCatalogRuleProductPrice($rule, $productID); - } - } else if ($productIDs == '*') { - $this->catalogRuleProduct->createOrUpdateCatalogRuleProduct($rule, $productIDs); - - $this->catalogRuleProductPrice->createOrUpdateCatalogRuleProductPrice($rule, $productIDs); - } - } - - /** - * Create or update catalog rule product resource - * - * @param CatalogRule $rule - * @param Integer $productID - * - * @return Void - */ - public function createOrUpdateCatalogRuleProduct($rule, $productID) - { - $channels = $rule->channels; - $customerGroups = $rule->customer_groups; - - $channelsGroupsCross = $channels->crossJoin($customerGroups); - - if ($productID == '*') { - $products = $this->product->all('id'); - - foreach ($channelsGroupsCross as $channelGroup) { - $channelId = $channelGroup[0]->channel_id; - $groupId = $channelGroup[1]->customer_group_id; - - foreach ($products as $product) { - $productID = $product->id; - - $catalogRuleProduct = $this->catalogRuleProduct->findWhere([ - 'channel_id' => $channelId, - 'customer_group_id' => $groupId, - 'product_id' => $productID - ]); - - if ($catalogRuleProduct->count()) { - // check for tie breaker rules and then update - $product = $this->product->find($productID); - - $productPrice = $product->price; - - // check for tie breaker rules and then update - $previousRuleID = $catalogRuleProduct->first()->catalog_rule_id; - - $newRuleID = $rule->id; - - $winnerRuleId = $this->breakTie($previousRuleID, $newRuleID, $product); - - $discountAmount = $this->getDiscountAmount($product, $rule); - - $data = [ - 'catalog_rule_id' => $rule->id, - 'starts_from' => $rule->starts_from, - 'ends_till' => $rule->ends_till, - 'customer_group_id' => $groupId, - 'channel_id' => $channelId, - 'product_id' => $productID, - 'action_code' => $rule->action_code, - 'action_amount' => $discountAmount - ]; - - if ($rule->id == $winnerRuleId) { - $this->catalogRuleProduct->create($data); - } else { - $this->catalogRuleProduct->update($data, $catalogRuleProduct->first()->id); - } - } else { - $data = [ - 'catalog_rule_id' => $rule->id, - 'starts_from' => $rule->starts_from, - 'ends_till' => $rule->ends_till, - 'customer_group_id' => $groupId, - 'channel_id' => $channelId, - 'product_id' => $productID, - 'action_code' => $rule->action_code, - 'action_amount' => $rule->discount_amount - ]; - - $this->catalogRuleProduct->create($data); - } - } - } - } else { - foreach ($channelsGroupsCross as $channelGroup) { - $channelId = $channelGroup[0]->channel_id; - $groupId = $channelGroup[1]->customer_group_id; - - $catalogRuleProduct = $this->catalogRuleProduct->findWhere([ - 'channel_id' => $channelId, - 'customer_group_id' => $groupId, - 'product_id' => $productID - ]); - - if ($catalogRuleProduct->count()) { - $product = $this->product->find($productID); - $productPrice = $product->price; - - // check for tie breaker rules and then update - $previousRuleID = $catalogRuleProduct->first()->catalog_rule_id; - - $newRuleID = $rule->id; - - $winnerRuleId = $this->breakTie($previousRuleID, $newRuleID, $product); - - // update - if ($winnerRuleId != $rule->id) { - $discountAmount = $this->getDiscountAmount($product, $rule); - - $catalogRuleProduct->first()->update([ - 'catalog_rule_id' => $rule->id, - 'starts_from' => $rule->starts_from, - 'ends_till' => $rule->ends_till, - 'customer_group_id' => $groupId, - 'channel_id' => $channelId, - 'product_id' => $productID, - 'action_code' => $rule->action_code, - 'action_amount' => $discountAmount - ]); - } else { - //do reassessment - } - } else if ($catalogRuleProduct->count() == 0) { - $product = $this->product->find($productID); - - $discountAmount = $this->getDiscountAmount($product, $rule); - - $data = [ - 'catalog_rule_id' => $rule->id, - 'starts_from' => $rule->starts_from, - 'ends_till' => $rule->ends_till, - 'customer_group_id' => $groupId, - 'channel_id' => $channelId, - 'product_id' => $productID, - 'action_code' => $rule->action_code, - 'action_amount' => $discountAmount - ]; - - $this->catalogRuleProduct->create($data); - } else { - // do the reassessment updation if the cart rule action changes the new action and its amount needs to be updated - } - } - } - } - - /** - * Create or update catalog rule product resource - * - * @param CatalogRule $rule - * @param Integer $productID - * - * @return Void - */ - public function createOrUpdateCatalogRuleProductPrice($rule, $productID) - { - $channels = $rule->channels; - $customerGroups = $rule->customer_groups; - - $channelsGroupsCross = $channels->crossJoin($customerGroups); - - if ($productID == '*') { - $products = $this->product->all('id'); - - foreach ($channelsGroupsCross as $channelGroup) { - $channelId = $channelGroup[0]->channel_id; - $groupId = $channelGroup[1]->customer_group_id; - - foreach ($products as $product) { - $productID = $product->id; - - $catalogRuleProductPrice = $this->catalogRuleProductPrice->findWhere([ - 'channel_id' => $channelId, - 'customer_group_id' => $groupId, - 'product_id' => $productID - ]); - - if ($catalogRuleProductPrice->count()) { - // check for tie breaker rules and then update - $data = [ - 'catalog_rule_id' => $rule->id, - 'starts_from' => $rule->starts_from, - 'ends_till' => $rule->ends_till, - 'customer_group_id' => $groupId, - 'channel_id' => $channelId, - 'product_id' => $productID, - 'action_code' => $rule->action_code, - 'action_amount' => $rule->discount_amount - ]; - - $this->catalogRuleProductPrice->update($data, $catalogRuleProductPrice->first()->id); - } else { - $data = [ - 'catalog_rule_id' => $rule->id, - 'starts_from' => $rule->starts_from, - 'ends_till' => $rule->ends_till, - 'customer_group_id' => $groupId, - 'channel_id' => $channelId, - 'product_id' => $productID, - 'action_code' => $rule->action_code, - 'action_amount' => $rule->discount_amount - ]; - - $this->catalogRuleProductPrice->create($data); - } - } - } - } else { - foreach ($channelsGroupsCross as $channelGroup) { - $channelId = $channelGroup[0]->channel_id; - $groupId = $channelGroup[1]->customer_group_id; - - $catalogRuleProduct = $this->catalogRuleProduct->findWhere([ - 'channel_id' => $channelId, - 'customer_group_id' => $groupId, - 'product_id' => $productID - ]); - - $catalogRuleProductPrice = $this->catalogRuleProductPrice->findWhere([ - 'channel_id' => $channelId, - 'customer_group_id' => $groupId, - 'product_id' => $productID - ]); - - if ($catalogRuleProductPrice->count()) { - $catalogRuleProduct = $catalogRuleProduct->first(); - - $product = $this->product->find($productID); - - $productPrice = $product->price - $catalogRuleProduct->action_amount; - - $winnerRuleId = $this->breakTie($catalogRuleProduct->catalog_rule_id, $rule->id, $product); - - if ($winnerRuleId != $rule->id) { - $data = [ - 'catalog_rule_id' => $rule->id, - 'starts_from' => $rule->starts_from, - 'ends_till' => $rule->ends_till, - 'customer_group_id' => $groupId, - 'channel_id' => $channelId, - 'product_id' => $productID, - 'rule_price' => $productPrice - ]; - - $catalogRuleProductPrice->first()->update($data); - } else { - // do reassement - } - } else if ($catalogRuleProductPrice->count() == 0) { - $catalogRuleProduct = $catalogRuleProduct->first(); - - $discountAmount = $catalogRuleProduct->action_amount; - - $product = $this->product->find($productID); - - $productPrice = $product->price - $discountAmount; - - $data = [ - 'catalog_rule_id' => $rule->id, - 'starts_from' => $rule->starts_from, - 'ends_till' => $rule->ends_till, - 'customer_group_id' => $groupId, - 'channel_id' => $channelId, - 'product_id' => $productID, - 'rule_price' => $productPrice - ]; - - $this->catalogRuleProductPrice->create($data); - } else { - // do the reassessment updation if the cart rule action changes the new action and its amount needs to be updated - } - } - } - } - - /** - * Get discount amount for the rule and product - * - * @return Decimal $discountAmount - */ - public function getDiscountAmount($product, $rule) - { - - $actionClass = config('discount-rules.catalog')[$rule->action_code]; - - $actionInstance = new $actionClass(); - - $discountAmount = $actionInstance->calculate($rule, $product); - - return $discountAmount; - } - - /** - * To expand the productIDs of configurable products - * - * @param Array $productIDs - * - * @return Array - */ - protected function expandProducts($productIDs) - { - $products = app('Webkul\Product\Repositories\ProductRepository'); - - $newProductIDs = collect(); - - foreach ($productIDs as $productID) { - $product = $products->find($productID); - - if ($product->type == 'configurable') { - $variants = $product->variants; - - foreach($variants as $variant) { - $newProductIDs->push($variant->id); - } - } else { - $newProductIDs->push($productID); - } - } - - if ($newProductIDs->count()) { - return $newProductIDs->toArray(); - } else { - return []; - } - } - - /** - * To break tie between two rules - * - * @param Integer $previousRuleID - * @param Integer $newRuleID - * - * @return String $id - */ - public function breakTie($previousRuleID, $newRuleID, $product) - { - $oldRule = $this->catalogRule->find($previousRuleID); - - $newRule = $this->catalogRule->find($newRuleID); - - if ($oldRule->ends_other_rules) { - return $oldRule->id; - } else { - $oldRuleDiscount = $this->getDiscountAmount($product, $oldRule); - - $newRuleDiscount = $this->getDiscountAmount($product, $newRule); - - if ($newRuleDiscount > $oldRuleDiscount) { - return $newRule->id; - } else { - return $oldRule->id; - } - } - } - - /** - * To declutter the catalog rules that are either inactive or deleted - * - * @return Boolean - */ - public function deClutter() - { - $rules = $this->catalogRule->all(); - - foreach ($rules as $rule) { - $validated = $this->checkApplicability($rule); - - if (! $validated) { - $this->deceased->push($rule->id); - } - } - - if (count($this->deceased)) { - $count = 0; - - foreach ($this->deceased as $deceased) { - $cartRuleProducts = $this->catalogRuleProduct->findWhere(['catalog_rule_id' => $deceased]); - - $cartRuleProductsPrice = $this->catalogRuleProductPrice->findWhere(['catalog_rule_id' => $deceased]); - - // obvious logic for removing entries as entries in both storage needs to be exactly equal for a product - foreach ($cartRuleProducts as $cartRuleProduct) { - // deletes cartRuleProducts resource - $cartRuleProduct->delete(); - - // deletes cartRuleProductsPrice resource - $cartRuleProductsPrice->delete(); - } - } - - return true; - } else { - return false; - } - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Helpers/Catalog/ConvertXToProductId.php b/packages/Webkul/Discount/src/Helpers/Catalog/ConvertXToProductId.php deleted file mode 100644 index c71d6c4e4..000000000 --- a/packages/Webkul/Discount/src/Helpers/Catalog/ConvertXToProductId.php +++ /dev/null @@ -1,271 +0,0 @@ - @prashant-webkul - * @copyright 2019 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class ConvertXToProductId -{ - /** - * CategoryRepository instance - */ - protected $category; - - /** - * AttributeRepository instance - */ - protected $attribute; - - /** - * ProductRepository instance - */ - protected $product; - - /** - * AttributeOptionRepository instance - */ - protected $attributeOption; - - /** - * CatalogRuleRepository instance - */ - protected $catalogRule; - - /** - * ProductAttributeValueRepository instance - */ - protected $pav; - - /** - * Condition symbols for matching the criteria with attributes selected - */ - protected $symbols; - - public function __construct( - Category $category, - Attribute $attribute, - Product $product, - AttributeOption $attributeOption, - CatalogRule $catalogRule, - ProductAttributeValue $pav - ) { - $this->category = $category; - - $this->attribute = $attribute; - - $this->product = $product; - - $this->attributeOption = $attributeOption; - - $this->catalogRule = $catalogRule; - - $this->pav = $pav; - - $this->conditionSymbols = config('pricerules.cart.conditions.symbols'); - } - - public function convertX($attributeConditions) - { - $categoryValues = $attributeConditions->categories; - - $attributeValues = $attributeConditions->attributes; - - if (! isset($categoryValues) && ! isset($attributeValues)) - return false; - - $categoryResult = collect(); - - if (isset($categoryValues) && count($categoryValues)) - $categoryResult = $this->convertFromCategories($categoryValues); - - $attributeResult = collect(); - - if (isset($attributeValues) && count($attributeValues)) - $attributeResult = $this->convertFromAttributes($attributeValues); - - // now call the function that will find all the unique product ids - $productIDs = $this->findAllUniqueIds($attributeResult, $categoryResult); - - return $productIDs; - } - - /** - * This method will return product id from the attribute and attribute option params - * - * @return array - */ - public function convertFromAttributes($attributeOptions) - { - $products = collect(); - - foreach ($attributeOptions as $attributeOption) { - if (isset($attributeOption->type) && $attributeOption->name != null && $attributeOption->condition != null && $attributeOption->value != [] && $attributeOption->type != null) { - $selectedOptions = $attributeOption->value; - - if ($attributeOption->type == 'select' || $attributeOption->type == 'multiselect') { - $attribute = $this->attribute->findWhere(['code' => $attributeOption->attribute]); - - $attributeOptions = $attribute->first()->options; - - $selectedAttributeOptions = collect(); - - foreach ($attributeOptions as $attributeOption) { - foreach ($selectedOptions as $key => $value) { - if ($attributeOption->id == $value) - $selectedAttributeOptions->push($attributeOption); - } - } - - foreach ($selectedAttributeOptions as $selectedAttributeOption) { - $typeColumn = $this->pav::$attributeTypeFields[$attribute->first()->type]; - - $pavResults = $this->pav->where( - "{$typeColumn}", - $selectedAttributeOption->id - )->get(); - - foreach ($pavResults as $pavResult) { - if ($pavResult->product->type == 'simple') - $products->push($pavResult->product); - } - } - } else { - $attribute = $this->attribute->findWhere(['code' => $attributeOption->attribute]); - - $pavValues = $attribute->first(); - - $selectedAttributeValues = collect(); - - if ($attributeOption->attribute == 'sku') { - $testValue = $attributeOption->value; - $testCondition = $attributeOption->condition; - - if ($testCondition == '{}') { - $foundProducts = $this->product->findWhere([ - ['sku', 'like', '%' . $testValue . '%'], - ['type', '!=', 'configurable'] - ])->flatten()->all(); - } else if ($testCondition == '!{}') { - $foundProducts = $this->product->findWhere([ - ['sku', 'not like', '%' . $testValue . '%'], - ['type', '!=', 'configurable'] - ])->flatten()->all(); - } else if ($testCondition == '=') { - $foundProducts = $this->product->findWhere([ - ['sku', '=', $testValue], - ['type', '!=', 'configurable'] - ])->flatten()->all(); - } - } - - foreach ($foundProducts as $foundProduct) { - $products->push($foundProduct); - } - } - } - } - - return $products; - } - - /** - * This method will return product id from the attribute and attribute option params - * - * @param Collection $categories - * - * @return array - */ - public function convertFromCategories($categories) - { - $products = collect(); - - foreach ($categories as $category) { - $data = $this->getAll($category->id); - - if ($data->count()) { - $products->push($data); - - unset($data); - } - } - - return $products->flatten()->all(); - } - - /** - * This method will remove the duplicates from the array and merge all the items into single array - * - * @param array - * - * @return array - */ - public function findAllUniqueIds(...$data) - { - $attributeResult = $data[0] ?? collect(); - $categoryResult = $data[1] ?? collect(); - - // find matched attribute options product ids - $mergedCollection = $attributeResult->merge($categoryResult); - - $productIDs = collect(); - - foreach ($mergedCollection as $merged) { - $productIDs->push($merged->id); - } - - // find all the unique product ids - $productIDs = $productIDs->unique(); - - return $productIDs->flatten()->all(); - } - - /** - * To get all product ids lying in the criteria - * - * @param integer $categoryId - * - * @return Collection - */ - public function getAll($categoryId = null) - { - $results = app('Webkul\Product\Repositories\ProductFlatRepository')->scopeQuery(function ($query) use ($categoryId) { - - $channel = request()->get('channel') ?: (core()->getCurrentChannelCode() ?: core()->getDefaultChannelCode()); - - $locale = request()->get('locale') ?: app()->getLocale(); - - $qb = $query->distinct() - ->select('products.id') - ->leftJoin('products', 'product_flat.product_id', '=', 'products.id') - ->leftJoin('product_categories', 'products.id', '=', 'product_categories.product_id') - ->whereNotNull('product_flat.url_key'); - - if ($categoryId) { - $qb->where('product_categories.category_id', $categoryId); - } - - $qb->where('product_flat.status', 1); - - $qb->where('product_flat.visible_individually', 1); - - $queryBuilder = $qb->leftJoin('product_flat as flat_variants', function ($qb) use ($channel, $locale) { - $qb->on('product_flat.id', '=', 'flat_variants.parent_id'); - }); - - return $qb->groupBy('product_flat.id'); - })->get(); - - return $results; - } -} diff --git a/packages/Webkul/Discount/src/Helpers/Catalog/Sale.php b/packages/Webkul/Discount/src/Helpers/Catalog/Sale.php deleted file mode 100644 index 294e61ef2..000000000 --- a/packages/Webkul/Discount/src/Helpers/Catalog/Sale.php +++ /dev/null @@ -1,85 +0,0 @@ - @prashant-webkul - * @copyright 2019 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -abstract class Sale -{ - abstract function apply(); - - /** - * To validate rule - * - * @param CatalogRule $rule - * - * @return Boolean - */ - public function checkApplicability($rule) - { - $cart = \Cart::getCart(); - - $timeBased = false; - - $status = false; - - // time based constraints - if ($rule->starts_from != null && $rule->ends_till == null) { - if (Carbon::parse($rule->starts_from) < now()) - $timeBased = true; - } else if ($rule->starts_from == null && $rule->ends_till != null) { - if (Carbon::parse($rule->ends_till) > now()) - $timeBased = true; - } else if ($rule->starts_from != null && $rule->ends_till != null) { - if (Carbon::parse($rule->starts_from) < now() && now() < Carbon::parse($rule->ends_till)) - $timeBased = true; - } else { - $timeBased = true; - } - - if ($rule->status) - $status = true; - - if ($timeBased && $status) { - return true; - } else { - return false; - } - } - - /** - * Function to maintain products and catalog rule - * - * @param CatalogRule $rule - * - * @return String|NULL - */ - public function getProductIds($rule) - { - if ($rule->conditions) { - $conditions = $rule->conditions; - - while(gettype($conditions) == 'string') { - $conditions = json_decode($conditions); - } - - $productIDs = $this->convertX->convertX($conditions); - } else { - $productIDs = '*'; - } - - return $productIDs; - } - - /** - * Function to maintain products, catalog rule, price - */ - -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Http/Controllers/CartRuleController.php b/packages/Webkul/Discount/src/Http/Controllers/CartRuleController.php deleted file mode 100644 index cd85e7638..000000000 --- a/packages/Webkul/Discount/src/Http/Controllers/CartRuleController.php +++ /dev/null @@ -1,573 +0,0 @@ - @prashant-webkul - * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class CartRuleController extends Controller -{ - /** - * Initialize _config, a default request parameter with route - */ - protected $_config; - - /** - * Property for Cart rule application - */ - protected $appliedConfig; - - /** - * To hold Cart repository instance - */ - protected $cartRule; - - /** - * To hold Rule Label repository instance - */ - protected $cartRuleLabel; - - /** - * To hold Coupons Repository instance - */ - protected $cartRuleCoupon; - - /** - * To hold category repository instance - */ - protected $category; - - /** - * To hold attribute repository instance - */ - protected $attribute; - - /** - * To hold the cart repository instance - */ - protected $cart; - - /** - * Convert X To Product ID. - * - */ - protected $convertX; - - public function __construct( - CartRule $cartRule, - CartRuleCoupons $cartRuleCoupon, - CartRuleLabels $cartRuleLabel, - Attribute $attribute, - Category $category, - ConvertX $convertX - ) - { - $this->_config = request('_config'); - - $this->cartRule = $cartRule; - - $this->cartRuleCoupon = $cartRuleCoupon; - - $this->cartRuleLabel = $cartRuleLabel; - - $this->attribute = $attribute; - - $this->category = $category; - - $this->convertX = $convertX; - - $this->appliedConfig = config('pricerules.cart'); - } - - /** - * @return \Illuminate\View\View - */ - public function index() - { - return view($this->_config['view']); - } - - /** - * @return \Illuminate\View\View - */ - public function create() - { - return view($this->_config['view'])->with('cart_rule', [$this->appliedConfig, $this->category->getPartial(), $this->getStatesAndCountries(), $this->attribute->getPartial()]); - } - - /** - * Stores the response from cart rule store page to datastore - * - * @return redirect - */ - public function store() - { - $this->validate(request(), [ - 'name' => 'required|string|unique:cart_rules,name', - 'description' => 'string', - 'starts_from' => 'nullable|date', - 'ends_till' => 'nullable|date|after_or_equal:starts_from', - 'customer_groups' => 'required|array', - 'channels' => 'required|array', - 'status' => 'required|boolean', - 'use_coupon' => 'boolean|required', - // 'usage_limit' => 'numeric|min:0', - // 'per_customer' => 'numeric|min:0', - 'action_type' => 'required|string', - 'disc_amount' => 'required|numeric', - 'disc_quantity' => 'numeric', - // 'disc_threshold' => 'numeric', - 'free_shipping' => 'required|boolean', - 'apply_to_shipping' => 'required|boolean', - 'code' => 'string|required_if:auto_generation,0', - 'all_conditions' => 'sometimes|nullable', - 'label' => 'array|nullable' - ]); - - $data = request()->all(); - - $attribute_conditions = $data['all_attributes']; - unset($data['all_attributes']); - - // unset token - unset($data['_token']); - - // check if starts_from is null - if ($data['starts_from'] == "") { - $data['starts_from'] = null; - } - - // check if end_till is null - if ($data['ends_till'] == "") { - $data['ends_till'] = null; - } - - // customer groups - $customer_groups = $data['customer_groups']; - - // unset customer groups - unset($data['customer_groups']); - - // unset criteria - unset($data['criteria']); - - // channels - $channels = $data['channels']; - - // unset channels - unset($data['channels']); - - // make labels - $labels = $data['label']; - - // unset labels - unset($data['label']); - - while (gettype($attribute_conditions) == 'string') { - $attribute_conditions = json_decode($attribute_conditions); - } - - if (! isset($attribute_conditions) || ! (count($attribute_conditions->categories) || count($attribute_conditions->attributes))) { - $data['uses_attribute_conditions'] = 0; - - $data['actions'] = [ - 'action_type' => $data['action_type'], - 'disc_amount' => $data['disc_amount'], - 'disc_quantity' => $data['disc_quantity'] - ]; - } else { - $data['uses_attribute_conditions'] = 1; - - $data['actions'] = [ - 'action_type' => $data['action_type'], - 'disc_amount' => $data['disc_amount'], - 'disc_quantity' => $data['disc_quantity'], - 'attribute_conditions' => $attribute_conditions - ]; - } - - // prepare json object from conditions - $data['actions'] = json_encode($data['actions']); - - // check if all - if (! isset($data['all_conditions']) || $data['all_conditions'] == "[]" || $data['all_conditions'] == "") { - $data['conditions'] = null; - } else { - $data['conditions'] = json_encode($data['all_conditions']); - } - - // unset cart_attributes from conditions - unset($data['cart_attributes']); - - // unset attributes from conditions - unset($data['attributes']); - - // unset all_conditions from conditions - unset($data['all_conditions']); - - // prepare coupons if coupons are used - if ($data['use_coupon']) { - // if (isset($data['auto_generation']) && $data['auto_generation']) { - // auto generation is off for now - $data['auto_generation'] = 0; - - // save the coupon used in coupon section - $coupons['code'] = $data['code']; - - $couponExists = $this->cartRuleCoupon->findWhere([ - 'code' => $coupons['code'] - ]); - - if ($couponExists->count()) { - session()->flash('warning', trans('admin::app.promotion.status.duplicate-coupon')); - - return redirect()->back(); - } - - // set coupon usage per customer same as per_customer limit which is disabled for now - // $coupons['usage_per_customer'] = $data['per_customer']; //0 is for unlimited usage - // unset coupon code from coupon section - unset($data['code']); - // } else { - // $data['auto_generation'] = 1; - // } - - // if (isset($data['prefix'])) { - // $coupons['prefix'] = $data['prefix']; - // unset($data['prefix']); - // } - - // if (isset($data['suffix'])) { - // $coupons['suffix'] = $data['suffix']; - // unset($data['suffix']); - // } - - // $coupons['limit'] = 0; - } - - // per coupon usage limit - // if(isset($data['usage_limit'])) { - // $coupons['limit'] = $data['usage_limit']; - // } - - // create a cart rule - $ruleCreated = $this->cartRule->create($data); - - // can execute convertX here after when the rule is updated - if (isset($attribute_conditions) && $data['uses_attribute_conditions']) { - $this->convertX->convertX($ruleCreated->id, $attribute_conditions); - } - - // create customer groups for cart rule - $ruleGroupCreated = $this->cartRule->CustomerGroupSync($customer_groups, $ruleCreated); - - // create customer groups for channels - $ruleChannelCreated = $this->cartRule->ChannelSync($channels, $ruleCreated); - - // prepare labels - if (isset($labels['global'])) { - foreach (core()->getAllChannels() as $channel) { - $label1['channel_id'] = $channel->id; - - foreach($channel->locales as $locale) { - $label1['locale_id'] = $locale->id; - $label1['label'] = $labels['global']; - $label1['cart_rule_id'] = $ruleCreated->id; - - $ruleLabelCreated = $this->cartRuleLabel->create($label1); - } - } - } else { - $label2['label'] = $labels['global']; - $label2['cart_rule_id'] = $ruleCreated->id; - - $ruleLabelCreated = $this->cartRuleLabel->create($label2); - } - - // create coupon if present - if (isset($coupons)) { - $coupons['cart_rule_id'] = $ruleCreated->id; - $couponCreated = $this->cartRuleCoupon->create($coupons); - } - - if ($ruleCreated && $ruleChannelCreated && $ruleGroupCreated) { - if (isset($couponCreated) && $couponCreated) { - session()->flash('success', trans('admin::app.promotion.status.success-coupon')); - } - - session()->flash('success', trans('admin::app.promotion.status.success')); - } else { - session()->flash('success', trans('admin::app.promotion.status.success')); - - return redirect()->back(); - } - - return redirect()->route($this->_config['redirect']); - } - - /** - * @return \Illuminate\View\View - */ - public function edit($id) - { - $cart_rule = $this->cartRule->find($id); - - return view($this->_config['view'])->with('cart_rule', [ - $this->appliedConfig, - $this->category->getPartial(), - $this->getStatesAndCountries(), - $cart_rule, - $this->attribute->getPartial() - ]); - } - - /** - * Collects the response from cart rule update page and update datastore - * - * @return redirect - */ - public function update($id) - { - $this->validate(request(), [ - 'name' => 'required|string|unique:cart_rules,name,'.$id, - 'description' => 'string', - 'starts_from' => 'nullable|date', - 'ends_till' => 'nullable|date|after_or_equal:starts_from', - 'customer_groups' => 'required|array', - 'channels' => 'required|array', - 'status' => 'required|boolean', - 'use_coupon' => 'boolean|required', - // 'usage_limit' => 'numeric|min:0', - // 'per_customer' => 'numeric|min:0', - 'action_type' => 'required|string', - 'disc_amount' => 'required|numeric', - 'disc_quantity' => 'required|numeric', - // 'disc_threshold' => 'required|numeric', - 'free_shipping' => 'required|boolean', - 'apply_to_shipping' => 'required|boolean', - 'code' => 'string|required_if:user_coupon,1', - 'all_conditions' => 'present', - 'label' => 'array|nullable' - ]); - - // collecting request in $data - $data = request()->all(); - - $attribute_conditions = $data['all_attributes']; - unset($data['all_attributes']); - - // unset request token from $data - unset($data['_token']); - - // check if starts_from is null - if ($data['starts_from'] == "") { - $data['starts_from'] = null; - } - - // check if end_till is null - if ($data['ends_till'] == "") { - $data['ends_till'] = null; - } - - // set channels - $channels = $data['channels']; - - // unset the channels from $data - unset($data['channels']); - - // set customer_groups - $customer_groups = $data['customer_groups']; - - // unset customer groups - unset($data['customer_groups']); - - // set labels and unset them from $data - if (isset($data['label'])) { - $labels = $data['label']; - - unset($data['label']); - } - - // unset cart_attributes and attributes from $data - unset($data['cart_attributes']); - unset($data['attributes']); - - // prepare actions from data for json action - $attribute_conditions = json_decode($attribute_conditions); - - while (gettype($attribute_conditions) == 'string') { - $attribute_conditions = json_decode($attribute_conditions); - } - - if (! isset($attribute_conditions) || ! (count($attribute_conditions->categories) || count($attribute_conditions->attributes))) { - $data['uses_attribute_conditions'] = 0; - - $data['actions'] = [ - 'action_type' => $data['action_type'], - 'disc_amount' => $data['disc_amount'], - 'disc_quantity' => $data['disc_quantity'] - ]; - } else { - $data['uses_attribute_conditions'] = 1; - - $data['actions'] = [ - 'action_type' => $data['action_type'], - 'disc_amount' => $data['disc_amount'], - 'disc_quantity' => $data['disc_quantity'], - 'attribute_conditions' => $attribute_conditions - ]; - } - - // encode php array to json for actions - $data['actions'] = json_encode($data['actions']); - - // Prepares conditions from all conditions - if (! isset($data['all_conditions']) || $data['all_conditions'] == "[]" || $data['all_conditions'] == "") { - $data['conditions'] = null; - } else { - $data['conditions'] = json_encode($data['all_conditions']); - } - - unset($data['match_criteria']); - - // unset all_conditions from conditions - unset($data['all_conditions']); - - // set coupons from $data - if ($data['use_coupon']) { - // if (isset($data['auto_generation']) && $data['auto_generation']) { - $data['auto_generation'] = 0; - - $coupons['code'] = $data['code']; - - $couponExists = $this->cartRuleCoupon->findWhere([ - 'code' => $coupons['code'] - ]); - - if ($couponExists->count()) { - if ($couponExists->first()->cart_rule_id != $id) { - session()->flash('warning', trans('admin::app.promotion.status.duplicate-coupon')); - - return redirect()->back(); - } - } - - unset($data['code']); - // } else { - // $data['auto_generation'] = 1; - // } - - // if (isset($data['prefix'])) { - // $coupons['prefix'] = $data['prefix']; - // unset($data['prefix']); - // } - - // if (isset($data['suffix'])) { - // $coupons['suffix'] = $data['suffix']; - // unset($data['suffix']); - // } - // $coupons['limit'] = 0; - } - - // if (isset($data['usage_limit'])) { - // $coupons['limit'] = $data['usage_limit']; - // } - - // update cart rule - $ruleUpdated = $this->cartRule->update($data, $id); - - if (isset($attribute_conditions) && $data['uses_attribute_conditions']) { - // can execute convert X here after when the rule is updated - $this->convertX->convertX($ruleUpdated->id, $attribute_conditions); - } else { - $ruleUpdated->update([ - 'product_ids' => null - ]); - } - - // update customer groups for cart rule - $ruleGroupUpdated = $this->cartRule->CustomerGroupSync($customer_groups, $ruleUpdated); - - // update customer groups for cart rule - $ruleChannelUpdated = $this->cartRule->ChannelSync($channels, $ruleUpdated); - - // update labels - $labelsUpdated = $this->cartRule->LabelSync($labels, $ruleUpdated); - - // check coupons set conditions - if (isset($coupons)) { - // $coupons['usage_per_customer'] = $data['per_customer']; //0 is for unlimited usage - $coupons['cart_rule_id'] = $ruleUpdated->id; - - if ($ruleUpdated->coupons == null) { - $couponCreatedOrUpdated = $this->cartRuleCoupon->create($coupons); - } else { - $couponCreatedOrUpdated = $ruleUpdated->coupons->update($coupons); - } - } else { - if ($ruleUpdated->coupons != null) { - $ruleUpdated->coupons->delete(); - } - } - - if ($ruleUpdated && $ruleGroupUpdated && $ruleChannelUpdated) { - if (isset($couponCreatedOrUpdated) && $couponCreatedOrUpdated) { - session()->flash('success', trans('admin::app.promotion.status.success-coupon')); - } - - session()->flash('success', trans('admin::app.promotion.status.update-success')); - } else { - session()->flash('success', trans('admin::app.promotion.status.update-success')); - - return redirect()->back(); - } - - return redirect()->route($this->_config['redirect']); - } - - /** - * Deletes the cart rule - * - * @return JSON - */ - public function destroy($id) - { - $cartRule = $this->cartRule->findOrFail($id); - - if ($cartRule->delete()) { - session()->flash('success', trans('admin::app.promotion.status.delete-success')); - - return response()->json(['message' => true], 200); - } else { - session()->flash('error', trans('admin::app.promotion.status.delete-failed')); - - return response()->json(['message' => false], 400); - } - } - - /** - * Get Countries and states list from core helpers - * - * @return Array - */ - public function getStatesAndCountries() - { - $countries = core()->countries()->toArray(); - $states = core()->groupedStatesByCountries(); - - return [ - 'countries' => $countries, - 'states' => $states - ]; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Http/Controllers/CatalogRuleController.php b/packages/Webkul/Discount/src/Http/Controllers/CatalogRuleController.php deleted file mode 100644 index 9bb650a8f..000000000 --- a/packages/Webkul/Discount/src/Http/Controllers/CatalogRuleController.php +++ /dev/null @@ -1,437 +0,0 @@ - @prashant-webkul - * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class CatalogRuleController extends Controller -{ - /** - * Initialize _config, a default request parameter with route - */ - protected $_config; - - /** - * Attribute $attribute - */ - protected $attribute; - - /** - * AttributeFamily $attributeFamily - */ - protected $attributeFamily; - - /** - * Category $category - */ - protected $category; - - /** - * Product $product - */ - protected $product; - - /** - * Property for catalog rule application - */ - protected $appliedConfig; - - /** - * Property for catalog rule application - */ - protected $appliedConditions; - - /** - * Property to hold Catalog Rule Channels Repository - */ - protected $catalogRuleChannels; - - /** - * Property to hold Catalog Rule Customer Groups Repository - */ - protected $catalogRuleCustomerGroups; - - /** - * To hold catalog repository instance - */ - protected $catalogRule; - - /** - * To hold Sale instance - */ - protected $apply; - - public function __construct( - Attribute $attribute, - AttributeFamily $attributeFamily, - Category $category, Product $product, - CatalogRule $catalogRule, - CatalogRuleChannels $catalogRuleChannels, - CatalogRuleCustomerGroups $catalogRuleCustomerGroups, - Apply $sale - ) { - $this->_config = request('_config'); - $this->attribute = $attribute; - $this->attributeFamily = $attributeFamily; - $this->category = $category; - $this->product = $product; - $this->sale = $sale; - $this->catalogRule = $catalogRule; - $this->catalogRuleChannels = $catalogRuleChannels; - $this->catalogRuleCustomerGroups = $catalogRuleCustomerGroups; - $this->appliedConfig = config('pricerules.catalog'); - $this->appliedConditions = config('pricerules.conditions'); - } - - public function index() - { - return view($this->_config['view']); - } - - /** - * To load create form for catalog rule - * - * @return View - */ - public function create() - { - return view($this->_config['view'])->with('catalog_rule', [$this->appliedConfig, $this->category->getPartial(), $this->getStatesAndCountries(), $this->attribute->getPartial()]); - } - - /** - * To store newly created catalog rule and store it - * - * @return Redirect - */ - public function store() - { - $this->validate(request(), [ - 'name' => 'required|string|unique:catalog_rules,name', - 'description' => 'string', - 'starts_from' => 'nullable|date', - 'ends_till' => 'nullable|date|after_or_equal:starts_from', - 'starts_from' => 'present|nullable|date', - 'ends_till' => 'present|nullable|date', - 'customer_groups' => 'required', - 'channels' => 'required', - 'status' => 'required|boolean', - 'end_other_rules' => 'required|boolean', - 'all_conditions' => 'present', - 'disc_amount' => 'sometimes', - 'disc_percent' => 'sometimes', - ]); - - $catalog_rule = request()->all(); - - $catalog_rule_channels = array(); - $catalog_rule_customer_groups = array(); - - // check if starts_from is null - if ($catalog_rule['starts_from'] == "") { - $catalog_rule['starts_from'] = null; - } - - // check if end_till is null - if ($catalog_rule['ends_till'] == "") { - $catalog_rule['ends_till'] = null; - } - - $catalog_rule_channels = $catalog_rule['channels']; - $catalog_rule_customer_groups = $catalog_rule['customer_groups']; - unset($catalog_rule['channels']); unset($catalog_rule['customer_groups']); - - unset($catalog_rule['criteria']); - - $catalog_rule['conditions'] = $catalog_rule['all_conditions']; - - unset($catalog_rule['all_conditions']); - - $catalog_rule['conditions'] = json_encode($catalog_rule['conditions']); - - if (isset($catalog_rule['disc_amount'])) { - $catalog_rule['actions'] = [ - 'action_code' => $catalog_rule['action_type'], - 'disc_amount' => $catalog_rule['disc_amount'] - ]; - } else if (isset($catalog_rule['disc_percent'])) { - $catalog_rule['actions'] = [ - 'action_code' => $catalog_rule['action_type'], - 'disc_percent' => $catalog_rule['disc_percent'], - ]; - } - - $catalog_rule['discount_amount'] = $catalog_rule['disc_amount']; - - $catalog_rule['action_code'] = $catalog_rule['action_type']; - - unset($catalog_rule['disc_amount']); - unset($catalog_rule['apply']); - unset($catalog_rule['attributes']); - unset($catalog_rule['_token']); - unset($catalog_rule['all_actions']); - - $catalog_rule['actions'] = json_encode($catalog_rule['actions']); - - $catalogRule = $this->catalogRule->create($catalog_rule); - - foreach($catalog_rule_channels as $catalog_rule_channel) { - $data['catalog_rule_id'] = $catalogRule->id; - $data['channel_id'] = $catalog_rule_channel; - - $catalogRuleChannels = $this->catalogRuleChannels->create($data); - } - - unset($data); - foreach ($catalog_rule_customer_groups as $catalog_rule_customer_group) { - $data['catalog_rule_id'] = $catalogRule->id; - $data['customer_group_id'] = $catalog_rule_customer_group; - - $catalogRuleCustomerGroups = $this->catalogRuleCustomerGroups->create($data); - } - - if($catalogRule && $catalogRuleChannels && $catalogRuleCustomerGroups) { - session()->flash('success', trans('admin::app.promotion.status.success')); - - return redirect()->route('admin.catalog-rule.index'); - } else { - session()->flash('error', trans('admin::app.promotion.status.failed')); - - return redirect()->back(); - } - } - - /** - * To load edit for previously created catalog rule - * - * @param $id - * - * @return View - */ - public function edit($id) - { - $catalog_rule = $this->catalogRule->find($id); - - $catalog_rule_channels = $this->catalogRuleChannels->findByField('catalog_rule_id', $id); - - $catalog_rule_customer_groups = $this->catalogRuleCustomerGroups->findByField('catalog_rule_id', $id); - - return view($this->_config['view'])->with('catalog_rule', [ - $this->attribute->getPartial(), - $this->category->getPartial(), - $this->fetchOptionableAttributes(), - $this->appliedConfig, - $this->appliedConditions, - $catalog_rule, - $catalog_rule_channels, - $catalog_rule_customer_groups, - $this->attributeFamily->getPartial() - ]); - } - - /** - * To update previously created catalog rule - * - * @param $id - * - * @return Redirect - */ - public function update($id) - { - $data = request()->input(); - - // $validated = \Validator::make($data, [ - // 'name' => 'required|string|unique:catalog_rules,name,' . $id, - // 'starts_from' => 'present|nullable|date', - // 'ends_till' => 'present|nullable|date', - // 'description' => 'string', - // 'customer_groups' => 'required', - // 'channels' => 'required', - // 'status' => 'required|boolean', - // 'end_other_rules' => 'required|boolean', - // 'all_conditions' => 'present', - // 'disc_amount' => 'sometimes', - // 'disc_percent' => 'sometimes' - // ]); - - // if ($validated->fails()) { - // dd($validated->errors()); - // } else { - // dd('passed'); - // } - - $this->validate(request(), [ - 'name' => 'required|string|unique:catalog_rules,name,'.$id, - // 'name' => 'required|string', - 'starts_from' => 'nullable|date', - 'ends_till' => 'nullable|date|after_or_equal:starts_from', - 'description' => 'string', - 'customer_groups' => 'required', - 'channels' => 'required', - 'status' => 'required|boolean', - 'end_other_rules' => 'required|boolean', - 'all_conditions' => 'present', - 'disc_amount' => 'sometimes', - 'disc_percent' => 'sometimes' - ]); - - $catalog_rule = request()->all(); - - $catalog_rule_channels = array(); - $catalog_rule_customer_groups = array(); - - // check if starts_from is null - if ($catalog_rule['starts_from'] == "") { - $catalog_rule['starts_from'] = null; - } - - // check if end_till is null - if ($catalog_rule['ends_till'] == "") { - $catalog_rule['ends_till'] = null; - } - - $catalog_rule_channels = $catalog_rule['channels']; - $catalog_rule_customer_groups = $catalog_rule['customer_groups']; - unset($catalog_rule['channels']); unset($catalog_rule['customer_groups']); - - unset($catalog_rule['criteria']); - - $catalog_rule['conditions'] = $catalog_rule['all_conditions']; - unset($catalog_rule['all_conditions']); - - if (isset($catalog_rule['disc_amount'])) { - $catalog_rule['action_code'] = $catalog_rule['action_type']; - $catalog_rule['actions'] = [ - 'action_code' => $catalog_rule['action_type'], - 'disc_amount' => $catalog_rule['disc_amount'] - ]; - } else if (isset($catalog_rule['disc_percent'])) { - $catalog_rule['action_code'] = $catalog_rule['action_type']; - $catalog_rule['actions'] = [ - 'action_code' => $catalog_rule['action'], - 'disc_percent' => $catalog_rule['disc_percent'], - ]; - } - - $catalog_rule['discount_amount'] = $catalog_rule['disc_amount']; - - unset($catalog_rule['disc_amount']); - unset($catalog_rule['apply']); - unset($catalog_rule['attributes']); - unset($catalog_rule['_token']); - unset($catalog_rule['all_actions']); - - $catalog_rule['actions'] = json_encode($catalog_rule['actions']); - $catalog_rule['conditions'] = json_encode($catalog_rule['conditions']); - - $catalogRule = $this->catalogRule->update($catalog_rule, $id); - - $catalogRuleChannels = $this->catalogRule->ChannelSync($catalog_rule_channels, $catalogRule); - $catalogRuleCustomerGroups = $this->catalogRule->CustomerGroupSync($catalog_rule_customer_groups, $catalogRule); - - if($catalogRule && $catalogRuleChannels && $catalogRuleCustomerGroups) { - session()->flash('success', trans('admin::app.promotion.status.update-success')); - - return redirect()->route($this->_config['redirect']); - } else { - session()->flash('error', trans('admin::app.promotion.status.update-failed')); - - return redirect()->back(); - } - } - - /** - * To apply the catalog rules - * - * @return Redirect - */ - public function applyRules() - { - $this->sale->apply(); - - session()->flash('success', trans('admin::app.promotion.processing-done')); - - return redirect()->route('admin.catalog-rule.index'); - } - - /** - * Initiates decluttering of rules and even reindexes the table if empty - * - * @return Response redirect - */ - public function deClutter() - { - $result = $this->sale->deClutter(); - - if ($result) { - session()->flash('success', trans('admin::app.promotion.declut-success')); - } else { - session()->flash('warning', trans('admin::app.promotion.declut-failure')); - } - - return redirect()->route($this->_config['redirect']); - } - - public function fetchOptionableAttributes() - { - $attributesWithOptions = array(); - - foreach($this->attribute->all() as $attribute) { - if (($attribute->type == 'select' || $attribute->type == 'multiselect') && $attribute->code != 'tax_category_id') { - $attributesWithOptions[$attribute->code] = $attribute->options->toArray(); - } - } - - return $attributesWithOptions; - } - - /** - * To delete existing catalog rule - * - * @param Integer $id - * - * @return Redirect - */ - public function destroy($id) - { - $catalogRule = $this->catalogRule->findOrFail($id); - - if ($catalogRule->delete()) { - session()->flash('success', trans('admin::app.promotion.status.delete-success')); - - return response()->json(['message' => true], 200); - } else { - session()->flash('error', trans('admin::app.promotion.status.delete-failed')); - - return response()->json(['message' => false], 400); - } - } - - /** - * Get Countries and states list from core helpers - * - * @return Array - */ - public function getStatesAndCountries() - { - $countries = core()->countries()->toArray(); - $states = core()->groupedStatesByCountries(); - - return [ - 'countries' => $countries, - 'states' => $states - ]; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Models/CartRule.php b/packages/Webkul/Discount/src/Models/CartRule.php deleted file mode 100644 index 6ea8b664d..000000000 --- a/packages/Webkul/Discount/src/Models/CartRule.php +++ /dev/null @@ -1,39 +0,0 @@ -hasMany(CartRuleChannels::modelClass()); - } - - public function customer_groups() - { - return $this->hasMany(CartRuleCustomerGroups::modelClass()); - } - - public function coupons() - { - return $this->hasOne(CartRuleCoupons::modelClass()); - } - - public function labels() - { - return $this->hasMany(CartRuleLabels::modelClass()); - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Models/CartRuleCart.php b/packages/Webkul/Discount/src/Models/CartRuleCart.php deleted file mode 100644 index 66d2b503c..000000000 --- a/packages/Webkul/Discount/src/Models/CartRuleCart.php +++ /dev/null @@ -1,22 +0,0 @@ -hasOne(CartRule::modelClass(), 'id', 'cart_rule_id'); - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Models/CartRuleCartProxy.php b/packages/Webkul/Discount/src/Models/CartRuleCartProxy.php deleted file mode 100644 index 98245e4d8..000000000 --- a/packages/Webkul/Discount/src/Models/CartRuleCartProxy.php +++ /dev/null @@ -1,10 +0,0 @@ -belongsTo(CartRule::modelClass(), 'cart_rule_id'); - } - - public function coupons_usage() - { - return $this->hasOne(CartRuleCouponsUsage::modelClass()); - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Models/CartRuleCouponsProxy.php b/packages/Webkul/Discount/src/Models/CartRuleCouponsProxy.php deleted file mode 100644 index 8f2fb7f23..000000000 --- a/packages/Webkul/Discount/src/Models/CartRuleCouponsProxy.php +++ /dev/null @@ -1,10 +0,0 @@ -hasOne(CustomerGroupProxy::modelClass(), 'id', 'customer_group_id'); - } -} diff --git a/packages/Webkul/Discount/src/Models/CartRuleCustomerGroupsProxy.php b/packages/Webkul/Discount/src/Models/CartRuleCustomerGroupsProxy.php deleted file mode 100644 index e402be089..000000000 --- a/packages/Webkul/Discount/src/Models/CartRuleCustomerGroupsProxy.php +++ /dev/null @@ -1,10 +0,0 @@ -belongsTo(CartRule::modelClass(), 'cart_rule_id'); - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Models/CartRuleCustomersProxy.php b/packages/Webkul/Discount/src/Models/CartRuleCustomersProxy.php deleted file mode 100644 index fed8df2c8..000000000 --- a/packages/Webkul/Discount/src/Models/CartRuleCustomersProxy.php +++ /dev/null @@ -1,10 +0,0 @@ -belongsTo(CartRule::modelClass(), 'cart_rule_id'); - } - - public function locale() - { - return $this->hasOne(Locale::modelClass(), 'id', 'locale_id'); - } - - public function channel() - { - return $this->hasOne(Channel::modelClass(), 'id', 'channel_id'); - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Models/CatalogRule.php b/packages/Webkul/Discount/src/Models/CatalogRule.php deleted file mode 100644 index 1c29bc299..000000000 --- a/packages/Webkul/Discount/src/Models/CatalogRule.php +++ /dev/null @@ -1,25 +0,0 @@ -hasMany(CatalogRuleChannels::modelClass()); - } - - public function customer_groups() - { - return $this->hasMany(CatalogRuleCustomerGroups::modelClass()); - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Models/CatalogRuleChannels.php b/packages/Webkul/Discount/src/Models/CatalogRuleChannels.php deleted file mode 100644 index d31ebf9de..000000000 --- a/packages/Webkul/Discount/src/Models/CatalogRuleChannels.php +++ /dev/null @@ -1,19 +0,0 @@ -belongsTo(CatalogRule::modelClass(), 'catalog_rule_id'); - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Models/CatalogRuleChannelsProxy.php b/packages/Webkul/Discount/src/Models/CatalogRuleChannelsProxy.php deleted file mode 100644 index c723f5482..000000000 --- a/packages/Webkul/Discount/src/Models/CatalogRuleChannelsProxy.php +++ /dev/null @@ -1,10 +0,0 @@ -hasOne(CustomerGroupProxy::modelClass(), 'id', 'customer_group_id'); - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Models/CatalogRuleCustomerGroupsProxy.php b/packages/Webkul/Discount/src/Models/CatalogRuleCustomerGroupsProxy.php deleted file mode 100644 index 12de4951a..000000000 --- a/packages/Webkul/Discount/src/Models/CatalogRuleCustomerGroupsProxy.php +++ /dev/null @@ -1,10 +0,0 @@ -loadMigrationsFrom(__DIR__ . '/../Database/Migrations'); - } - - /** - * Register services. - * - * @return void - */ - public function register() - { - $this->registerConfig(); - } - - /** - * To merge the price rule configuration in price rule configuration - */ - protected function registerConfig() - { - $this->mergeConfigFrom( - dirname(__DIR__) . '/Config/rule-conditions.php', 'pricerules' - ); - - $this->mergeConfigFrom( - dirname(__DIR__) . '/Config/discount-rules.php', 'discount-rules' - ); - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Providers/ModuleServiceProvider.php b/packages/Webkul/Discount/src/Providers/ModuleServiceProvider.php deleted file mode 100644 index 4332e00dc..000000000 --- a/packages/Webkul/Discount/src/Providers/ModuleServiceProvider.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @copyright 2019 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class CartRuleCartRepository extends Repository -{ - /** - * Specify Model class name - * - * @return mixed - */ - function model() - { - return 'Webkul\Discount\Contracts\CartRuleCart'; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Repositories/CartRuleChannelsRepository.php b/packages/Webkul/Discount/src/Repositories/CartRuleChannelsRepository.php deleted file mode 100644 index 2d6209445..000000000 --- a/packages/Webkul/Discount/src/Repositories/CartRuleChannelsRepository.php +++ /dev/null @@ -1,24 +0,0 @@ - @prashant-webkul - * @copyright 2019 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class CartRuleChannelsRepository extends Repository -{ - /** - * Specify Model class name - * - * @return mixed - */ - function model() - { - return 'Webkul\Discount\Contracts\CartRuleChannels'; - } -} diff --git a/packages/Webkul/Discount/src/Repositories/CartRuleCouponsRepository.php b/packages/Webkul/Discount/src/Repositories/CartRuleCouponsRepository.php deleted file mode 100644 index 8b0e53f99..000000000 --- a/packages/Webkul/Discount/src/Repositories/CartRuleCouponsRepository.php +++ /dev/null @@ -1,24 +0,0 @@ - @prashant-webkul - * @copyright 2019 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class CartRuleCouponsRepository extends Repository -{ - /** - * Specify Model class name - * - * @return mixed - */ - function model() - { - return 'Webkul\Discount\Contracts\CartRuleCoupons'; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Repositories/CartRuleCustomerGroupsRepository.php b/packages/Webkul/Discount/src/Repositories/CartRuleCustomerGroupsRepository.php deleted file mode 100644 index cfd4dbe75..000000000 --- a/packages/Webkul/Discount/src/Repositories/CartRuleCustomerGroupsRepository.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @copyright 2019 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class CartRuleCustomerGroupsRepository extends Repository -{ - /** - * Specify Model class name - * - * @return mixed - */ - function model() - { - return 'Webkul\Discount\Contracts\CartRuleCustomerGroups'; - } -} diff --git a/packages/Webkul/Discount/src/Repositories/CartRuleLabelsRepository.php b/packages/Webkul/Discount/src/Repositories/CartRuleLabelsRepository.php deleted file mode 100644 index 2a4d03be7..000000000 --- a/packages/Webkul/Discount/src/Repositories/CartRuleLabelsRepository.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @copyright 2019 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class CartRuleLabelsRepository extends Repository -{ - /** - * Specify Model class name - * - * @return mixed - */ - function model() - { - return 'Webkul\Discount\Contracts\CartRuleLabels'; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Repositories/CartRuleRepository.php b/packages/Webkul/Discount/src/Repositories/CartRuleRepository.php deleted file mode 100644 index 6005f8d0f..000000000 --- a/packages/Webkul/Discount/src/Repositories/CartRuleRepository.php +++ /dev/null @@ -1,205 +0,0 @@ - - * @copyright 2019 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class CartRuleRepository extends Repository -{ - /** - * Will hold cartRuleChannelsRepository instance - */ - protected $cartRuleChannels; - - /** - * Will hold cartRuleCustomerGroupsRepository instance - */ - protected $cartRuleCustomerGroups; - - /** - * Will hold cartRuleCoupons instance - */ - protected $cartRuleCoupons; - - /** - * Will hold cartRuleCustomerGroupsRepository instance - */ - protected $cartRuleLabels; - - /** - * @param CartRuleChannels $cartRuleChannels - * @param CartRuleCustomerGroups $cartRuleCustomerGroups - * @param CartRuleCoupons $cartRuleCoupons - * @param - */ - public function __construct( - CartRuleChannels $cartRuleChannels, - CartRuleCustomerGroups $cartRuleCustomerGroups, - CartRuleCoupons $cartRuleCoupons, - CartRuleLabels $cartRuleLabels, - App $app - ) { - $this->cartRuleChannels = $cartRuleChannels; - $this->cartRuleCustomerGroups = $cartRuleCustomerGroups; - $this->cartRuleCoupons = $cartRuleCoupons; - $this->cartRuleLabel = $cartRuleLabels; - - parent::__construct($app); - } - - /** - * Specify Model class name - * - * @return mixed - */ - function model() - { - return 'Webkul\Discount\Contracts\CartRule'; - } - - /** - * To sync the customer groups related records - */ - public function CustomerGroupSync($newCustomerGroups, $cartRule) - { - $oldCustomerGroups = array(); - foreach ($cartRule->customer_groups as $oldCustomerGroup) { - array_push($oldCustomerGroups, ['id' => $oldCustomerGroup->id, 'customer_group_id' => $oldCustomerGroup->customer_group_id]); - } - - foreach ($oldCustomerGroups as $key => $oldCustomerGroup) { - $found = 0; - foreach ($newCustomerGroups as $newCustomerGroup) { - if ($oldCustomerGroup['customer_group_id'] == $newCustomerGroup) - $found = 1; - } - - if ($found == 0) { - $this->cartRuleCustomerGroups->find($oldCustomerGroup['id'])->delete(); - } else { - $found = 0; - } - } - - //unset the commons - if (count($newCustomerGroups) && count($oldCustomerGroups)) { - foreach ($oldCustomerGroups as $oldCustomerGroup) { - $found = 0; - foreach ($newCustomerGroups as $key => $newCustomerGroup) { - if ($oldCustomerGroup['customer_group_id'] == $newCustomerGroup) - unset($newCustomerGroups[$key]); - } - } - } - - //create the left ones - foreach ($newCustomerGroups as $newCustomerGroup) { - $data['customer_group_id'] = $newCustomerGroup; - $data['cart_rule_id'] = $cartRule->id; - - $this->cartRuleCustomerGroups->create($data); - } - - return true; - } - - /** - * To sync the channels related records - */ - public function ChannelSync($newChannels, $cartRule) - { - $oldChannels = array(); - - foreach ($cartRule->channels as $oldChannel) { - array_push($oldChannels, ['id' => $oldChannel->id, 'channel_id' => $oldChannel->channel_id]); - } - - foreach ($oldChannels as $key => $oldChannel) { - $found = 0; - foreach ($newChannels as $newChannel) { - if ($oldChannel['channel_id'] == $newChannel) - $found = 1; - } - - if ($found == 0) { - $this->cartRuleChannels->find($oldChannel['id'])->delete(); - } else { - $found = 0; - } - } - - //unset the commons - if (count($newChannels) && count($oldChannels)) { - foreach ($oldChannels as $oldChannel) { - $found = 0; - - foreach ($newChannels as $key => $newChannel) { - if ($oldChannel['channel_id'] == $newChannel) - unset($newChannels[$key]); - } - } - } - - //create the left ones - foreach ($newChannels as $newChannel) { - $data['channel_id'] = $newChannel; - $data['cart_rule_id'] = $cartRule->id; - - $this->cartRuleChannels->create($data); - } - - return true; - } - - /** - * To sync the labels associated with the cart rule - */ - public function LabelSync($labels, $cartRule) - { - foreach ($labels as $channelCode => $value) { - $localeCode = array_keys($value)[0]; - $localeValue = array_values($value)[0]; - - $updated = 0; - foreach ($cartRule->labels as $label) { - if ($label->channel->code == $channelCode && $label->locale->code == $localeCode) { - $label->update(['label' => $localeValue]); - - $updated = 1; - } - } - - if ($updated == 0) { - foreach (core()->getAllChannels() as $channel) { - if ($channel->code == $channelCode) - $newLabel['channel_id'] = $channel->id; - - foreach($channel->locales as $locale) { - if ($localeCode == $locale->code) { - $newLabel['locale_id'] = $locale->id; - $newLabel['label'] = $localeValue; - $newLabel['cart_rule_id'] = $cartRule->id; - - $ruleLabelCreated = $this->CartRuleLabels->create($newLabel); - } - } - } - } - - $updated = 0; - } - - return true; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Repositories/CatalogRuleChannelsRepository.php b/packages/Webkul/Discount/src/Repositories/CatalogRuleChannelsRepository.php deleted file mode 100644 index 50ade8dbc..000000000 --- a/packages/Webkul/Discount/src/Repositories/CatalogRuleChannelsRepository.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @copyright 2019 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class CatalogRuleChannelsRepository extends Repository -{ - /** - * Specify Model class name - * - * @return String - */ - function model() - { - return 'Webkul\Discount\Contracts\CatalogRuleChannels'; - } -} diff --git a/packages/Webkul/Discount/src/Repositories/CatalogRuleCustomerGroupsRepository.php b/packages/Webkul/Discount/src/Repositories/CatalogRuleCustomerGroupsRepository.php deleted file mode 100644 index 2d7184610..000000000 --- a/packages/Webkul/Discount/src/Repositories/CatalogRuleCustomerGroupsRepository.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @copyright 2019 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class CatalogRuleCustomerGroupsRepository extends Repository -{ - /** - * Specify Model class name - * - * @return String - */ - function model() - { - return 'Webkul\Discount\Contracts\CatalogRuleCustomerGroups'; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Repositories/CatalogRuleProductsPriceRepository.php b/packages/Webkul/Discount/src/Repositories/CatalogRuleProductsPriceRepository.php deleted file mode 100644 index 5becbb9eb..000000000 --- a/packages/Webkul/Discount/src/Repositories/CatalogRuleProductsPriceRepository.php +++ /dev/null @@ -1,51 +0,0 @@ - @prashant-webkul - * @copyright 2019 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class CatalogRuleProductsPriceRepository extends Repository -{ - /** - * To hold ProductRepository instance - */ - protected $product; - - /** - * To hold CatalogRuleProductRepository instance - * - */ - protected $catalogRuleProduct; - - /** - * @param Product $product - */ - public function __construct(Product $product, CatalogRuleProduct $catalogRuleProduct,App $app) - { - - $this->product = $product; - - $this->catalogRuleProduct = $catalogRuleProduct; - - parent::__construct($app); - } - - /** - * Specify Model class name - * - * @return String - */ - function model() - { - return 'Webkul\Discount\Contracts\CatalogRuleProductsPrice'; - } -} \ No newline at end of file diff --git a/packages/Webkul/Discount/src/Repositories/CatalogRuleProductsRepository.php b/packages/Webkul/Discount/src/Repositories/CatalogRuleProductsRepository.php deleted file mode 100644 index aedf092fd..000000000 --- a/packages/Webkul/Discount/src/Repositories/CatalogRuleProductsRepository.php +++ /dev/null @@ -1,39 +0,0 @@ - @prashant-webkul - * @copyright 2019 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class CatalogRuleProductsRepository extends Repository -{ - /** - * CatalogRule Apply instance - */ - protected $apply; - - /** - * @param App $app - */ - public function __construct(App $app) - { - parent::__construct($app); - } - - /** - * Specify Model class name - * - * @return String - */ - function model() - { - return 'Webkul\Discount\Contracts\CatalogRuleProducts'; - } -} diff --git a/packages/Webkul/Discount/src/Repositories/CatalogRuleRepository.php b/packages/Webkul/Discount/src/Repositories/CatalogRuleRepository.php deleted file mode 100644 index da6b684ae..000000000 --- a/packages/Webkul/Discount/src/Repositories/CatalogRuleRepository.php +++ /dev/null @@ -1,155 +0,0 @@ - - * @copyright 2019 Webkul Software Pvt Ltd (http://www.webkul.com) - */ -class CatalogRuleRepository extends Repository -{ - /** - * Will hold catalogRuleChannelsRepository instance - */ - protected $catalogRuleChannels; - - /** - * Will hold catalogRuleCustomerGroupsRepository instance - */ - protected $catalogRuleCustomerGroups; - - /** - * @param CatalogRuleChannels $catalogRuleChannels - * @param CatalogRuleCustomerGroups $catalogRuleCustomerGroups - * @param App $app - */ - public function __construct(CatalogRuleChannels $catalogRuleChannels, CatalogRuleCustomerGroups $catalogRuleCustomerGroups, App $app) - { - $this->catalogRuleChannels = $catalogRuleChannels; - - $this->catalogRuleCustomerGroups = $catalogRuleCustomerGroups; - - parent::__construct($app); - } - - /** - * Specify Model class name - * - * @return String - */ - function model() - { - return 'Webkul\Discount\Contracts\CatalogRule'; - } - - /** - * To sync the customer groups related records - * - * @param Array $newCustomerGroups - * @param CatalogRule $catalogRule - * - * @return Boolean - */ - public function CustomerGroupSync($newCustomerGroups, $catalogRule) - { - $oldCustomerGroups = array(); - foreach ($catalogRule->customer_groups as $oldCustomerGroup) { - array_push($oldCustomerGroups, ['id' => $oldCustomerGroup->id, 'customer_group_id' => $oldCustomerGroup->customer_group_id]); - } - - foreach ($oldCustomerGroups as $key => $oldCustomerGroup) { - $found = 0; - - foreach($newCustomerGroups as $newCustomerGroup) { - if ($oldCustomerGroup['customer_group_id'] == $newCustomerGroup) - $found = 1; - } - - if ($found == 0) { - $this->catalogRuleCustomerGroups->find($oldCustomerGroup['id'])->delete(); - } else { - $found = 0; - } - } - - //unset the commons - if (count($newCustomerGroups) && count($oldCustomerGroups)) { - foreach ($oldCustomerGroups as $oldCustomerGroup) { - $found = 0; - - foreach ($newCustomerGroups as $key => $newCustomerGroup) { - if ($oldCustomerGroup['customer_group_id'] == $newCustomerGroup) - unset($newCustomerGroups[$key]); - } - } - } - - //create the left ones - foreach ($newCustomerGroups as $newCustomerGroup) { - $data['customer_group_id'] = $newCustomerGroup; - $data['catalog_rule_id'] = $catalogRule->id; - - $this->catalogRuleCustomerGroups->create($data); - } - - return true; - } - - /** - * To sync the channels related records - * - * @param Array $newChannels - * @param CatalogRule $catalogRule - * - * @return Boolean - */ - public function ChannelSync($newChannels, $catalogRule) - { - $oldChannels = array(); - foreach ($catalogRule->channels as $oldChannel) { - array_push($oldChannels, ['id' => $oldChannel->id, 'channel_id' => $oldChannel->channel_id]); - } - - foreach ($oldChannels as $key => $oldChannel) { - $found = 0; - foreach($newChannels as $newChannel) { - if ($oldChannel['channel_id'] == $newChannel) - $found = 1; - } - - if ($found == 0) { - $this->catalogRuleChannels->find($oldChannel['id'])->delete(); - } else { - $found = 0; - } - } - - //unset the commons - if (count($newChannels) && count($oldChannels)) { - foreach ($oldChannels as $oldChannel) { - $found = 0; - - foreach ($newChannels as $key => $newChannel) { - if ($oldChannel['channel_id'] == $newChannel) - unset($newChannels[$key]); - } - } - } - - //create the left ones - foreach ($newChannels as $newChannel) { - $data['channel_id'] = $newChannel; - $data['catalog_rule_id'] = $catalogRule->id; - $this->catalogRuleChannels->create($data); - } - - return true; - } -} \ No newline at end of file diff --git a/packages/Webkul/Rule/src/Helpers/Validator.php b/packages/Webkul/Rule/src/Helpers/Validator.php new file mode 100644 index 000000000..06a623f43 --- /dev/null +++ b/packages/Webkul/Rule/src/Helpers/Validator.php @@ -0,0 +1,190 @@ +conditions) + return true; + + $validConditionCount = $totalConditionCount = 0; + + foreach ($rule->conditions as $condition) { + if (! $condition['attribute'] || ! isset($condition['value']) || is_null($condition['value']) || $condition['value'] == '') + continue; + + if ($entity instanceof \Webkul\Checkout\Contracts\Cart && strpos($condition['attribute'], 'cart|') === false) + continue; + + $totalConditionCount++; + + $attributeValue = $this->getAttributeValue($condition, $entity); + + if ($rule->condition_type == 1) { + if (! $this->validateAttribute($condition['operator'], $attributeValue, $condition['value'])) { + return false; + } else { + $validConditionCount++; + } + } else { + if ($this->validateAttribute($condition['operator'], $attributeValue, $condition['value'])) + return true; + } + } + + return $validConditionCount == $totalConditionCount ? true : false; + } + + /** + * Return value for the attribute + * + * @param array $condition + * @param Cart|CartItem|Product $entity + * @return boolean + */ + public function getAttributeValue($condition, $entity) + { + $chunks = explode('|', $condition['attribute']); + + $attributeNameChunks = explode('::', $chunks[1]); + + $attributeCode = $attributeNameChunks[count($attributeNameChunks) - 1]; + + $attributeScope = count($attributeNameChunks) == 2 ? $attributeNameChunks[0] : null; + + switch (current($chunks)) { + case 'cart': + $cart = $entity instanceof \Webkul\Checkout\Contracts\Cart ? $entity : $entity->cart; + + if (in_array($attributeCode, ['postcode', 'state', 'country'])) { + if (! $cart->shipping_address) + return; + + return $cart->shipping_address->{$attributeCode}; + } else if ($attributeCode == 'shipping_method') { + if (! $cart->shipping_method) + return; + + $shippingChunks = explode('_', $cart->shipping_method); + + return current($shippingChunks); + } else if ($attributeCode == 'payment_method') { + if (! $cart->payment) + return; + + return $cart->payment->method; + } else { + return $cart->{$attributeCode}; + } + + case 'cart_item': + return $entity->{$attributeCode}; + + case 'product': + if ($attributeCode == 'category_ids') { + $value = $attributeScope == 'children' + ? ($entity->child ? $entity->child->product->categories()->pluck('id')->toArray() : []) + : ($entity->product + ? $entity->product->categories()->pluck('id')->toArray() + : $entity->categories()->pluck('id')->toArray() + ); + + return $value; + } else { + $value = $attributeScope == 'children' + ? ($entity->child ? $entity->child->product->{$attributeCode} : null) + : ($entity->product ? $entity->product->{$attributeCode} : $entity->{$attributeCode}); + + if (! in_array($condition['attribute_type'], ['multiselect', 'checkbox'])) + return $value; + + return $value ? explode(',', $value) : []; + } + } + } + + /** + * Validate attribute value for condition + * + * @param string $operator + * @param mixed $attributeValue + * @param mixed $conditionValue + * @return boolean + */ + public function validateAttribute($operator, $attributeValue, $conditionValue) + { + switch ($operator) { + case '==': case '!=': + if (is_array($conditionValue)) { + if (! is_array($attributeValue)) + return false; + + $result = ! empty(array_intersect($conditionValue, $attributeValue)); + } else { + if (is_array($attributeValue)) { + $result = count($attributeValue) == 1 && array_shift($attributeValue) == $conditionValue; + } else { + $result = $attributeValue == $conditionValue; + } + } + + break; + + case '<=': case '>': + if (! is_scalar($attributeValue)) + return false; + + $result = $attributeValue <= $conditionValue; + + break; + + case '>=': case '<': + if (! is_scalar($attributeValue)) + return false; + + $result = $attributeValue >= $conditionValue; + + break; + + case '{}': case '!{}': + if (is_scalar($attributeValue) && is_array($conditionValue)) { + foreach ($conditionValue as $item) { + if (stripos($attributeValue, $item) !== false) { + $result = true; + + break; + } + } + } else if (is_array($conditionValue)) { + if (! is_array($attributeValue)) + return false; + + $result = ! empty(array_intersect($conditionValue, $attributeValue)); + } else { + if (is_array($attributeValue)) { + $result = in_array($conditionValue, $attributeValue); + } else { + $result = (strpos($attributeValue, $conditionValue) !== false) ? true : false; + } + } + + break; + } + + if (in_array($operator, ['!=', '>', '<', '!{}'])) + $result = ! $result; + + return $result; + } +} \ No newline at end of file diff --git a/packages/Webkul/Rule/src/Providers/RuleServiceProvider.php b/packages/Webkul/Rule/src/Providers/RuleServiceProvider.php new file mode 100644 index 000000000..2a48f4d5d --- /dev/null +++ b/packages/Webkul/Rule/src/Providers/RuleServiceProvider.php @@ -0,0 +1,26 @@ + Date: Sat, 21 Dec 2019 13:01:16 +0530 Subject: [PATCH 07/84] Added changes on core packages for discount --- .../assets/sass/partials/_configuration.scss | 25 ++++ .../src/Helpers/CatalogRuleProduct.php | 3 + packages/Webkul/Checkout/src/Cart.php | 43 ++++++- ...ied_cart_rule_ids_column_in_cart_table.php | 32 +++++ ...rt_rule_ids_column_in_cart_items_table.php | 32 +++++ ...t_columns_in_cart_shipping_rates_table.php | 33 +++++ .../Checkout/src/Models/CartShippingRate.php | 2 +- ...d_cart_rule_ids_column_in_orders_table.php | 32 +++++ .../src/Http/Controllers/CartController.php | 48 +++++++ packages/Webkul/Shop/src/Http/routes.php | 6 +- .../Shop/src/Resources/assets/sass/app.scss | 26 ++++ .../views/checkout/cart/coupon.blade.php | 119 ++++++++++++++++++ 12 files changed, 395 insertions(+), 6 deletions(-) create mode 100644 packages/Webkul/Checkout/src/Database/Migrations/2019_11_25_171136_add_applied_cart_rule_ids_column_in_cart_table.php create mode 100644 packages/Webkul/Checkout/src/Database/Migrations/2019_11_25_171208_add_applied_cart_rule_ids_column_in_cart_items_table.php create mode 100644 packages/Webkul/Checkout/src/Database/Migrations/2019_11_30_165644_add_discount_columns_in_cart_shipping_rates_table.php create mode 100644 packages/Webkul/Sales/src/Database/Migrations/2019_11_30_124437_add_applied_cart_rule_ids_column_in_orders_table.php create mode 100644 packages/Webkul/Shop/src/Resources/views/checkout/cart/coupon.blade.php diff --git a/packages/Webkul/Admin/src/Resources/assets/sass/partials/_configuration.scss b/packages/Webkul/Admin/src/Resources/assets/sass/partials/_configuration.scss index 2e2b3258d..c66e1bda9 100644 --- a/packages/Webkul/Admin/src/Resources/assets/sass/partials/_configuration.scss +++ b/packages/Webkul/Admin/src/Resources/assets/sass/partials/_configuration.scss @@ -48,4 +48,29 @@ border-bottom: 1px solid #e8e8e8; cursor: pointer; } +} + +.cart-rule-conditions, +.catalog-rule-conditions { + table { + td { + &.attribute { + width: 250px; + padding-left: 0; + } + + &.operator, + &.value { + width: 260px; + } + + &.actions { + width: 44px; + + .icon { + margin-top: 6px; + } + } + } + } } \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php index 31a046554..f700fb5fe 100644 --- a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php +++ b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php @@ -130,6 +130,9 @@ class CatalogRuleProduct if ($product) $qb->where('products.id', $product->id); + if (! $rule->conditions) + return $qb; + foreach ($rule->conditions as $condition) { if (! $condition['attribute'] || ! $condition['value']) continue; diff --git a/packages/Webkul/Checkout/src/Cart.php b/packages/Webkul/Checkout/src/Cart.php index 7ac80d9fb..8d772a56c 100755 --- a/packages/Webkul/Checkout/src/Cart.php +++ b/packages/Webkul/Checkout/src/Cart.php @@ -638,11 +638,15 @@ class Cart { } if ($shipping = $cart->selected_shipping_rate) { - $cart->grand_total = (float) $cart->grand_total + $shipping->price; - $cart->base_grand_total = (float) $cart->base_grand_total + $shipping->base_price; + $cart->grand_total = (float) $cart->grand_total + $shipping->price - $shipping->discount_amount; + $cart->base_grand_total = (float) $cart->base_grand_total + $shipping->base_price - $shipping->base_discount_amount; + + $cart->discount_amount += $shipping->discount_amount; + $cart->base_discount_amount += $shipping->base_discount_amount; } $quantities = 0; + foreach ($cart->items as $item) { $quantities = $quantities + $item->quantity; } @@ -839,6 +843,8 @@ class Cart { 'base_sub_total' => $data['base_sub_total'], 'tax_amount' => $data['tax_total'], 'base_tax_amount' => $data['base_tax_total'], + 'coupon_code' => $data['coupon_code'], + 'applied_cart_rule_ids' => $data['applied_cart_rule_ids'], 'discount_amount' => $data['discount_amount'], 'base_discount_amount' => $data['base_discount_amount'], 'billing_address' => array_except($data['billing_address'], ['id', 'cart_id']), @@ -976,4 +982,37 @@ class Cart { return true; } + + /** + * Set coupon code to the cart + * + * @param string $code + * @return Cart + */ + public function setCouponCode($code) + { + $cart = $this->getCart(); + + $cart->coupon_code = $code; + + $cart->save(); + + return $this; + } + + /** + * Remove coupon code from cart + * + * @return Cart + */ + public function removeCouponCode() + { + $cart = $this->getCart(); + + $cart->coupon_code = null; + + $cart->save(); + + return $this; + } } \ No newline at end of file diff --git a/packages/Webkul/Checkout/src/Database/Migrations/2019_11_25_171136_add_applied_cart_rule_ids_column_in_cart_table.php b/packages/Webkul/Checkout/src/Database/Migrations/2019_11_25_171136_add_applied_cart_rule_ids_column_in_cart_table.php new file mode 100644 index 000000000..b6423d3be --- /dev/null +++ b/packages/Webkul/Checkout/src/Database/Migrations/2019_11_25_171136_add_applied_cart_rule_ids_column_in_cart_table.php @@ -0,0 +1,32 @@ +string('applied_cart_rule_ids')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('cart', function (Blueprint $table) { + // + }); + } +} diff --git a/packages/Webkul/Checkout/src/Database/Migrations/2019_11_25_171208_add_applied_cart_rule_ids_column_in_cart_items_table.php b/packages/Webkul/Checkout/src/Database/Migrations/2019_11_25_171208_add_applied_cart_rule_ids_column_in_cart_items_table.php new file mode 100644 index 000000000..cb22375bf --- /dev/null +++ b/packages/Webkul/Checkout/src/Database/Migrations/2019_11_25_171208_add_applied_cart_rule_ids_column_in_cart_items_table.php @@ -0,0 +1,32 @@ +string('applied_cart_rule_ids')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('cart_items', function (Blueprint $table) { + // + }); + } +} diff --git a/packages/Webkul/Checkout/src/Database/Migrations/2019_11_30_165644_add_discount_columns_in_cart_shipping_rates_table.php b/packages/Webkul/Checkout/src/Database/Migrations/2019_11_30_165644_add_discount_columns_in_cart_shipping_rates_table.php new file mode 100644 index 000000000..8c7b48e44 --- /dev/null +++ b/packages/Webkul/Checkout/src/Database/Migrations/2019_11_30_165644_add_discount_columns_in_cart_shipping_rates_table.php @@ -0,0 +1,33 @@ +decimal('discount_amount', 12, 4)->default(0); + $table->decimal('base_discount_amount', 12, 4)->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('cart_shipping_rates', function (Blueprint $table) { + // + }); + } +} diff --git a/packages/Webkul/Checkout/src/Models/CartShippingRate.php b/packages/Webkul/Checkout/src/Models/CartShippingRate.php index 6ecf168cb..7c4447e33 100755 --- a/packages/Webkul/Checkout/src/Models/CartShippingRate.php +++ b/packages/Webkul/Checkout/src/Models/CartShippingRate.php @@ -7,7 +7,7 @@ use Webkul\Checkout\Contracts\CartShippingRate as CartShippingRateContract; class CartShippingRate extends Model implements CartShippingRateContract { - protected $fillable = ['carrier', 'carrier_title', 'method', 'method_title', 'method_description', 'price', 'base_price']; + protected $fillable = ['carrier', 'carrier_title', 'method', 'method_title', 'method_description', 'price', 'base_price', 'discount_amount', 'base_discount_amount']; /** * Get the post that owns the comment. diff --git a/packages/Webkul/Sales/src/Database/Migrations/2019_11_30_124437_add_applied_cart_rule_ids_column_in_orders_table.php b/packages/Webkul/Sales/src/Database/Migrations/2019_11_30_124437_add_applied_cart_rule_ids_column_in_orders_table.php new file mode 100644 index 000000000..6ee96be4b --- /dev/null +++ b/packages/Webkul/Sales/src/Database/Migrations/2019_11_30_124437_add_applied_cart_rule_ids_column_in_orders_table.php @@ -0,0 +1,32 @@ +string('applied_cart_rule_ids')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('orders', function (Blueprint $table) { + // + }); + } +} diff --git a/packages/Webkul/Shop/src/Http/Controllers/CartController.php b/packages/Webkul/Shop/src/Http/Controllers/CartController.php index b23c42b4c..ddd139e7e 100755 --- a/packages/Webkul/Shop/src/Http/Controllers/CartController.php +++ b/packages/Webkul/Shop/src/Http/Controllers/CartController.php @@ -155,4 +155,52 @@ class CartController extends Controller return redirect()->back(); } + + /** + * Apply coupon to the cart + * + * @return \Illuminate\Http\JsonResponse + */ + public function applyCoupon() + { + $couponCode = request()->get('code'); + + try { + if (strlen($couponCode)) { + Cart::setCouponCode($couponCode)->collectTotals(); + + if (Cart::getCart()->coupon_code == $couponCode) { + return response()->json([ + 'success' => true, + 'message' => trans('shop::app.checkout.total.success-coupon') + ]); + } + } + + return response()->json([ + 'success' => false, + 'message' => trans('shop::app.checkout.total.invalid-coupon') + ]); + } catch (\Exception $e) { + return response()->json([ + 'success' => false, + 'message' => trans('shop::app.checkout.total.coupon-apply-issue') + ]); + } + } + + /** + * Apply coupon to the cart + * + * @return \Illuminate\Http\JsonResponse + */ + public function removeCoupon() + { + Cart::removeCouponCode()->collectTotals(); + + return response()->json([ + 'success' => true, + 'message' => trans('shop::app.checkout.total.remove-coupon') + ]); + } } \ No newline at end of file diff --git a/packages/Webkul/Shop/src/Http/routes.php b/packages/Webkul/Shop/src/Http/routes.php index 129c625fa..2ba7c3ff9 100755 --- a/packages/Webkul/Shop/src/Http/routes.php +++ b/packages/Webkul/Shop/src/Http/routes.php @@ -34,10 +34,10 @@ Route::group(['middleware' => ['web', 'locale', 'theme', 'currency']], function 'view' => 'shop::checkout.cart.index' ])->name('shop.checkout.cart.index'); - Route::post('checkout/check/coupons', 'Webkul\Shop\Http\Controllers\OnepageController@applyCoupon')->name('shop.checkout.check.coupons'); - - Route::post('checkout/remove/coupon', 'Webkul\Shop\Http\Controllers\OnepageController@removeCoupon')->name('shop.checkout.remove.coupon'); + Route::post('checkout/cart/coupon', 'Webkul\Shop\Http\Controllers\CartController@applyCoupon')->name('shop.checkout.cart.coupon.apply'); + Route::delete('checkout/cart/coupon', 'Webkul\Shop\Http\Controllers\CartController@removeCoupon')->name('shop.checkout.coupon.remove.coupon'); + //Cart Items Add Route::post('checkout/cart/add/{id}', 'Webkul\Shop\Http\Controllers\CartController@add')->defaults('_config', [ 'redirect' => 'shop.checkout.cart.index' diff --git a/packages/Webkul/Shop/src/Resources/assets/sass/app.scss b/packages/Webkul/Shop/src/Resources/assets/sass/app.scss index 6b4e35b19..4f6ae0e9b 100755 --- a/packages/Webkul/Shop/src/Resources/assets/sass/app.scss +++ b/packages/Webkul/Shop/src/Resources/assets/sass/app.scss @@ -2478,6 +2478,32 @@ section.cart { } } +.coupon-container { + .discount-control { + .control-group { + margin-top: 20px; + + .control { + width: 100%; + } + } + } + + .applied-coupon-details { + margin-top: 30px; + + .right { + float: right; + + .icon { + vertical-align: text-bottom; + margin-bottom: 1px; + cursor: pointer; + } + } + } +} + .order-summary { h3 { font-size: 16px; diff --git a/packages/Webkul/Shop/src/Resources/views/checkout/cart/coupon.blade.php b/packages/Webkul/Shop/src/Resources/views/checkout/cart/coupon.blade.php new file mode 100644 index 000000000..090740935 --- /dev/null +++ b/packages/Webkul/Shop/src/Resources/views/checkout/cart/coupon.blade.php @@ -0,0 +1,119 @@ +@if ($cart) + + + +@endif \ No newline at end of file From 795561ea58608bc96d81c1afcf89c7f4b6900dcc Mon Sep 17 00:00:00 2001 From: jitendra Date: Sat, 21 Dec 2019 16:00:22 +0530 Subject: [PATCH 08/84] Made all changes for discount packages --- .../src/DataGrids/CartRuleCouponDataGrid.php | 86 ++++++++++++ .../views/sales/orders/view.blade.php | 8 +- .../Webkul/CartRule/src/Helpers/CartRule.php | 2 + .../Webkul/CartRule/src/Listeners/Cart.php | 29 ++++ .../src/Providers/EventServiceProvider.php | 2 + .../src/Helpers/CatalogRuleProduct.php | 3 +- packages/Webkul/Checkout/src/Models/Cart.php | 2 - .../Http/Controllers/OnepageController.php | 132 ++++++------------ .../Webkul/Shop/src/Resources/lang/en/app.php | 11 +- .../views/checkout/cart/index.blade.php | 3 + .../views/checkout/onepage.blade.php | 77 ++-------- .../views/checkout/total/summary.blade.php | 39 +----- 12 files changed, 194 insertions(+), 200 deletions(-) create mode 100644 packages/Webkul/Admin/src/DataGrids/CartRuleCouponDataGrid.php diff --git a/packages/Webkul/Admin/src/DataGrids/CartRuleCouponDataGrid.php b/packages/Webkul/Admin/src/DataGrids/CartRuleCouponDataGrid.php new file mode 100644 index 000000000..ccf8c6375 --- /dev/null +++ b/packages/Webkul/Admin/src/DataGrids/CartRuleCouponDataGrid.php @@ -0,0 +1,86 @@ + + * @copyright 2018 Webkul Software Pvt Ltd (http://www.webkul.com) + */ +class CartRuleCouponDataGrid extends DataGrid +{ + protected $index = 'id'; + + protected $sortOrder = 'desc'; + + public function prepareQueryBuilder() + { + $queryBuilder = DB::table('cart_rule_coupons') + ->addSelect('id', 'code', 'created_at', 'expired_at', 'times_used') + ->where('cart_rule_coupons.cart_rule_id', request('id')); + + $this->setQueryBuilder($queryBuilder); + } + + public function addColumns() + { + $this->addColumn([ + 'index' => 'id', + 'label' => trans('admin::app.datagrid.id'), + 'type' => 'number', + 'searchable' => false, + 'sortable' => true, + 'filterable' => true + ]); + + $this->addColumn([ + 'index' => 'code', + 'label' => trans('admin::app.datagrid.coupon-code'), + 'type' => 'string', + 'searchable' => true, + 'sortable' => true, + 'filterable' => true + ]); + + $this->addColumn([ + 'index' => 'created_at', + 'label' => trans('admin::app.datagrid.created-date'), + 'type' => 'datetime', + 'sortable' => true, + 'searchable' => false, + 'filterable' => true + ]); + + $this->addColumn([ + 'index' => 'expired_at', + 'label' => trans('admin::app.datagrid.expiration-date'), + 'type' => 'datetime', + 'sortable' => true, + 'searchable' => false, + 'filterable' => true + ]); + + $this->addColumn([ + 'index' => 'times_used', + 'label' => trans('admin::app.datagrid.times-used'), + 'type' => 'number', + 'searchable' => true, + 'sortable' => true, + 'filterable' => true + ]); + } + + public function prepareMassActions() + { + $this->addMassAction([ + 'type' => 'delete', + 'action' => route('admin.cart-rule-coupons.mass-delete'), + 'label' => trans('admin::app.datagrid.delete'), + 'method' => 'DELETE' + ]); + } +} diff --git a/packages/Webkul/Admin/src/Resources/views/sales/orders/view.blade.php b/packages/Webkul/Admin/src/Resources/views/sales/orders/view.blade.php index c635af49e..a1b28cbd0 100755 --- a/packages/Webkul/Admin/src/Resources/views/sales/orders/view.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/sales/orders/view.blade.php @@ -332,7 +332,13 @@ @if ($order->base_discount_amount > 0) - {{ __('admin::app.sales.orders.discount') }} + + {{ __('admin::app.sales.orders.discount') }} + + @if ($order->coupon_code) + ({{ $order->coupon_code }}) + @endif + - {{ core()->formatBasePrice($order->base_discount_amount) }} diff --git a/packages/Webkul/CartRule/src/Helpers/CartRule.php b/packages/Webkul/CartRule/src/Helpers/CartRule.php index faef6fa22..942fe77ea 100644 --- a/packages/Webkul/CartRule/src/Helpers/CartRule.php +++ b/packages/Webkul/CartRule/src/Helpers/CartRule.php @@ -380,6 +380,8 @@ class CartRule break; } + $selectedShipping->save(); + $cartAppliedCartRuleIds = array_merge(explode(',', $cart->applied_cart_rule_ids), $appliedRuleIds); $cartAppliedCartRuleIds = array_filter($cartAppliedCartRuleIds); diff --git a/packages/Webkul/CartRule/src/Listeners/Cart.php b/packages/Webkul/CartRule/src/Listeners/Cart.php index f886166b4..f039059c1 100644 --- a/packages/Webkul/CartRule/src/Listeners/Cart.php +++ b/packages/Webkul/CartRule/src/Listeners/Cart.php @@ -2,6 +2,8 @@ namespace Webkul\CartRule\Listeners; +use Webkul\CartRule\Helpers\CartRule; + /** * Cart event handler * @@ -10,5 +12,32 @@ namespace Webkul\CartRule\Listeners; */ class Cart { + /** + * CartRule object + * + * @var CartRule + */ + protected $cartRuleHepler; + /** + * Create a new listener instance. + * + * @param Webkul\CartRule\Repositories\CartRule $cartRuleHepler + * @return void + */ + public function __construct(CartRule $cartRuleHepler) + { + $this->cartRuleHepler = $cartRuleHepler; + } + + /** + * Aplly valid cart rules to cart + * + * @param Cart $cart + * @return void + */ + public function applyCartRules($cart) + { + $this->cartRuleHepler->collect(); + } } \ No newline at end of file diff --git a/packages/Webkul/CartRule/src/Providers/EventServiceProvider.php b/packages/Webkul/CartRule/src/Providers/EventServiceProvider.php index a935da915..a5b5d7133 100755 --- a/packages/Webkul/CartRule/src/Providers/EventServiceProvider.php +++ b/packages/Webkul/CartRule/src/Providers/EventServiceProvider.php @@ -15,5 +15,7 @@ class EventServiceProvider extends ServiceProvider public function boot() { Event::listen('checkout.order.save.after', 'Webkul\CartRule\Listeners\Order@manageCartRule'); + + Event::listen('checkout.cart.collect.totals.before', 'Webkul\CartRule\Listeners\Cart@applyCartRules'); } } \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php index f700fb5fe..5be4b124f 100644 --- a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php +++ b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php @@ -134,7 +134,7 @@ class CatalogRuleProduct return $qb; foreach ($rule->conditions as $condition) { - if (! $condition['attribute'] || ! $condition['value']) + if (! $condition['attribute'] || ! isset($condition['value']) || is_null($condition['value']) || $condition['value'] == '') continue; $chunks = explode('|', $condition['attribute']); @@ -204,6 +204,7 @@ class CatalogRuleProduct ->orderBy('channel_id', 'asc') ->orderBy('customer_group_id', 'asc') ->orderBy('product_id', 'asc') + ->orderBy('sort_order', 'asc') ->orderBy('catalog_rule_id', 'asc'); if ($product) { diff --git a/packages/Webkul/Checkout/src/Models/Cart.php b/packages/Webkul/Checkout/src/Models/Cart.php index 01cddea2b..9088531fa 100755 --- a/packages/Webkul/Checkout/src/Models/Cart.php +++ b/packages/Webkul/Checkout/src/Models/Cart.php @@ -12,8 +12,6 @@ class Cart extends Model implements CartContract protected $guarded = ['id', 'created_at', 'updated_at']; - protected $hidden = ['coupon_code']; - protected $with = ['items', 'items.children']; /** diff --git a/packages/Webkul/Shop/src/Http/Controllers/OnepageController.php b/packages/Webkul/Shop/src/Http/Controllers/OnepageController.php index a77f66752..12dad01aa 100755 --- a/packages/Webkul/Shop/src/Http/Controllers/OnepageController.php +++ b/packages/Webkul/Shop/src/Http/Controllers/OnepageController.php @@ -8,9 +8,6 @@ use Webkul\Shipping\Facades\Shipping; use Webkul\Payment\Facades\Payment; use Webkul\Checkout\Http\Requests\CustomerAddressForm; use Webkul\Sales\Repositories\OrderRepository; -use Webkul\Discount\Helpers\Cart\CouponAbleRule as Coupon; -use Webkul\Discount\Helpers\Cart\NonCouponAbleRule as NonCoupon; -use Webkul\Discount\Helpers\Cart\ValidatesDiscount; use Webkul\Customer\Repositories\CustomerRepository; /** @@ -22,13 +19,6 @@ use Webkul\Customer\Repositories\CustomerRepository; */ class OnepageController extends Controller { - /** - * OrderRepository object - * - * @var array - */ - protected $orderRepository; - /** * Contains route related configuration * @@ -37,21 +27,11 @@ class OnepageController extends Controller protected $_config; /** - * CouponAbleRule instance object + * OrderRepository object * + * @var array */ - protected $coupon; - - /** - * NoncouponAbleRule instance object - * - */ - protected $nonCoupon; - - /** - * ValidatesDiscount instance object - */ - protected $validatesDiscount; + protected $orderRepository; /** * customerRepository instance object @@ -61,25 +41,17 @@ class OnepageController extends Controller /** * Create a new controller instance. * - * @param \Webkul\Attribute\Repositories\OrderRepository $orderRepository + * @param \Webkul\Attribute\Repositories\OrderRepository $orderRepository + * @param \Webkul\Customer\Repositories\CustomerRepository $customerRepository * @return void */ public function __construct( OrderRepository $orderRepository, - Coupon $coupon, - NonCoupon $nonCoupon, - ValidatesDiscount $validatesDiscount, CustomerRepository $customerRepository ) { - $this->coupon = $coupon; - - $this->nonCoupon = $nonCoupon; - $this->orderRepository = $orderRepository; - $this->validatesDiscount = $validatesDiscount; - $this->customerRepository = $customerRepository; $this->_config = request('_config'); @@ -100,8 +72,6 @@ class OnepageController extends Controller if (! auth()->guard('customer')->check() && $cart->haveDownloadableItems()) return redirect()->route('customer.session.index'); - $this->nonCoupon->apply(); - Cart::collectTotals(); return view($this->_config['view'], compact('cart')); @@ -139,8 +109,6 @@ class OnepageController extends Controller } else { $cart = Cart::getCart(); - $this->nonCoupon->apply(); - Cart::collectTotals(); if ($cart->haveStockableItems()) { @@ -166,8 +134,6 @@ class OnepageController extends Controller if (Cart::hasError() || !$shippingMethod || !Cart::saveShippingMethod($shippingMethod)) return response()->json(['redirect_url' => route('shop.checkout.cart.index')], 403); - $this->nonCoupon->apply(); - Cart::collectTotals(); return response()->json(Payment::getSupportedPaymentMethods()); @@ -185,8 +151,6 @@ class OnepageController extends Controller if (Cart::hasError() || ! $payment || ! Cart::savePaymentMethod($payment)) return response()->json(['redirect_url' => route('shop.checkout.cart.index')], 403); - $this->nonCoupon->apply(); - Cart::collectTotals(); $cart = Cart::getCart(); @@ -253,23 +217,53 @@ class OnepageController extends Controller { $cart = Cart::getCart(); - $this->validatesDiscount->validate(); - - if ($cart->haveStockableItems() && ! $cart->shipping_address) { + if ($cart->haveStockableItems() && ! $cart->shipping_address) throw new \Exception(trans('Please check shipping address.')); - } - if (! $cart->billing_address) { + if (! $cart->billing_address) throw new \Exception(trans('Please check billing address.')); - } - if ($cart->haveStockableItems() && ! $cart->selected_shipping_rate) { + if ($cart->haveStockableItems() && ! $cart->selected_shipping_rate) throw new \Exception(trans('Please specify shipping method.')); - } - if (! $cart->payment) { + if (! $cart->payment) throw new \Exception(trans('Please specify payment method.')); - } + } + + /** + * Check Customer is exist or not + * + * @return Response + */ + public function checkExistCustomer() + { + $customer = $this->customerRepository->findOneWhere([ + 'email' => request()->email + ]); + + if (! is_null($customer)) + return 'true'; + + return 'false'; + } + + /** + * Login for checkout + * + * @return Response + */ + public function loginForCheckout() + { + $this->validate(request(), [ + 'email' => 'required|email' + ]); + + if (! auth()->guard('customer')->attempt(request(['email', 'password']))) + return response()->json(['error' => trans('shop::app.customer.login-form.invalid-creds')]); + + Cart::mergeCart(); + + return response()->json(['success' => 'Login successfully']); } /** @@ -333,40 +327,4 @@ class OnepageController extends Controller ], 422); } } - - /** - * Check Customer is exist or not - * - * @return Response - */ - public function checkExistCustomer() - { - //check customer is exist or not - $customer = $this->customerRepository->findOneWhere([ - 'email' => request()->email - ]); - - //if customer is exist - if (! is_null($customer)) { - return 'true'; - } - return 'false'; - } - - //login for checkout - public function loginForCheckout() - { - $this->validate(request(), [ - 'email' => 'required|email' - ]); - - if (! auth()->guard('customer')->attempt(request(['email', 'password']))) { - return response()->json(['error' => trans('shop::app.customer.login-form.invalid-creds')]); - } - - //Event passed to prepare cart after login - Cart::mergeCart(); - - return response()->json(['success' => 'Login successfully']); - } } \ No newline at end of file diff --git a/packages/Webkul/Shop/src/Resources/lang/en/app.php b/packages/Webkul/Shop/src/Resources/lang/en/app.php index 7095c10b6..c538d53b8 100755 --- a/packages/Webkul/Shop/src/Resources/lang/en/app.php +++ b/packages/Webkul/Shop/src/Resources/lang/en/app.php @@ -499,7 +499,8 @@ return [ 'free-desc' => 'This is a free shipping', 'flat-desc' => 'This is a flat rate', 'password' => 'Password', - 'login-exist-message' => 'You already have an account with us, Sign in or continue as guest.' + 'login-exist-message' => 'You already have an account with us, Sign in or continue as guest.', + 'enter-coupon-code' => 'Enter Coupon Code' ], 'total' => [ @@ -513,9 +514,13 @@ return [ 'disc-amount' => 'Amount discounted', 'new-grand-total' => 'New Grand Total', 'coupon' => 'Coupon', - 'coupon-applied' => 'Coupon Applied', + 'coupon-applied' => 'Applied Coupon', 'remove-coupon' => 'Remove Coupon', - 'cannot-apply-coupon' => 'Cannot Apply Coupon' + 'cannot-apply-coupon' => 'Cannot Apply Coupon', + 'invalid-coupon' => 'Coupon code is invalid.', + 'success-coupon' => 'Coupon code applied successfully.', + 'remove-coupon' => 'Coupon code removed successfully.', + 'coupon-apply-issue' => 'Coupon code can\'t be applied.' ], 'success' => [ diff --git a/packages/Webkul/Shop/src/Resources/views/checkout/cart/index.blade.php b/packages/Webkul/Shop/src/Resources/views/checkout/cart/index.blade.php index 269fc5ca4..72aa3c9bd 100755 --- a/packages/Webkul/Shop/src/Resources/views/checkout/cart/index.blade.php +++ b/packages/Webkul/Shop/src/Resources/views/checkout/cart/index.blade.php @@ -127,6 +127,8 @@ @include('shop::checkout.total.summary', ['cart' => $cart]) + + {!! view_render_event('bagisto.shop.checkout.cart.summary.after', ['cart' => $cart]) !!}
@@ -155,6 +157,7 @@ @endsection @push('scripts') + @include('shop::checkout.cart.coupon') diff --git a/packages/Webkul/Shop/src/Resources/views/checkout/total/summary.blade.php b/packages/Webkul/Shop/src/Resources/views/checkout/total/summary.blade.php index bbab890a3..70d5d87d6 100755 --- a/packages/Webkul/Shop/src/Resources/views/checkout/total/summary.blade.php +++ b/packages/Webkul/Shop/src/Resources/views/checkout/total/summary.blade.php @@ -24,15 +24,12 @@ @endif -
base_discount_amount && $cart->base_discount_amount > 0) style="display: block;" @else style="display: none;" @endif>
@@ -43,36 +40,4 @@ {{ core()->currency($cart->base_grand_total) }} - -
is('checkout/cart')) v-if="parseInt(discount)" @endif> - @if (! request()->is('checkout/cart')) - @if (! $cart->coupon_code) -
-
-
-
- -
- -
* @{{ error_message }}
- - -
-
-
- @else -
-
- - - -
-
- @endif - @endif -
\ No newline at end of file From 871836c9785a68a9e57c4e56ba3b660b03c8d397 Mon Sep 17 00:00:00 2001 From: peternuernberger Date: Mon, 23 Dec 2019 17:11:56 +0100 Subject: [PATCH 09/84] added automagically genereted file --- config/laravelwebconsole.php | 51 ++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 config/laravelwebconsole.php diff --git a/config/laravelwebconsole.php b/config/laravelwebconsole.php new file mode 100644 index 000000000..1e3be3bce --- /dev/null +++ b/config/laravelwebconsole.php @@ -0,0 +1,51 @@ + false, + + // Single-user credentials (REQUIRED) + 'user' => [ + 'name' => env('CONSOLE_USER_NAME', 'root'), + 'password' => env('CONSOLE_USER_PASSWORD', 'root'), + ], + + // Multi-user credentials (OPTIONAL) + // Example: 'user' => 'password', 'user1' => 'password1' + 'accounts' => [ + // 'user' => 'password', + ], + + // Hash incoming password + // By default it's sha256 + 'password_hash_algorithm' => '', + + // Home directory (multi-user mode supported) + // Example: 'home_dir' => '/tmp'; + // 'home_dir' => array('user1' => '/home/user1', 'user2' => '/home/user2'); + 'home_dir' => '', +]; From 405c979375f59773f2baf655188ff61195bb382f Mon Sep 17 00:00:00 2001 From: peternuernberger Date: Mon, 23 Dec 2019 17:13:12 +0100 Subject: [PATCH 10/84] added use statement --- .../Webkul/Category/src/Repositories/CategoryRepository.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/Webkul/Category/src/Repositories/CategoryRepository.php b/packages/Webkul/Category/src/Repositories/CategoryRepository.php index 004f5b15a..a351fe683 100755 --- a/packages/Webkul/Category/src/Repositories/CategoryRepository.php +++ b/packages/Webkul/Category/src/Repositories/CategoryRepository.php @@ -9,6 +9,7 @@ use Webkul\Core\Eloquent\Repository; use Webkul\Category\Models\Category; use Webkul\Category\Models\CategoryTranslation; use Illuminate\Database\Eloquent\ModelNotFoundException; +use Illuminate\Support\Facades\DB; /** * Category Reposotory @@ -126,7 +127,7 @@ class CategoryRepository extends Repository $exists = CategoryTranslation::where('category_id', '<>', $id) ->where('slug', $slug) ->limit(1) - ->select(\DB::raw(1)) + ->select(DB::raw(1)) ->exists(); return $exists ? false : true; From a2f2c650a4bf3865606e1c064cf80722cf93d380 Mon Sep 17 00:00:00 2001 From: peternuernberger Date: Mon, 23 Dec 2019 17:13:48 +0100 Subject: [PATCH 11/84] added method that returns path categories --- .../Webkul/Category/src/Models/Category.php | 46 ++++++++++++++++++- tests/unit/Category/CategoryCest.php | 13 ++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/packages/Webkul/Category/src/Models/Category.php b/packages/Webkul/Category/src/Models/Category.php index b40ff1a77..6d1e9239b 100755 --- a/packages/Webkul/Category/src/Models/Category.php +++ b/packages/Webkul/Category/src/Models/Category.php @@ -5,6 +5,7 @@ namespace Webkul\Category\Models; use Webkul\Core\Eloquent\TranslatableModel; use Kalnoy\Nestedset\NodeTrait; use Illuminate\Support\Facades\Storage; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Webkul\Category\Contracts\Category as CategoryContract; use Webkul\Attribute\Models\AttributeProxy; @@ -19,7 +20,7 @@ class Category extends TranslatableModel implements CategoryContract { use NodeTrait; - public $translatedAttributes = ['name', 'description', 'slug', 'meta_title', 'meta_description', 'meta_keywords']; + public $translatedAttributes = ['name', 'description', 'slug', 'url_path', 'meta_title', 'meta_description', 'meta_keywords']; protected $fillable = ['position', 'status', 'display_mode', 'parent_id']; @@ -51,4 +52,47 @@ class Category extends TranslatableModel implements CategoryContract { return $this->belongsToMany(AttributeProxy::modelClass(), 'category_filterable_attributes')->with('options'); } + + /** + * Returns all categories within the category's path + * + * @return Category[] + */ + public function getPathCategories(): array + { + $category = $this->findInTree(); + + $categories = [$category]; + + while (isset($category->parent)) { + $category = $category->parent; + $categories[] = $category; + } + + array_pop($categories); + return array_reverse($categories); + } + + /** + * Finds and returns the category within a nested category tree + * will search in root category by default + * + * @param Category[] $categoryTree + * @return Category + */ + private function findInTree($categoryTree = null): Category + { + if (!$categoryTree) { + $rootCategoryId = core()->getCurrentChannel()->root_category_id; + $categoryTree = app('Webkul\Category\Repositories\CategoryRepository')->getVisibleCategoryTree($rootCategoryId); + } + + foreach ($categoryTree as $category) { + if ($category->id === $this->id) { + return $category; + } + return $this->findInTree($category->children); + } + throw new NotFoundHttpException('category not found in tree'); + } } \ No newline at end of file diff --git a/tests/unit/Category/CategoryCest.php b/tests/unit/Category/CategoryCest.php index c3c2779b0..abd8ad7d0 100644 --- a/tests/unit/Category/CategoryCest.php +++ b/tests/unit/Category/CategoryCest.php @@ -138,5 +138,18 @@ class CategoryCest 'locale' => $this->localeEn->code, 'url_path' => $expectedUrlPath, ]); + + // test if the url_path attribute is available in the model + $this->grandChildCategory->refresh(); + $I->assertEquals($expectedUrlPath, $this->grandChildCategory->url_path); + } + + public function testGetPathCategories(UnitTester $I) + { + $pathCategories = $this->grandChildCategory->getPathCategories(); + $I->assertCount(3, $pathCategories); + $I->assertEquals($pathCategories[0]->id, $this->category->id); + $I->assertEquals($pathCategories[1]->id, $this->childCategory->id); + $I->assertEquals($pathCategories[2]->id, $this->grandChildCategory->id); } } From 7aba45486f2ce974e42865715c1ff77895f3927b Mon Sep 17 00:00:00 2001 From: jitendra Date: Wed, 25 Dec 2019 19:57:05 +0530 Subject: [PATCH 12/84] Indexes created for all product types --- CHANGELOG for v0.1.x.md | 64 ++++++++++ CHANGELOG for v0.2.x.md | 17 +++ .../promotions/cart-rules/create.blade.php | 8 +- .../promotions/cart-rules/edit.blade.php | 10 +- .../Webkul/CartRule/src/Helpers/CartRule.php | 27 ++++ .../src/Helpers/CatalogRuleIndex.php | 13 +- .../src/Helpers/CatalogRuleProduct.php | 25 +++- .../Webkul/Product/src/Type/AbstractType.php | 39 +++++- packages/Webkul/Product/src/Type/Bundle.php | 27 ++++ .../Webkul/Product/src/Type/Configurable.php | 10 ++ packages/Webkul/Product/src/Type/Grouped.php | 10 ++ .../Webkul/Rule/src/Helpers/Validator.php | 118 +++++++++++++----- .../Webkul/Shop/src/Resources/lang/en/app.php | 1 - 13 files changed, 314 insertions(+), 55 deletions(-) create mode 100644 CHANGELOG for v0.2.x.md diff --git a/CHANGELOG for v0.1.x.md b/CHANGELOG for v0.1.x.md index 1359bdd27..be4c3b3c1 100755 --- a/CHANGELOG for v0.1.x.md +++ b/CHANGELOG for v0.1.x.md @@ -2,6 +2,70 @@ #### This changelog consists the bug & security fixes and new features being included in the releases listed below. +## **v0.1.9 (20th of December, 2019)** - *Release* + +* #1875 [fixed] - Discount gets applied on cart if condition is "Visible Individually" is set to yes and product added in cart is not visible individually. + +* #1868 [fixed] - Getting exception on checkout if action Buy X Get Y free is selected in cart rule. + +* #1838 [fixed] - Cart rule not working for condition sku(children only) and sku(parent only). + +* #1835 [fixed] - Getting exception if condition value remains blank. + +* #1831 [fixed] - Negative sign is not required in discount amount. + +* #1830 [fixed] - If Coupon type is selected as "No Coupon" then coupon code should not generate for that particular cart rule. + +* #1904 [fixed] - Existing tax should display as list on creating catalog rule if in condition "Tax Category" is selected. + +* #1903 [fixed] - UI issue in condition field + +* #1895 [fixed] - Translation issue Action Type field while creating catalog rule. + +* #1883 [fixed] - Free shipping not applied on cart, if from action "Free Shipping" is selected and discount amount is given as zero. + +* #1882 [fixed] - If from Action "Apply on shipping " is selected as yes then the discounted amount is applying on both product and shipping charge. + +* #1861 [fixed] - Getting exception on checkout if applying invalid coupon code and proceed for checkout. + +* #1857 [fixed] - Getting exception when creating cart rule with condition URL KEY(children only). + +* #1856 [fixed] - Getting exception on creating cart rule with condition Name(children only). + +* #1847 [fixed] - If cart rule condition does not match the cart then on applying coupon it should display message "Coupon cannot be applied". + +* #1839 [fixed] - Getting exception on filtering cart rule through id. + +* #1836 [fixed] - Back button on Edit cart rule page doesn't work. + +* #1834 [fixed] - On editing any cart rule, its priority updates to 1. + +* #1833 [fixed] - Discount not applied if "Payment Method", "Shipping Method", "Shipping State" or "Shipping Country" is selected in condition. + +* #1832 [fixed] - Able to use coupon irrespective of the number given in "Uses per coupon" field. + +* #1828 [fixed] - Updated changes are not saved on editing cart rule. + +* #1825 [fixed] - Not able to generate coupon code while creating cart rule. + +* #1823 [fixed] - Getting exception after clicking on developement. + +* #1929 [fixed] - Actual product amount and discounted amount both should display on product page for configurable product + +* #1928 [fixed] - Catalog rule should not apply if any of the condition doesn't match, if condition type"All Condition are true" + +* #1931 [fixed] - Catalog rule not applying if in condition type"Any Condition is true" is selected, and some of the condition doesn't match the product. + +* #1935 [fixed] - Categories are not displaying if in condition Categories(children only) or Categories(Parent Only) is selected. + +* #1938 [fixed] - multiple cart rules are getting applied by using only single coupon. + +* #1939 [fixed] - Invalid coupon gets applied, if clicking on apply coupon multiple time, although there is no discount amount but its displaying message that coupon code applied successfully. + +* #1942 [fixed] - When editing the cart rule, selected category is not checked. + + + ## **v0.1.8 (4th of October, 2019)** - *Release* * [feature] - Refund is added for orders. diff --git a/CHANGELOG for v0.2.x.md b/CHANGELOG for v0.2.x.md new file mode 100644 index 000000000..bf693debb --- /dev/null +++ b/CHANGELOG for v0.2.x.md @@ -0,0 +1,17 @@ +# CHANGELOG for v0.2.x + +#### This changelog consists the bug & security fixes and new features being included in the releases listed below. + +## **v0.2.0 (23th of December, 2019)** - *Release* + +* #1955 [fixed] - Message need to be changed on mouse hover on cross symbol next to applied coupon. + +* #1959 [fixed] - if admin has set the same condition twice, then catalog rule is not getting apply + +* #1958 [fixed] - getting exception on front end, if action type is Buy x get y free in non couponable cart rule. + +* #1957 [fixed] - if action type is Fixed Amount to Whole Cart, then apply to shipping option should get hide. + +* #1954 [fixed] - If any different tax category has been assigned to variants in configurable product, then while using tax category condition in cart rule, rule is not working properly. + +* #1950 [fixed] - multiple catalog rule should not get get applied, if 1st one has been created as End Other Rules = yes \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/create.blade.php b/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/create.blade.php index c687601ac..6ced9889a 100644 --- a/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/create.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/create.blade.php @@ -199,7 +199,7 @@
- @@ -236,7 +236,7 @@
- @@ -380,7 +380,9 @@ condition_type: 1, - conditions: [] + conditions: [], + + action_type: "{{ old('action_type') ?: 'by_percent' }}" } }, diff --git a/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/edit.blade.php b/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/edit.blade.php index 4af87ddf2..cdc051a59 100644 --- a/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/edit.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/promotions/cart-rules/edit.blade.php @@ -164,7 +164,7 @@
- +
@@ -205,7 +205,7 @@ action_type ?> - @@ -246,7 +246,7 @@ apply_to_shipping ?> - @@ -472,7 +472,9 @@ condition_type: {{ old('condition_type') ?: $cartRule->condition_type }}, - conditions: @json($cartRule->conditions ?: []) + conditions: @json($cartRule->conditions ?: []), + + action_type: "{{ old('action_type') ?: $cartRule->action_type }}" } }, diff --git a/packages/Webkul/CartRule/src/Helpers/CartRule.php b/packages/Webkul/CartRule/src/Helpers/CartRule.php index 942fe77ea..8ad0c4dac 100644 --- a/packages/Webkul/CartRule/src/Helpers/CartRule.php +++ b/packages/Webkul/CartRule/src/Helpers/CartRule.php @@ -106,6 +106,9 @@ class CartRule foreach ($cart->items()->get() as $item) { $this->process($item); + + if ($item->children()->count() && $item->product->getTypeInstance()->isChildrenCalculated()) + $this->devideDiscount($item); } $this->processShippingDiscount($cart); @@ -231,6 +234,8 @@ class CartRule $quantity = $rule->discount_quantity ? min($item->quantity, $rule->discount_quantity) : $item->quantity; + $discountAmount = $baseDiscountAmount = 0; + switch ($rule->action_type) { case 'by_percent': $rulePercent = min(100, $rule->discount_amount); @@ -493,4 +498,26 @@ class CartRule if (! $coupon || ! in_array($coupon->cart_rule_id, explode(',', $cart->applied_cart_rule_ids))) Cart::removeCouponCode(); } + + /** + * Devide discount amount to children + * + * @param CartItem $item + * @return void + */ + protected function devideDiscount($item) + { + foreach ($item->children as $child) { + $ratio = $item->base_total != 0 ? $child->base_total / $item->base_total : 0; + + foreach (['discount_amount', 'base_discount_amount'] as $column) { + if (! $item->{$column}) + continue; + + $child->{$column} = round(($item->{$column} * $ratio), 4); + + $child->save(); + } + } + } } \ No newline at end of file diff --git a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleIndex.php b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleIndex.php index 3d8336caf..fd9b6cc5f 100644 --- a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleIndex.php +++ b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleIndex.php @@ -78,13 +78,12 @@ class CatalogRuleIndex public function reindexProduct($product) { try { - $productIds = []; - - if ($product->type == 'configurable') { - $productIds = $product->variants()->pluck('id')->toArray(); - } else { - $productIds[] = $product->id; - } + if (! $product->getTypeInstance()->priceRuleCanBeApplied()) + return; + + $productIds = $product->getTypeInstance()->isComposite() + ? $product->getTypeInstance()->getChildrenIds() + : [$product->id]; $this->cleanIndexes($productIds); diff --git a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php index 5be4b124f..38eb6e439 100644 --- a/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php +++ b/packages/Webkul/CatalogRule/src/Helpers/CatalogRuleProduct.php @@ -133,9 +133,17 @@ class CatalogRuleProduct if (! $rule->conditions) return $qb; + $appliedAttributes = []; + foreach ($rule->conditions as $condition) { - if (! $condition['attribute'] || ! isset($condition['value']) || is_null($condition['value']) || $condition['value'] == '') + if (! $condition['attribute'] + || ! isset($condition['value']) + || is_null($condition['value']) + || $condition['value'] == '' + || in_array($condition['attribute'], $appliedAttributes)) continue; + + $appliedAttributes[] = $condition['attribute']; $chunks = explode('|', $condition['attribute']); @@ -148,9 +156,12 @@ class CatalogRuleProduct $validatedProductIds = []; foreach ($qb->get() as $product) { + if (! $product->getTypeInstance()->priceRuleCanBeApplied()) + continue; + if ($this->validator->validate($rule, $product)) { - if ($product->type == 'configurable') { - $validatedProductIds = array_merge($validatedProductIds, $product->variants()->pluck('id')->toArray()); + if ($product->getTypeInstance()->isComposite()) { + $validatedProductIds = array_merge($validatedProductIds, $product->getTypeInstance()->getChildrenIds()); } else { $validatedProductIds[] = $product->id; } @@ -208,8 +219,12 @@ class CatalogRuleProduct ->orderBy('catalog_rule_id', 'asc'); if ($product) { - if ($product->type == 'configurable') { - $qb->whereIn('catalog_rule_products.product_id', $product->variants()->pluck('id')->toArray()); + + if (! $product->getTypeInstance()->priceRuleCanBeApplied()) + return $qb; + + if ($product->getTypeInstance()->isComposite()) { + $qb->whereIn('catalog_rule_products.product_id', $product->getTypeInstance()->getChildrenIds()); } else { $qb->where('catalog_rule_products.product_id', $product->id); } diff --git a/packages/Webkul/Product/src/Type/AbstractType.php b/packages/Webkul/Product/src/Type/AbstractType.php index 39568653d..a761d5b2a 100644 --- a/packages/Webkul/Product/src/Type/AbstractType.php +++ b/packages/Webkul/Product/src/Type/AbstractType.php @@ -112,6 +112,13 @@ abstract class AbstractType */ protected $hasVariants = false; + /** + * Product children price can be calculated or not + * + * @var boolean + */ + protected $isChildrenCalculated = false; + /** * Create a new product type instance. * @@ -250,6 +257,26 @@ abstract class AbstractType return $this; } + /** + * Returns children ids + * + * @return array + */ + public function getChildrenIds() + { + return []; + } + + /** + * Check if catalog rule can be applied + * + * @return bool + */ + public function priceRuleCanBeApplied() + { + return true; + } + /** * Return true if this product type is saleable * @@ -289,11 +316,21 @@ abstract class AbstractType * * @return bool */ - public function hasVariants(): bool + public function hasVariants() { return $this->hasVariants; } + /** + * Product children price can be calculated or not + * + * @return bool + */ + public function isChildrenCalculated() + { + return $this->isChildrenCalculated; + } + /** * @param integer $qty * @return bool diff --git a/packages/Webkul/Product/src/Type/Bundle.php b/packages/Webkul/Product/src/Type/Bundle.php index dad347cec..52a1345da 100644 --- a/packages/Webkul/Product/src/Type/Bundle.php +++ b/packages/Webkul/Product/src/Type/Bundle.php @@ -68,6 +68,13 @@ class Bundle extends AbstractType */ protected $isComposite = true; + /** + * Product children price can be calculated or not + * + * @var boolean + */ + protected $isChildrenCalculated = true; + /** * Create a new product type instance. * @@ -126,6 +133,26 @@ class Bundle extends AbstractType return $product; } + /** + * Returns children ids + * + * @return array + */ + public function getChildrenIds() + { + return array_unique($this->product->bundle_options()->pluck('product_id')->toArray()); + } + + /** + * Check if catalog rule can be applied + * + * @return bool + */ + public function priceRuleCanBeApplied() + { + return false; + } + /** * Get product minimal price * diff --git a/packages/Webkul/Product/src/Type/Configurable.php b/packages/Webkul/Product/src/Type/Configurable.php index e0f1c3eea..db2890f1d 100644 --- a/packages/Webkul/Product/src/Type/Configurable.php +++ b/packages/Webkul/Product/src/Type/Configurable.php @@ -286,6 +286,16 @@ class Configurable extends AbstractType return false; } + /** + * Returns children ids + * + * @return array + */ + public function getChildrenIds() + { + return $this->product->variants()->pluck('id')->toArray(); + } + /** * @param CartItem $cartItem * @return bool diff --git a/packages/Webkul/Product/src/Type/Grouped.php b/packages/Webkul/Product/src/Type/Grouped.php index 2af33ccb6..ec2fc4c39 100644 --- a/packages/Webkul/Product/src/Type/Grouped.php +++ b/packages/Webkul/Product/src/Type/Grouped.php @@ -104,6 +104,16 @@ class Grouped extends AbstractType return $product; } + /** + * Returns children ids + * + * @return array + */ + public function getChildrenIds() + { + return array_unique($this->product->grouped_products()->pluck('product_id')->toArray()); + } + /** * Get product minimal price * diff --git a/packages/Webkul/Rule/src/Helpers/Validator.php b/packages/Webkul/Rule/src/Helpers/Validator.php index 06a623f43..ac510f314 100644 --- a/packages/Webkul/Rule/src/Helpers/Validator.php +++ b/packages/Webkul/Rule/src/Helpers/Validator.php @@ -29,16 +29,14 @@ class Validator $totalConditionCount++; - $attributeValue = $this->getAttributeValue($condition, $entity); - if ($rule->condition_type == 1) { - if (! $this->validateAttribute($condition['operator'], $attributeValue, $condition['value'])) { + if (! $this->validateObject($condition, $entity)) { return false; } else { $validConditionCount++; } } else { - if ($this->validateAttribute($condition['operator'], $attributeValue, $condition['value'])) + if ($this->validateObject($condition, $entity)) return true; } } @@ -49,8 +47,8 @@ class Validator /** * Return value for the attribute * - * @param array $condition - * @param Cart|CartItem|Product $entity + * @param array $condition + * @param CartItem|Product $entity * @return boolean */ public function getAttributeValue($condition, $entity) @@ -61,8 +59,6 @@ class Validator $attributeCode = $attributeNameChunks[count($attributeNameChunks) - 1]; - $attributeScope = count($attributeNameChunks) == 2 ? $attributeNameChunks[0] : null; - switch (current($chunks)) { case 'cart': $cart = $entity instanceof \Webkul\Checkout\Contracts\Cart ? $entity : $entity->cart; @@ -93,18 +89,15 @@ class Validator case 'product': if ($attributeCode == 'category_ids') { - $value = $attributeScope == 'children' - ? ($entity->child ? $entity->child->product->categories()->pluck('id')->toArray() : []) - : ($entity->product + $value = $entity->product ? $entity->product->categories()->pluck('id')->toArray() - : $entity->categories()->pluck('id')->toArray() - ); + : $entity->categories()->pluck('id')->toArray(); return $value; } else { - $value = $attributeScope == 'children' - ? ($entity->child ? $entity->child->product->{$attributeCode} : null) - : ($entity->product ? $entity->product->{$attributeCode} : $entity->{$attributeCode}); + $value = $entity->product + ? $entity->product->{$attributeCode} + : $entity->{$attributeCode}; if (! in_array($condition['attribute_type'], ['multiselect', 'checkbox'])) return $value; @@ -114,28 +107,85 @@ class Validator } } + /** + * Validate object + * + * @param array $condition + * @param CartItem $entity + * @return bool + */ + private function validateObject($condition, $entity) + { + $validated = false; + + foreach ($this->getAllItems($this->getAttributeScope($condition), $entity) as $item) { + $attributeValue = $this->getAttributeValue($condition, $item); + + if ($validated = $this->validateAttribute($condition, $attributeValue)) + break; + } + + return $validated; + } + + /** + * Return all cart items + * + * @param string $attributeScope + * @param Cart|CartItem|Product $item + * @return array + */ + private function getAllItems($attributeScope, $item) + { + if ($attributeScope === 'parent') { + return [$item]; + } elseif ($attributeScope === 'children') { + return $item->children ?: [$item]; + } else { + $items = $item->children ?: []; + + $items[] = $item; + } + + return $items; + } + + /** + * Validate object + * + * @param array $condition + * @return string + */ + private function getAttributeScope($condition) + { + $chunks = explode('|', $condition['attribute']); + + $attributeNameChunks = explode('::', $chunks[1]); + + return count($attributeNameChunks) == 2 ? $attributeNameChunks[0] : null; + } + /** * Validate attribute value for condition * - * @param string $operator - * @param mixed $attributeValue - * @param mixed $conditionValue + * @param array $condition + * @param mixed $attributeValue * @return boolean */ - public function validateAttribute($operator, $attributeValue, $conditionValue) + public function validateAttribute($condition, $attributeValue) { - switch ($operator) { + switch ($condition['operator']) { case '==': case '!=': - if (is_array($conditionValue)) { + if (is_array($condition['value'])) { if (! is_array($attributeValue)) return false; - $result = ! empty(array_intersect($conditionValue, $attributeValue)); + $result = ! empty(array_intersect($condition['value'], $attributeValue)); } else { if (is_array($attributeValue)) { - $result = count($attributeValue) == 1 && array_shift($attributeValue) == $conditionValue; + $result = count($attributeValue) == 1 && array_shift($attributeValue) == $condition['value']; } else { - $result = $attributeValue == $conditionValue; + $result = $attributeValue == $condition['value']; } } @@ -145,7 +195,7 @@ class Validator if (! is_scalar($attributeValue)) return false; - $result = $attributeValue <= $conditionValue; + $result = $attributeValue <= $condition['value']; break; @@ -153,36 +203,36 @@ class Validator if (! is_scalar($attributeValue)) return false; - $result = $attributeValue >= $conditionValue; + $result = $attributeValue >= $condition['value']; break; case '{}': case '!{}': - if (is_scalar($attributeValue) && is_array($conditionValue)) { - foreach ($conditionValue as $item) { + if (is_scalar($attributeValue) && is_array($condition['value'])) { + foreach ($condition['value'] as $item) { if (stripos($attributeValue, $item) !== false) { $result = true; break; } } - } else if (is_array($conditionValue)) { + } else if (is_array($condition['value'])) { if (! is_array($attributeValue)) return false; - $result = ! empty(array_intersect($conditionValue, $attributeValue)); + $result = ! empty(array_intersect($condition['value'], $attributeValue)); } else { if (is_array($attributeValue)) { - $result = in_array($conditionValue, $attributeValue); + $result = in_array($condition['value'], $attributeValue); } else { - $result = (strpos($attributeValue, $conditionValue) !== false) ? true : false; + $result = (strpos($attributeValue, $condition['value']) !== false) ? true : false; } } break; } - if (in_array($operator, ['!=', '>', '<', '!{}'])) + if (in_array($condition['operator'], ['!=', '>', '<', '!{}'])) $result = ! $result; return $result; diff --git a/packages/Webkul/Shop/src/Resources/lang/en/app.php b/packages/Webkul/Shop/src/Resources/lang/en/app.php index c538d53b8..27547f8c4 100755 --- a/packages/Webkul/Shop/src/Resources/lang/en/app.php +++ b/packages/Webkul/Shop/src/Resources/lang/en/app.php @@ -519,7 +519,6 @@ return [ 'cannot-apply-coupon' => 'Cannot Apply Coupon', 'invalid-coupon' => 'Coupon code is invalid.', 'success-coupon' => 'Coupon code applied successfully.', - 'remove-coupon' => 'Coupon code removed successfully.', 'coupon-apply-issue' => 'Coupon code can\'t be applied.' ], From a63c2f9fd8d6d73394edcffbcdc75a5e5aa18da1 Mon Sep 17 00:00:00 2001 From: rabol Date: Sat, 28 Dec 2019 10:38:54 +0100 Subject: [PATCH 13/84] Make it possible to specify timezone in .env --- .env.example | 2 +- config/app.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index bb471ec98..f8f0aa0bb 100644 --- a/.env.example +++ b/.env.example @@ -4,7 +4,7 @@ APP_VERSION=0.1.8 APP_KEY= APP_DEBUG=true APP_URL=http://localhost - +APP_TIMEZONE='Asia/Kolkata' LOG_CHANNEL=stack DB_CONNECTION=mysql diff --git a/config/app.php b/config/app.php index 8e675f952..c8dcb8247 100755 --- a/config/app.php +++ b/config/app.php @@ -65,7 +65,7 @@ return [ | */ - 'timezone' => 'Asia/Kolkata', + 'timezone' => env('APP_TIMEZONE','Asia/Kolkata'), /* |-------------------------------------------------------------------------- From 0abc5ec43e2c25ee7b22e36b959c28a52dd00bed Mon Sep 17 00:00:00 2001 From: rabol Date: Sat, 28 Dec 2019 11:22:41 +0100 Subject: [PATCH 14/84] Make it possible to specify currency in .env --- .env.example | 1 + config/app.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index f8f0aa0bb..4ece248c8 100644 --- a/.env.example +++ b/.env.example @@ -6,6 +6,7 @@ APP_DEBUG=true APP_URL=http://localhost APP_TIMEZONE='Asia/Kolkata' LOG_CHANNEL=stack +APP_CURRENCY=USD DB_CONNECTION=mysql DB_HOST=127.0.0.1 diff --git a/config/app.php b/config/app.php index c8dcb8247..653f9ab46 100755 --- a/config/app.php +++ b/config/app.php @@ -102,7 +102,7 @@ return [ | */ - 'currency' => 'USD', + 'currency' => env('APP_CURRENCY','USD'), /* |-------------------------------------------------------------------------- From 029971e9cf36a37cd70c7c4f644d679642bc97d1 Mon Sep 17 00:00:00 2001 From: rabol Date: Sat, 28 Dec 2019 15:36:40 +0100 Subject: [PATCH 15/84] Fix bug that prevent user from signing up for newsletter --- packages/Webkul/Shop/src/Mail/SubscriptionEmail.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/Webkul/Shop/src/Mail/SubscriptionEmail.php b/packages/Webkul/Shop/src/Mail/SubscriptionEmail.php index 271cb6f85..fdb3f9442 100755 --- a/packages/Webkul/Shop/src/Mail/SubscriptionEmail.php +++ b/packages/Webkul/Shop/src/Mail/SubscriptionEmail.php @@ -30,9 +30,10 @@ class SubscriptionEmail extends Mailable */ public function build() { - return $this->to($this->subscriptionData['email']) - ->from(config('mail.from')) + return $this->to($this->subscriptionData['email']) + ->from(config('mail.from.address'),config('mail.from.name')) ->subject(trans('shop::app.mail.customer.subscription.subject')) ->view('shop::emails.customer.subscription-email')->with('data', ['content' => 'You Are Subscribed', 'token' => $this->subscriptionData['token']]); + } } \ No newline at end of file From 74348ac5bef299b089cdb64fee084ef392c0cbc3 Mon Sep 17 00:00:00 2001 From: Annika Wolff Date: Mon, 30 Dec 2019 11:03:50 +0100 Subject: [PATCH 16/84] resolve warning exception occurring on apply of catalog rule --- packages/Webkul/Product/src/Helpers/ProductType.php | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/Webkul/Product/src/Helpers/ProductType.php b/packages/Webkul/Product/src/Helpers/ProductType.php index 103b1ed58..68c523b50 100644 --- a/packages/Webkul/Product/src/Helpers/ProductType.php +++ b/packages/Webkul/Product/src/Helpers/ProductType.php @@ -28,6 +28,7 @@ class ProductType extends AbstractProduct */ public static function getAllTypesHavingVariants(): array { + $havingVariants = []; foreach (config('product_types') as $type) { if (self::hasVariants($type['key'])) { array_push($havingVariants, $type['key']); From 04fee503d8e2e3971f82e012e26e66776a48fd19 Mon Sep 17 00:00:00 2001 From: peternuernberger Date: Mon, 30 Dec 2019 12:56:15 +0100 Subject: [PATCH 17/84] added space after ! --- packages/Webkul/Category/src/Models/Category.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/Webkul/Category/src/Models/Category.php b/packages/Webkul/Category/src/Models/Category.php index 6d1e9239b..e1dcf86eb 100755 --- a/packages/Webkul/Category/src/Models/Category.php +++ b/packages/Webkul/Category/src/Models/Category.php @@ -82,7 +82,7 @@ class Category extends TranslatableModel implements CategoryContract */ private function findInTree($categoryTree = null): Category { - if (!$categoryTree) { + if (! $categoryTree) { $rootCategoryId = core()->getCurrentChannel()->root_category_id; $categoryTree = app('Webkul\Category\Repositories\CategoryRepository')->getVisibleCategoryTree($rootCategoryId); } From 44621624bc24dd4a6cfdb9b0fae03cc04f56165b Mon Sep 17 00:00:00 2001 From: peternuernberger Date: Mon, 30 Dec 2019 13:00:56 +0100 Subject: [PATCH 18/84] deleted laravelwebconsole for it is not used any more --- config/laravelwebconsole.php | 51 ------------------------------------ 1 file changed, 51 deletions(-) delete mode 100644 config/laravelwebconsole.php diff --git a/config/laravelwebconsole.php b/config/laravelwebconsole.php deleted file mode 100644 index 1e3be3bce..000000000 --- a/config/laravelwebconsole.php +++ /dev/null @@ -1,51 +0,0 @@ - false, - - // Single-user credentials (REQUIRED) - 'user' => [ - 'name' => env('CONSOLE_USER_NAME', 'root'), - 'password' => env('CONSOLE_USER_PASSWORD', 'root'), - ], - - // Multi-user credentials (OPTIONAL) - // Example: 'user' => 'password', 'user1' => 'password1' - 'accounts' => [ - // 'user' => 'password', - ], - - // Hash incoming password - // By default it's sha256 - 'password_hash_algorithm' => '', - - // Home directory (multi-user mode supported) - // Example: 'home_dir' => '/tmp'; - // 'home_dir' => array('user1' => '/home/user1', 'user2' => '/home/user2'); - 'home_dir' => '', -]; From e8f3b1009c25ad0240ab478b16bc1eb86eb1daf1 Mon Sep 17 00:00:00 2001 From: peternuernberger Date: Mon, 30 Dec 2019 13:17:34 +0100 Subject: [PATCH 19/84] added some test context --- tests/unit/Category/CategoryCest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/unit/Category/CategoryCest.php b/tests/unit/Category/CategoryCest.php index abd8ad7d0..7ac54fcbd 100644 --- a/tests/unit/Category/CategoryCest.php +++ b/tests/unit/Category/CategoryCest.php @@ -48,7 +48,6 @@ class CategoryCest $this->category = $I->have(Category::class, $this->categoryAttributes); $I->assertNotNull($this->category); - //return true; $I->seeRecord(CategoryTranslation::class, [ 'category_id' => $this->category->id, @@ -104,7 +103,6 @@ class CategoryCest public function testChildUrlPathIsUpdatedOnParentUpdate(UnitTester $I) { - //return true; $newCategorySlug = $this->faker->slug; $this->categoryAttributes[$this->localeEn->code]['slug'] = $newCategorySlug; @@ -146,7 +144,10 @@ class CategoryCest public function testGetPathCategories(UnitTester $I) { + $I->wantTo('test getPathCategories is returning the correct categories in the correct order'); + $I->amGoingTo('get all categories wihin the path of the grand child category'); $pathCategories = $this->grandChildCategory->getPathCategories(); + $I->assertCount(3, $pathCategories); $I->assertEquals($pathCategories[0]->id, $this->category->id); $I->assertEquals($pathCategories[1]->id, $this->childCategory->id); From c3514922120869873317fdebfb764d8e437aced9 Mon Sep 17 00:00:00 2001 From: peternuernberger Date: Mon, 30 Dec 2019 13:27:41 +0100 Subject: [PATCH 20/84] added amGoingTo to test --- tests/unit/Category/CategoryCest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/Category/CategoryCest.php b/tests/unit/Category/CategoryCest.php index 7ac54fcbd..ca611885b 100644 --- a/tests/unit/Category/CategoryCest.php +++ b/tests/unit/Category/CategoryCest.php @@ -137,7 +137,7 @@ class CategoryCest 'url_path' => $expectedUrlPath, ]); - // test if the url_path attribute is available in the model + $I->amGoingTo('test if the url_path attribute is available in the model'); $this->grandChildCategory->refresh(); $I->assertEquals($expectedUrlPath, $this->grandChildCategory->url_path); } From 97dcf89740a9044aefb5e34be2ad1bf1ed7e6c92 Mon Sep 17 00:00:00 2001 From: peternuernberger Date: Mon, 30 Dec 2019 13:28:09 +0100 Subject: [PATCH 21/84] refactored model reference --- packages/Webkul/Category/src/Models/Category.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/Webkul/Category/src/Models/Category.php b/packages/Webkul/Category/src/Models/Category.php index e1dcf86eb..3c11b04f1 100755 --- a/packages/Webkul/Category/src/Models/Category.php +++ b/packages/Webkul/Category/src/Models/Category.php @@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Storage; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Webkul\Category\Contracts\Category as CategoryContract; use Webkul\Attribute\Models\AttributeProxy; +use Webkul\Category\Repositories\CategoryRepository; /** * Class Category @@ -84,7 +85,7 @@ class Category extends TranslatableModel implements CategoryContract { if (! $categoryTree) { $rootCategoryId = core()->getCurrentChannel()->root_category_id; - $categoryTree = app('Webkul\Category\Repositories\CategoryRepository')->getVisibleCategoryTree($rootCategoryId); + $categoryTree = app(CategoryRepository::class)->getVisibleCategoryTree($rootCategoryId); } foreach ($categoryTree as $category) { From dc89cd651194ffb5f9d84a3c71dbf1714cbd5186 Mon Sep 17 00:00:00 2001 From: MonaHartdegen Date: Thu, 2 Jan 2020 13:14:53 +0100 Subject: [PATCH 22/84] fixed product links in two views (replaced hard coded link with route) --- .../Shop/src/Resources/views/checkout/cart/index.blade.php | 4 ++-- .../Resources/views/customers/account/reviews/index.blade.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/Webkul/Shop/src/Resources/views/checkout/cart/index.blade.php b/packages/Webkul/Shop/src/Resources/views/checkout/cart/index.blade.php index 269fc5ca4..6e34cc901 100755 --- a/packages/Webkul/Shop/src/Resources/views/checkout/cart/index.blade.php +++ b/packages/Webkul/Shop/src/Resources/views/checkout/cart/index.blade.php @@ -25,7 +25,7 @@
- +
@@ -33,7 +33,7 @@ {!! view_render_event('bagisto.shop.checkout.cart.item.name.before', ['item' => $item]) !!} diff --git a/packages/Webkul/Shop/src/Resources/views/customers/account/reviews/index.blade.php b/packages/Webkul/Shop/src/Resources/views/customers/account/reviews/index.blade.php index 0e24927d6..a456ae557 100755 --- a/packages/Webkul/Shop/src/Resources/views/customers/account/reviews/index.blade.php +++ b/packages/Webkul/Shop/src/Resources/views/customers/account/reviews/index.blade.php @@ -36,13 +36,13 @@
getProductBaseImage($review->product); ?> - +
From 9fda68d5970cbff78be4d2372f3160b099a1b204 Mon Sep 17 00:00:00 2001 From: Annika Wolff <57894757+AnnikaWolff@users.noreply.github.com> Date: Thu, 2 Jan 2020 15:46:16 +0100 Subject: [PATCH 23/84] merge bagisto master 7b1378f (#10) * added checkbox to add empty (default) option for attributes; only show attribute labels (not admin names) on product detail view * added attribute (-related) factories; added functional test * improved usage of var/let/const; fixed error on removing row * Allow datagrid action to have target="_blank" * The {length} didn't get properly formatted I don't know if this is completely correct since I don't know this language, but for my language it said ``` Veld "Wachtwoord" moet ten minste {length} tekens bevatten ``` So the length didn't get replaced. I think the locales.js needs to change * Multiple type file error * add two events to profile index blade view * throw exception when session user is not available on product review page * check guest customer configuration * Issue #1879 and #1880 * Issue 1802. * Issue #1792 * increase maintainability by replacing hard coded class names by ::class in ProductRepository * Issue #1806 * fix: broken url sometimes when finishing installation,go to wrong application url Co-authored-by: hb-monah <58027155+hb-monah@users.noreply.github.com> Co-authored-by: Hans Schouten Co-authored-by: KevinLaveto <31034266+KevinLaveto@users.noreply.github.com> Co-authored-by: Jitendra Singh <39991107+jitendra-webkul@users.noreply.github.com> Co-authored-by: Shubham Mehrotra Co-authored-by: rahulshukla-webkul <42834394+rahulshukla-webkul@users.noreply.github.com> --- .../Admin/publishable/assets/js/admin.js | 2 +- .../Admin/src/Resources/lang/en/app.php | 1 + .../views/catalog/attributes/create.blade.php | 62 ++++++++-- .../views/catalog/attributes/edit.blade.php | 73 +++++++++-- .../Resources/views/dashboard/index.blade.php | 2 +- .../views/settings/sliders/edit.blade.php | 2 +- .../Database/Factories/AttributeFactory.php | 84 +++++++++++++ .../Factories/AttributeOptionFactory.php | 83 +++++++++++++ .../Providers/AttributeServiceProvider.php | 3 + .../Http/Controllers/CustomerController.php | 30 ++--- packages/Webkul/Product/src/Helpers/View.php | 16 ++- .../src/Repositories/ProductRepository.php | 12 +- .../Webkul/Product/src/Type/AbstractType.php | 6 +- .../DownloadableProductController.php | 4 +- .../src/Http/Controllers/ReviewController.php | 15 +-- .../src/Resources/assets/js/lang/locales.js | 18 +-- .../views/checkout/onepage.blade.php | 1 + .../customers/account/profile/index.blade.php | 6 + .../views/products/view/attributes.blade.php | 30 ++--- .../Resources/views/datagrid/body.blade.php | 4 + public/installer/Finish.php | 6 +- tests/functional/Product/ProductCest.php | 113 ++++++++++++++++++ 22 files changed, 488 insertions(+), 85 deletions(-) create mode 100644 packages/Webkul/Attribute/src/Database/Factories/AttributeFactory.php create mode 100644 packages/Webkul/Attribute/src/Database/Factories/AttributeOptionFactory.php create mode 100644 tests/functional/Product/ProductCest.php diff --git a/packages/Webkul/Admin/publishable/assets/js/admin.js b/packages/Webkul/Admin/publishable/assets/js/admin.js index 47d88041c..26b22274d 100755 --- a/packages/Webkul/Admin/publishable/assets/js/admin.js +++ b/packages/Webkul/Admin/publishable/assets/js/admin.js @@ -1 +1 @@ -!function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:r})},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=0)}({0:function(e,t,n){n("J66Q"),e.exports=n("MT9B")},"162o":function(e,t,n){(function(e){var r=void 0!==e&&e||"undefined"!=typeof self&&self||window,i=Function.prototype.apply;function o(e,t){this._id=e,this._clearFn=t}t.setTimeout=function(){return new o(i.call(setTimeout,r,arguments),clearTimeout)},t.setInterval=function(){return new o(i.call(setInterval,r,arguments),clearInterval)},t.clearTimeout=t.clearInterval=function(e){e&&e.close()},o.prototype.unref=o.prototype.ref=function(){},o.prototype.close=function(){this._clearFn.call(r,this._id)},t.enroll=function(e,t){clearTimeout(e._idleTimeoutId),e._idleTimeout=t},t.unenroll=function(e){clearTimeout(e._idleTimeoutId),e._idleTimeout=-1},t._unrefActive=t.active=function(e){clearTimeout(e._idleTimeoutId);var t=e._idleTimeout;t>=0&&(e._idleTimeoutId=setTimeout(function(){e._onTimeout&&e._onTimeout()},t))},n("mypn"),t.setImmediate="undefined"!=typeof self&&self.setImmediate||void 0!==e&&e.setImmediate||this&&this.setImmediate,t.clearImmediate="undefined"!=typeof self&&self.clearImmediate||void 0!==e&&e.clearImmediate||this&&this.clearImmediate}).call(t,n("DuR2"))},"21It":function(e,t,n){"use strict";var r=n("FtD3");e.exports=function(e,t,n){var i=n.config.validateStatus;n.status&&i&&!i(n.status)?t(r("Request failed with status code "+n.status,n.config,null,n.request,n)):e(n)}},"3IRH":function(e,t){e.exports=function(e){return e.webpackPolyfill||(e.deprecate=function(){},e.paths=[],e.children||(e.children=[]),Object.defineProperty(e,"loaded",{enumerable:!0,get:function(){return e.l}}),Object.defineProperty(e,"id",{enumerable:!0,get:function(){return e.i}}),e.webpackPolyfill=1),e}},"5VQ+":function(e,t,n){"use strict";var r=n("cGG2");e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},"7GwW":function(e,t,n){"use strict";var r=n("cGG2"),i=n("21It"),o=n("DQCr"),a=n("oJlt"),u=n("GHBc"),s=n("FtD3"),c="undefined"!=typeof window&&window.btoa&&window.btoa.bind(window)||n("thJu");e.exports=function(e){return new Promise(function(t,l){var f=e.data,d=e.headers;r.isFormData(f)&&delete d["Content-Type"];var p=new XMLHttpRequest,h="onreadystatechange",v=!1;if("undefined"==typeof window||!window.XDomainRequest||"withCredentials"in p||u(e.url)||(p=new window.XDomainRequest,h="onload",v=!0,p.onprogress=function(){},p.ontimeout=function(){}),e.auth){var m=e.auth.username||"",g=e.auth.password||"";d.Authorization="Basic "+c(m+":"+g)}if(p.open(e.method.toUpperCase(),o(e.url,e.params,e.paramsSerializer),!0),p.timeout=e.timeout,p[h]=function(){if(p&&(4===p.readyState||v)&&(0!==p.status||p.responseURL&&0===p.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in p?a(p.getAllResponseHeaders()):null,r={data:e.responseType&&"text"!==e.responseType?p.response:p.responseText,status:1223===p.status?204:p.status,statusText:1223===p.status?"No Content":p.statusText,headers:n,config:e,request:p};i(t,l,r),p=null}},p.onerror=function(){l(s("Network Error",e,null,p)),p=null},p.ontimeout=function(){l(s("timeout of "+e.timeout+"ms exceeded",e,"ECONNABORTED",p)),p=null},r.isStandardBrowserEnv()){var y=n("p1b6"),b=(e.withCredentials||u(e.url))&&e.xsrfCookieName?y.read(e.xsrfCookieName):void 0;b&&(d[e.xsrfHeaderName]=b)}if("setRequestHeader"in p&&r.forEach(d,function(e,t){void 0===f&&"content-type"===t.toLowerCase()?delete d[t]:p.setRequestHeader(t,e)}),e.withCredentials&&(p.withCredentials=!0),e.responseType)try{p.responseType=e.responseType}catch(t){if("json"!==e.responseType)throw t}"function"==typeof e.onDownloadProgress&&p.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&p.upload&&p.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then(function(e){p&&(p.abort(),l(e),p=null)}),void 0===f&&(f=null),p.send(f)})}},"7t+N":function(e,t,n){var r;!function(t,n){"use strict";"object"==typeof e&&"object"==typeof e.exports?e.exports=t.document?n(t,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return n(e)}:n(t)}("undefined"!=typeof window?window:this,function(n,i){"use strict";var o=[],a=n.document,u=Object.getPrototypeOf,s=o.slice,c=o.concat,l=o.push,f=o.indexOf,d={},p=d.toString,h=d.hasOwnProperty,v=h.toString,m=v.call(Object),g={},y=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},b=function(e){return null!=e&&e===e.window},_={type:!0,src:!0,nonce:!0,noModule:!0};function w(e,t,n){var r,i,o=(n=n||a).createElement("script");if(o.text=e,t)for(r in _)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?d[p.call(e)]||"object":typeof e}var T=function(e,t){return new T.fn.init(e,t)},C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function A(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!y(e)&&!b(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}T.fn=T.prototype={jquery:"3.4.1",constructor:T,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=T.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return T.each(this,e)},map:function(e){return this.pushStack(T.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n+~]|"+I+")"+I+"*"),W=new RegExp(I+"|>"),Y=new RegExp(q),V=new RegExp("^"+R+"$"),Z={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+I+"*(even|odd|(([+-]|)(\\d*)n|)"+I+"*(?:([+-]|)"+I+"*(\\d+)|))"+I+"*\\)|)","i"),bool:new RegExp("^(?:"+F+")$","i"),needsContext:new RegExp("^"+I+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+I+"*((?:-\\d)?\\d*)"+I+"*\\)|)(?=[^-]|$)","i")},G=/HTML$/i,X=/^(?:input|select|textarea|button)$/i,K=/^h\d$/i,J=/^[^{]+\{\s*\[native \w/,Q=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+I+"?|("+I+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"�":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){d()},ae=_e(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{N.apply(O=L.call(w.childNodes),w.childNodes),O[w.childNodes.length].nodeType}catch(e){N={apply:O.length?function(e,t){j.apply(e,L.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}function ue(e,t,r,i){var o,u,c,l,f,h,g,y=t&&t.ownerDocument,x=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==x&&9!==x&&11!==x)return r;if(!i&&((t?t.ownerDocument||t:w)!==p&&d(t),t=t||p,v)){if(11!==x&&(f=Q.exec(e)))if(o=f[1]){if(9===x){if(!(c=t.getElementById(o)))return r;if(c.id===o)return r.push(c),r}else if(y&&(c=y.getElementById(o))&&b(t,c)&&c.id===o)return r.push(c),r}else{if(f[2])return N.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return N.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!k[e+" "]&&(!m||!m.test(e))&&(1!==x||"object"!==t.nodeName.toLowerCase())){if(g=e,y=t,1===x&&W.test(e)){for((l=t.getAttribute("id"))?l=l.replace(re,ie):t.setAttribute("id",l=_),u=(h=a(e)).length;u--;)h[u]="#"+l+" "+be(h[u]);g=h.join(","),y=ee.test(e)&&ge(t.parentNode)||t}try{return N.apply(r,y.querySelectorAll(g)),r}catch(t){k(e,!0)}finally{l===_&&t.removeAttribute("id")}}}return s(e.replace(U,"$1"),t,r,i)}function se(){var e=[];return function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}}function ce(e){return e[_]=!0,e}function le(e){var t=p.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){for(var n=e.split("|"),i=n.length;i--;)r.attrHandle[n[i]]=t}function de(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function pe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function he(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ve(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ae(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function me(e){return ce(function(t){return t=+t,ce(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&void 0!==e.getElementsByTagName&&e}for(t in n=ue.support={},o=ue.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!G.test(t||n&&n.nodeName||"HTML")},d=ue.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==p&&9===a.nodeType&&a.documentElement?(h=(p=a).documentElement,v=!o(p),w!==p&&(i=p.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",oe,!1):i.attachEvent&&i.attachEvent("onunload",oe)),n.attributes=le(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=le(function(e){return e.appendChild(p.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=J.test(p.getElementsByClassName),n.getById=le(function(e){return h.appendChild(e).id=_,!p.getElementsByName||!p.getElementsByName(_).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if(void 0!==t.getElementById&&v){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(te,ne);return function(e){var n=void 0!==e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if(void 0!==t.getElementById&&v){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];for(i=t.getElementsByName(e),r=0;o=i[r++];)if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if(void 0!==t.getElementsByClassName&&v)return t.getElementsByClassName(e)},g=[],m=[],(n.qsa=J.test(p.querySelectorAll))&&(le(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&m.push("[*^$]="+I+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||m.push("\\["+I+"*(?:value|"+F+")"),e.querySelectorAll("[id~="+_+"-]").length||m.push("~="),e.querySelectorAll(":checked").length||m.push(":checked"),e.querySelectorAll("a#"+_+"+*").length||m.push(".#.+[+~]")}),le(function(e){e.innerHTML="";var t=p.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&m.push("name"+I+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&m.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&m.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),m.push(",.*:")})),(n.matchesSelector=J.test(y=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&le(function(e){n.disconnectedMatch=y.call(e,"*"),y.call(e,"[s!='']:x"),g.push("!=",q)}),m=m.length&&new RegExp(m.join("|")),g=g.length&&new RegExp(g.join("|")),t=J.test(h.compareDocumentPosition),b=t||J.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===p||e.ownerDocument===w&&b(w,e)?-1:t===p||t.ownerDocument===w&&b(w,t)?1:l?M(l,e)-M(l,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],u=[t];if(!i||!o)return e===p?-1:t===p?1:i?-1:o?1:l?M(l,e)-M(l,t):0;if(i===o)return de(e,t);for(n=e;n=n.parentNode;)a.unshift(n);for(n=t;n=n.parentNode;)u.unshift(n);for(;a[r]===u[r];)r++;return r?de(a[r],u[r]):a[r]===w?-1:u[r]===w?1:0},p):p},ue.matches=function(e,t){return ue(e,null,null,t)},ue.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&d(e),n.matchesSelector&&v&&!k[t+" "]&&(!g||!g.test(t))&&(!m||!m.test(t)))try{var r=y.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){k(t,!0)}return ue(t,p,null,[e]).length>0},ue.contains=function(e,t){return(e.ownerDocument||e)!==p&&d(e),b(e,t)},ue.attr=function(e,t){(e.ownerDocument||e)!==p&&d(e);var i=r.attrHandle[t.toLowerCase()],o=i&&S.call(r.attrHandle,t.toLowerCase())?i(e,t,!v):void 0;return void 0!==o?o:n.attributes||!v?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},ue.escape=function(e){return(e+"").replace(re,ie)},ue.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},ue.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,l=!n.sortStable&&e.slice(0),e.sort(D),f){for(;t=e[o++];)t===e[o]&&(i=r.push(o));for(;i--;)e.splice(r[i],1)}return l=null,e},i=ue.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else for(;t=e[r++];)n+=i(t);return n},(r=ue.selectors={cacheLength:50,createPseudo:ce,match:Z,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||ue.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&ue.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return Z.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&Y.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=new RegExp("(^|"+I+")"+e+"("+I+"|$)"))&&C(e,function(e){return t.test("string"==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ue.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace(H," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),u="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,s){var c,l,f,d,p,h,v=o!==a?"nextSibling":"previousSibling",m=t.parentNode,g=u&&t.nodeName.toLowerCase(),y=!s&&!u,b=!1;if(m){if(o){for(;v;){for(d=t;d=d[v];)if(u?d.nodeName.toLowerCase()===g:1===d.nodeType)return!1;h=v="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&y){for(b=(p=(c=(l=(f=(d=m)[_]||(d[_]={}))[d.uniqueID]||(f[d.uniqueID]={}))[e]||[])[0]===x&&c[1])&&c[2],d=p&&m.childNodes[p];d=++p&&d&&d[v]||(b=p=0)||h.pop();)if(1===d.nodeType&&++b&&d===t){l[e]=[x,p,b];break}}else if(y&&(b=p=(c=(l=(f=(d=t)[_]||(d[_]={}))[d.uniqueID]||(f[d.uniqueID]={}))[e]||[])[0]===x&&c[1]),!1===b)for(;(d=++p&&d&&d[v]||(b=p=0)||h.pop())&&((u?d.nodeName.toLowerCase()!==g:1!==d.nodeType)||!++b||(y&&((l=(f=d[_]||(d[_]={}))[d.uniqueID]||(f[d.uniqueID]={}))[e]=[x,b]),d!==t)););return(b-=i)===r||b%r==0&&b/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||ue.error("unsupported pseudo: "+e);return i[_]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?ce(function(e,n){for(var r,o=i(e,t),a=o.length;a--;)e[r=M(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:ce(function(e){var t=[],n=[],r=u(e.replace(U,"$1"));return r[_]?ce(function(e,t,n,i){for(var o,a=r(e,null,i,[]),u=e.length;u--;)(o=a[u])&&(e[u]=!(t[u]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:ce(function(e){return function(t){return ue(e,t).length>0}}),contains:ce(function(e){return e=e.replace(te,ne),function(t){return(t.textContent||i(t)).indexOf(e)>-1}}),lang:ce(function(e){return V.test(e||"")||ue.error("unsupported lang: "+e),e=e.replace(te,ne).toLowerCase(),function(t){var n;do{if(n=v?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ve(!1),disabled:ve(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return K.test(e.nodeName)},input:function(e){return X.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:me(function(){return[0]}),last:me(function(e,t){return[t-1]}),eq:me(function(e,t,n){return[n<0?n+t:n]}),even:me(function(e,t){for(var n=0;nt?t:n;--r>=0;)e.push(r);return e}),gt:me(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xe(e,t,n,r,i){for(var o,a=[],u=0,s=e.length,c=null!=t;u-1&&(o[c]=!(a[c]=f))}}else g=xe(g===a?g.splice(h,g.length):g),i?i(null,a,g,s):N.apply(a,g)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],u=a||r.relative[" "],s=a?1:0,l=_e(function(e){return e===t},u,!0),f=_e(function(e){return M(t,e)>-1},u,!0),d=[function(e,n,r){var i=!a&&(r||n!==c)||((t=n).nodeType?l(e,n,r):f(e,n,r));return t=null,i}];s1&&we(d),s>1&&be(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(U,"$1"),n,s0,i=e.length>0,o=function(o,a,u,s,l){var f,h,m,g=0,y="0",b=o&&[],_=[],w=c,T=o||i&&r.find.TAG("*",l),C=x+=null==w?1:Math.random()||.1,A=T.length;for(l&&(c=a===p||a||l);y!==A&&null!=(f=T[y]);y++){if(i&&f){for(h=0,a||f.ownerDocument===p||(d(f),u=!v);m=e[h++];)if(m(f,a||p,u)){s.push(f);break}l&&(x=C)}n&&((f=!m&&f)&&g--,o&&b.push(f))}if(g+=y,n&&y!==g){for(h=0;m=t[h++];)m(b,_,a,u);if(o){if(g>0)for(;y--;)b[y]||_[y]||(_[y]=E.call(s));_=xe(_)}N.apply(s,_),l&&!o&&_.length>0&&g+t.length>1&&ue.uniqueSort(s)}return l&&(x=C,c=w),b};return n?ce(o):o}(o,i))).selector=e}return u},s=ue.select=function(e,t,n,i){var o,s,c,l,f,d="function"==typeof e&&e,p=!i&&a(e=d.selector||e);if(n=n||[],1===p.length){if((s=p[0]=p[0].slice(0)).length>2&&"ID"===(c=s[0]).type&&9===t.nodeType&&v&&r.relative[s[1].type]){if(!(t=(r.find.ID(c.matches[0].replace(te,ne),t)||[])[0]))return n;d&&(t=t.parentNode),e=e.slice(s.shift().value.length)}for(o=Z.needsContext.test(e)?0:s.length;o--&&(c=s[o],!r.relative[l=c.type]);)if((f=r.find[l])&&(i=f(c.matches[0].replace(te,ne),ee.test(s[0].type)&&ge(t.parentNode)||t))){if(s.splice(o,1),!(e=i.length&&be(s)))return N.apply(n,i),n;break}}return(d||u(e,p))(i,t,!v,n,!t||ee.test(e)&&ge(t.parentNode)||t),n},n.sortStable=_.split("").sort(D).join("")===_,n.detectDuplicates=!!f,d(),n.sortDetached=le(function(e){return 1&e.compareDocumentPosition(p.createElement("fieldset"))}),le(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&le(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),le(function(e){return null==e.getAttribute("disabled")})||fe(F,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),ue}(n);T.find=$,T.expr=$.selectors,T.expr[":"]=T.expr.pseudos,T.uniqueSort=T.unique=$.uniqueSort,T.text=$.getText,T.isXMLDoc=$.isXML,T.contains=$.contains,T.escapeSelector=$.escape;var k=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&T(e).is(n))break;r.push(e)}return r},D=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},S=T.expr.match.needsContext;function O(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var E=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return y(t)?T.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?T.grep(e,function(e){return e===t!==n}):"string"!=typeof t?T.grep(e,function(e){return f.call(t,e)>-1!==n}):T.filter(t,e,n)}T.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?T.find.matchesSelector(r,e)?[r]:[]:T.find.matches(e,T.grep(t,function(e){return 1===e.nodeType}))},T.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(T(e).filter(function(){for(t=0;t1?T.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&S.test(e)?T(e):e||[],!1).length}});var N,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(T.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||N,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof T?t[0]:t,T.merge(this,T.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:a,!0)),E.test(r[1])&&T.isPlainObject(t))for(r in t)y(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=a.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):y(e)?void 0!==n.ready?n.ready(e):e(T):T.makeArray(e,this)}).prototype=T.fn,N=T(a);var M=/^(?:parents|prev(?:Until|All))/,F={children:!0,contents:!0,next:!0,prev:!0};function I(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}T.fn.extend({has:function(e){var t=T(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&T.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?T.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?f.call(T(e),this[0]):f.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(T.uniqueSort(T.merge(this.get(),T(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),T.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return I(e,"nextSibling")},prev:function(e){return I(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return D((e.parentNode||{}).firstChild,e)},children:function(e){return D(e.firstChild)},contents:function(e){return void 0!==e.contentDocument?e.contentDocument:(O(e,"template")&&(e=e.content||e),T.merge([],e.childNodes))}},function(e,t){T.fn[e]=function(n,r){var i=T.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=T.filter(r,i)),this.length>1&&(F[e]||T.uniqueSort(i),M.test(e)&&i.reverse()),this.pushStack(i)}});var R=/[^\x20\t\r\n\f]+/g;function P(e){return e}function q(e){throw e}function H(e,t,n,r){var i;try{e&&y(i=e.promise)?i.call(e).done(t).fail(n):e&&y(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}T.Callbacks=function(e){e="string"==typeof e?function(e){var t={};return T.each(e.match(R)||[],function(e,n){t[n]=!0}),t}(e):T.extend({},e);var t,n,r,i,o=[],a=[],u=-1,s=function(){for(i=i||e.once,r=t=!0;a.length;u=-1)for(n=a.shift();++u-1;)o.splice(n,1),n<=u&&u--}),this},has:function(e){return e?T.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||s()),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},T.extend({Deferred:function(e){var t=[["notify","progress",T.Callbacks("memory"),T.Callbacks("memory"),2],["resolve","done",T.Callbacks("once memory"),T.Callbacks("once memory"),0,"resolved"],["reject","fail",T.Callbacks("once memory"),T.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},catch:function(e){return i.then(null,e)},pipe:function(){var e=arguments;return T.Deferred(function(n){T.each(t,function(t,r){var i=y(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&y(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(e,r,i){var o=0;function a(e,t,r,i){return function(){var u=this,s=arguments,c=function(){var n,c;if(!(e=o&&(r!==q&&(u=void 0,s=[n]),t.rejectWith(u,s))}};e?l():(T.Deferred.getStackHook&&(l.stackTrace=T.Deferred.getStackHook()),n.setTimeout(l))}}return T.Deferred(function(n){t[0][3].add(a(0,n,y(i)?i:P,n.notifyWith)),t[1][3].add(a(0,n,y(e)?e:P)),t[2][3].add(a(0,n,y(r)?r:q))}).promise()},promise:function(e){return null!=e?T.extend(e,i):i}},o={};return T.each(t,function(e,n){var a=n[2],u=n[5];i[n[1]]=a.add,u&&a.add(function(){r=u},t[3-e][2].disable,t[3-e][3].disable,t[0][2].lock,t[0][3].lock),a.add(n[3].fire),o[n[0]]=function(){return o[n[0]+"With"](this===o?void 0:this,arguments),this},o[n[0]+"With"]=a.fireWith}),i.promise(o),e&&e.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=s.call(arguments),o=T.Deferred(),a=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?s.call(arguments):n,--t||o.resolveWith(r,i)}};if(t<=1&&(H(e,o.done(a(n)).resolve,o.reject,!t),"pending"===o.state()||y(i[n]&&i[n].then)))return o.then();for(;n--;)H(i[n],a(n),o.reject);return o.promise()}});var U=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;T.Deferred.exceptionHook=function(e,t){n.console&&n.console.warn&&e&&U.test(e.name)&&n.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},T.readyException=function(e){n.setTimeout(function(){throw e})};var B=T.Deferred();function z(){a.removeEventListener("DOMContentLoaded",z),n.removeEventListener("load",z),T.ready()}T.fn.ready=function(e){return B.then(e).catch(function(e){T.readyException(e)}),this},T.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--T.readyWait:T.isReady)||(T.isReady=!0,!0!==e&&--T.readyWait>0||B.resolveWith(a,[T]))}}),T.ready.then=B.then,"complete"===a.readyState||"loading"!==a.readyState&&!a.documentElement.doScroll?n.setTimeout(T.ready):(a.addEventListener("DOMContentLoaded",z),n.addEventListener("load",z));var W=function(e,t,n,r,i,o,a){var u=0,s=e.length,c=null==n;if("object"===x(n))for(u in i=!0,n)W(e,t,u,n[u],!0,o,a);else if(void 0!==r&&(i=!0,y(r)||(a=!0),c&&(a?(t.call(e,r),t=null):(c=t,t=function(e,t,n){return c.call(T(e),n)})),t))for(;u1,null,!0)},removeData:function(e){return this.each(function(){Q.remove(this,e)})}}),T.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,T.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=T.queue(e,t),r=n.length,i=n.shift(),o=T._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){T.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:T.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),T.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]*)/i,ge=/^$|^module$|\/(?:java|ecma)script/i,ye={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function be(e,t){var n;return n=void 0!==e.getElementsByTagName?e.getElementsByTagName(t||"*"):void 0!==e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&O(e,t)?T.merge([e],n):n}function _e(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(c=ue(o),a=be(f.appendChild(o),"script"),c&&_e(a),n)for(l=0;o=a[l++];)ge.test(o.type||"")&&n.push(o);return f}we=a.createDocumentFragment().appendChild(a.createElement("div")),(xe=a.createElement("input")).setAttribute("type","radio"),xe.setAttribute("checked","checked"),xe.setAttribute("name","t"),we.appendChild(xe),g.checkClone=we.cloneNode(!0).cloneNode(!0).lastChild.checked,we.innerHTML="",g.noCloneChecked=!!we.cloneNode(!0).lastChild.defaultValue;var Ae=/^key/,$e=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ke=/^([^.]*)(?:\.(.+)|)/;function De(){return!0}function Se(){return!1}function Oe(e,t){return e===function(){try{return a.activeElement}catch(e){}}()==("focus"===t)}function Ee(e,t,n,r,i,o){var a,u;if("object"==typeof t){for(u in"string"!=typeof n&&(r=r||n,n=void 0),t)Ee(e,u,n,r,t[u],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return T().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=T.guid++)),e.each(function(){T.event.add(this,t,i,r,n)})}function je(e,t,n){n?(J.set(e,t,!1),T.event.add(e,t,{namespace:!1,handler:function(e){var r,i,o=J.get(this,t);if(1&e.isTrigger&&this[t]){if(o.length)(T.event.special[t]||{}).delegateType&&e.stopPropagation();else if(o=s.call(arguments),J.set(this,t,o),r=n(this,t),this[t](),o!==(i=J.get(this,t))||r?J.set(this,t,!1):i={},o!==i)return e.stopImmediatePropagation(),e.preventDefault(),i.value}else o.length&&(J.set(this,t,{value:T.event.trigger(T.extend(o[0],T.Event.prototype),o.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===J.get(e,t)&&T.event.add(e,t,De)}T.event={global:{},add:function(e,t,n,r,i){var o,a,u,s,c,l,f,d,p,h,v,m=J.get(e);if(m)for(n.handler&&(n=(o=n).handler,i=o.selector),i&&T.find.matchesSelector(ae,i),n.guid||(n.guid=T.guid++),(s=m.events)||(s=m.events={}),(a=m.handle)||(a=m.handle=function(t){return void 0!==T&&T.event.triggered!==t.type?T.event.dispatch.apply(e,arguments):void 0}),c=(t=(t||"").match(R)||[""]).length;c--;)p=v=(u=ke.exec(t[c])||[])[1],h=(u[2]||"").split(".").sort(),p&&(f=T.event.special[p]||{},p=(i?f.delegateType:f.bindType)||p,f=T.event.special[p]||{},l=T.extend({type:p,origType:v,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&T.expr.match.needsContext.test(i),namespace:h.join(".")},o),(d=s[p])||((d=s[p]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(p,a)),f.add&&(f.add.call(e,l),l.handler.guid||(l.handler.guid=n.guid)),i?d.splice(d.delegateCount++,0,l):d.push(l),T.event.global[p]=!0)},remove:function(e,t,n,r,i){var o,a,u,s,c,l,f,d,p,h,v,m=J.hasData(e)&&J.get(e);if(m&&(s=m.events)){for(c=(t=(t||"").match(R)||[""]).length;c--;)if(p=v=(u=ke.exec(t[c])||[])[1],h=(u[2]||"").split(".").sort(),p){for(f=T.event.special[p]||{},d=s[p=(r?f.delegateType:f.bindType)||p]||[],u=u[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=d.length;o--;)l=d[o],!i&&v!==l.origType||n&&n.guid!==l.guid||u&&!u.test(l.namespace)||r&&r!==l.selector&&("**"!==r||!l.selector)||(d.splice(o,1),l.selector&&d.delegateCount--,f.remove&&f.remove.call(e,l));a&&!d.length&&(f.teardown&&!1!==f.teardown.call(e,h,m.handle)||T.removeEvent(e,p,m.handle),delete s[p])}else for(p in s)T.event.remove(e,p+t[c],n,r,!0);T.isEmptyObject(s)&&J.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,u=T.event.fix(e),s=new Array(arguments.length),c=(J.get(this,"events")||{})[u.type]||[],l=T.event.special[u.type]||{};for(s[0]=u,t=1;t=1))for(;c!==this;c=c.parentNode||this)if(1===c.nodeType&&("click"!==e.type||!0!==c.disabled)){for(o=[],a={},n=0;n-1:T.find(i,this,null,[c]).length),a[i]&&o.push(r);o.length&&u.push({elem:c,handlers:o})}return c=this,s\x20\t\r\n\f]*)[^>]*)\/>/gi,Le=/\s*$/g;function Ie(e,t){return O(e,"table")&&O(11!==t.nodeType?t:t.firstChild,"tr")&&T(e).children("tbody")[0]||e}function Re(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Pe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function qe(e,t){var n,r,i,o,a,u,s,c;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),c=o.events))for(i in delete a.handle,a.events={},c)for(n=0,r=c[i].length;n1&&"string"==typeof h&&!g.checkClone&&Me.test(h))return e.each(function(i){var o=e.eq(i);v&&(t[0]=h.call(this,i,o.html())),He(o,t,n,r)});if(d&&(o=(i=Ce(t,e[0].ownerDocument,!1,e,r)).firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(a=T.map(be(i,"script"),Re)).length;f")},clone:function(e,t,n){var r,i,o,a,u,s,c,l=e.cloneNode(!0),f=ue(e);if(!(g.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||T.isXMLDoc(e)))for(a=be(l),r=0,i=(o=be(e)).length;r0&&_e(a,!f&&be(e,"script")),l},cleanData:function(e){for(var t,n,r,i=T.event.special,o=0;void 0!==(n=e[o]);o++)if(X(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?T.event.remove(n,r):T.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),T.fn.extend({detach:function(e){return Ue(this,e,!0)},remove:function(e){return Ue(this,e)},text:function(e){return W(this,function(e){return void 0===e?T.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return He(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Ie(this,e).appendChild(e)})},prepend:function(){return He(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Ie(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return He(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return He(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(T.cleanData(be(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return T.clone(this,e,t)})},html:function(e){return W(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Le.test(e)&&!ye[(me.exec(e)||["",""])[1].toLowerCase()]){e=T.htmlPrefilter(e);try{for(;n=0&&(s+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-s-u-.5))||0),s}function it(e,t,n){var r=ze(e),i=(!g.boxSizingReliable()||n)&&"border-box"===T.css(e,"boxSizing",!1,r),o=i,a=Ye(e,t,r),u="offset"+t[0].toUpperCase()+t.slice(1);if(Be.test(a)){if(!n)return a;a="auto"}return(!g.boxSizingReliable()&&i||"auto"===a||!parseFloat(a)&&"inline"===T.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===T.css(e,"boxSizing",!1,r),(o=u in e)&&(a=e[u])),(a=parseFloat(a)||0)+rt(e,t,n||(i?"border":"content"),o,r,a)+"px"}function ot(e,t,n,r,i){return new ot.prototype.init(e,t,n,r,i)}T.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Ye(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,u=G(t),s=Qe.test(t),c=e.style;if(s||(t=Ke(u)),a=T.cssHooks[t]||T.cssHooks[u],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:c[t];"string"===(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=fe(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||s||(n+=i&&i[3]||(T.cssNumber[u]?"":"px")),g.clearCloneStyle||""!==n||0!==t.indexOf("background")||(c[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(s?c.setProperty(t,n):c[t]=n))}},css:function(e,t,n,r){var i,o,a,u=G(t);return Qe.test(t)||(t=Ke(u)),(a=T.cssHooks[t]||T.cssHooks[u])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Ye(e,t,r)),"normal"===i&&t in tt&&(i=tt[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),T.each(["height","width"],function(e,t){T.cssHooks[t]={get:function(e,n,r){if(n)return!Je.test(T.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?it(e,t,r):le(e,et,function(){return it(e,t,r)})},set:function(e,n,r){var i,o=ze(e),a=!g.scrollboxSize()&&"absolute"===o.position,u=(a||r)&&"border-box"===T.css(e,"boxSizing",!1,o),s=r?rt(e,t,r,u,o):0;return u&&a&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-rt(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=T.css(e,t)),nt(0,n,s)}}}),T.cssHooks.marginLeft=Ve(g.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Ye(e,"marginLeft"))||e.getBoundingClientRect().left-le(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),T.each({margin:"",padding:"",border:"Width"},function(e,t){T.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(T.cssHooks[e+t].set=nt)}),T.fn.extend({css:function(e,t){return W(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=ze(e),i=t.length;a1)}}),T.Tween=ot,ot.prototype={constructor:ot,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||T.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(T.cssNumber[n]?"":"px")},cur:function(){var e=ot.propHooks[this.prop];return e&&e.get?e.get(this):ot.propHooks._default.get(this)},run:function(e){var t,n=ot.propHooks[this.prop];return this.options.duration?this.pos=t=T.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):ot.propHooks._default.set(this),this}},ot.prototype.init.prototype=ot.prototype,ot.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=T.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){T.fx.step[e.prop]?T.fx.step[e.prop](e):1!==e.elem.nodeType||!T.cssHooks[e.prop]&&null==e.elem.style[Ke(e.prop)]?e.elem[e.prop]=e.now:T.style(e.elem,e.prop,e.now+e.unit)}}},ot.propHooks.scrollTop=ot.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},T.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},T.fx=ot.prototype.init,T.fx.step={};var at,ut,st=/^(?:toggle|show|hide)$/,ct=/queueHooks$/;function lt(){ut&&(!1===a.hidden&&n.requestAnimationFrame?n.requestAnimationFrame(lt):n.setTimeout(lt,T.fx.interval),T.fx.tick())}function ft(){return n.setTimeout(function(){at=void 0}),at=Date.now()}function dt(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function pt(e,t,n){for(var r,i=(ht.tweeners[t]||[]).concat(ht.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){T.removeAttr(this,e)})}}),T.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return void 0===e.getAttribute?T.prop(e,t,n):(1===o&&T.isXMLDoc(e)||(i=T.attrHooks[t.toLowerCase()]||(T.expr.match.bool.test(t)?vt:void 0)),void 0!==n?null===n?void T.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=T.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!g.radioValue&&"radio"===t&&O(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(R);if(i&&1===e.nodeType)for(;n=i[r++];)e.removeAttribute(n)}}),vt={set:function(e,t,n){return!1===t?T.removeAttr(e,n):e.setAttribute(n,n),n}},T.each(T.expr.match.bool.source.match(/\w+/g),function(e,t){var n=mt[t]||T.find.attr;mt[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=mt[a],mt[a]=i,i=null!=n(e,t,r)?a:null,mt[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;function bt(e){return(e.match(R)||[]).join(" ")}function _t(e){return e.getAttribute&&e.getAttribute("class")||""}function wt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(R)||[]}T.fn.extend({prop:function(e,t){return W(this,T.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[T.propFix[e]||e]})}}),T.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&T.isXMLDoc(e)||(t=T.propFix[t]||t,i=T.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=T.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{for:"htmlFor",class:"className"}}),g.optSelected||(T.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),T.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){T.propFix[this.toLowerCase()]=this}),T.fn.extend({addClass:function(e){var t,n,r,i,o,a,u,s=0;if(y(e))return this.each(function(t){T(this).addClass(e.call(this,t,_t(this)))});if((t=wt(e)).length)for(;n=this[s++];)if(i=_t(n),r=1===n.nodeType&&" "+bt(i)+" "){for(a=0;o=t[a++];)r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(u=bt(r))&&n.setAttribute("class",u)}return this},removeClass:function(e){var t,n,r,i,o,a,u,s=0;if(y(e))return this.each(function(t){T(this).removeClass(e.call(this,t,_t(this)))});if(!arguments.length)return this.attr("class","");if((t=wt(e)).length)for(;n=this[s++];)if(i=_t(n),r=1===n.nodeType&&" "+bt(i)+" "){for(a=0;o=t[a++];)for(;r.indexOf(" "+o+" ")>-1;)r=r.replace(" "+o+" "," ");i!==(u=bt(r))&&n.setAttribute("class",u)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):y(e)?this.each(function(n){T(this).toggleClass(e.call(this,n,_t(this),t),t)}):this.each(function(){var t,i,o,a;if(r)for(i=0,o=T(this),a=wt(e);t=a[i++];)o.hasClass(t)?o.removeClass(t):o.addClass(t);else void 0!==e&&"boolean"!==n||((t=_t(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;for(t=" "+e+" ";n=this[r++];)if(1===n.nodeType&&(" "+bt(_t(n))+" ").indexOf(t)>-1)return!0;return!1}});var xt=/\r/g;T.fn.extend({val:function(e){var t,n,r,i=this[0];return arguments.length?(r=y(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,T(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=T.map(i,function(e){return null==e?"":e+""})),(t=T.valHooks[this.type]||T.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))})):i?(t=T.valHooks[i.type]||T.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(xt,""):null==n?"":n:void 0}}),T.extend({valHooks:{option:{get:function(e){var t=T.find.attr(e,"value");return null!=t?t:bt(T.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,u=a?null:[],s=a?o+1:i.length;for(r=o<0?s:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),T.each(["radio","checkbox"],function(){T.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=T.inArray(T(e).val(),t)>-1}},g.checkOn||(T.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),g.focusin="onfocusin"in n;var Tt=/^(?:focusinfocus|focusoutblur)$/,Ct=function(e){e.stopPropagation()};T.extend(T.event,{trigger:function(e,t,r,i){var o,u,s,c,l,f,d,p,v=[r||a],m=h.call(e,"type")?e.type:e,g=h.call(e,"namespace")?e.namespace.split("."):[];if(u=p=s=r=r||a,3!==r.nodeType&&8!==r.nodeType&&!Tt.test(m+T.event.triggered)&&(m.indexOf(".")>-1&&(m=(g=m.split(".")).shift(),g.sort()),l=m.indexOf(":")<0&&"on"+m,(e=e[T.expando]?e:new T.Event(m,"object"==typeof e&&e)).isTrigger=i?2:3,e.namespace=g.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=r),t=null==t?[e]:T.makeArray(t,[e]),d=T.event.special[m]||{},i||!d.trigger||!1!==d.trigger.apply(r,t))){if(!i&&!d.noBubble&&!b(r)){for(c=d.delegateType||m,Tt.test(c+m)||(u=u.parentNode);u;u=u.parentNode)v.push(u),s=u;s===(r.ownerDocument||a)&&v.push(s.defaultView||s.parentWindow||n)}for(o=0;(u=v[o++])&&!e.isPropagationStopped();)p=u,e.type=o>1?c:d.bindType||m,(f=(J.get(u,"events")||{})[e.type]&&J.get(u,"handle"))&&f.apply(u,t),(f=l&&u[l])&&f.apply&&X(u)&&(e.result=f.apply(u,t),!1===e.result&&e.preventDefault());return e.type=m,i||e.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),t)||!X(r)||l&&y(r[m])&&!b(r)&&((s=r[l])&&(r[l]=null),T.event.triggered=m,e.isPropagationStopped()&&p.addEventListener(m,Ct),r[m](),e.isPropagationStopped()&&p.removeEventListener(m,Ct),T.event.triggered=void 0,s&&(r[l]=s)),e.result}},simulate:function(e,t,n){var r=T.extend(new T.Event,n,{type:e,isSimulated:!0});T.event.trigger(r,null,t)}}),T.fn.extend({trigger:function(e,t){return this.each(function(){T.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return T.event.trigger(e,t,n,!0)}}),g.focusin||T.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){T.event.simulate(t,e.target,T.event.fix(e))};T.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var At=n.location,$t=Date.now(),kt=/\?/;T.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new n.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||T.error("Invalid XML: "+e),t};var Dt=/\[\]$/,St=/\r?\n/g,Ot=/^(?:submit|button|image|reset|file)$/i,Et=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))T.each(t,function(t,i){n||Dt.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}T.param=function(e,t){var n,r=[],i=function(e,t){var n=y(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!T.isPlainObject(e))T.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},T.fn.extend({serialize:function(){return T.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=T.prop(this,"elements");return e?T.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!T(this).is(":disabled")&&Et.test(this.nodeName)&&!Ot.test(e)&&(this.checked||!ve.test(e))}).map(function(e,t){var n=T(this).val();return null==n?null:Array.isArray(n)?T.map(n,function(e){return{name:t.name,value:e.replace(St,"\r\n")}}):{name:t.name,value:n.replace(St,"\r\n")}}).get()}});var Nt=/%20/g,Lt=/#.*$/,Mt=/([?&])_=[^&]*/,Ft=/^(.*?):[ \t]*([^\r\n]*)$/gm,It=/^(?:GET|HEAD)$/,Rt=/^\/\//,Pt={},qt={},Ht="*/".concat("*"),Ut=a.createElement("a");function Bt(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(R)||[];if(y(n))for(;r=o[i++];)"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function zt(e,t,n,r){var i={},o=e===qt;function a(u){var s;return i[u]=!0,T.each(e[u]||[],function(e,u){var c=u(t,n,r);return"string"!=typeof c||o||i[c]?o?!(s=c):void 0:(t.dataTypes.unshift(c),a(c),!1)}),s}return a(t.dataTypes[0])||!i["*"]&&a("*")}function Wt(e,t){var n,r,i=T.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&T.extend(!0,e,r),e}Ut.href=At.href,T.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:At.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(At.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Ht,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":T.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Wt(Wt(e,T.ajaxSettings),t):Wt(T.ajaxSettings,e)},ajaxPrefilter:Bt(Pt),ajaxTransport:Bt(qt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var r,i,o,u,s,c,l,f,d,p,h=T.ajaxSetup({},t),v=h.context||h,m=h.context&&(v.nodeType||v.jquery)?T(v):T.event,g=T.Deferred(),y=T.Callbacks("once memory"),b=h.statusCode||{},_={},w={},x="canceled",C={readyState:0,getResponseHeader:function(e){var t;if(l){if(!u)for(u={};t=Ft.exec(o);)u[t[1].toLowerCase()+" "]=(u[t[1].toLowerCase()+" "]||[]).concat(t[2]);t=u[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return l?o:null},setRequestHeader:function(e,t){return null==l&&(e=w[e.toLowerCase()]=w[e.toLowerCase()]||e,_[e]=t),this},overrideMimeType:function(e){return null==l&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(l)C.always(e[C.status]);else for(t in e)b[t]=[b[t],e[t]];return this},abort:function(e){var t=e||x;return r&&r.abort(t),A(0,t),this}};if(g.promise(C),h.url=((e||h.url||At.href)+"").replace(Rt,At.protocol+"//"),h.type=t.method||t.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(R)||[""],null==h.crossDomain){c=a.createElement("a");try{c.href=h.url,c.href=c.href,h.crossDomain=Ut.protocol+"//"+Ut.host!=c.protocol+"//"+c.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=T.param(h.data,h.traditional)),zt(Pt,h,t,C),l)return C;for(d in(f=T.event&&h.global)&&0==T.active++&&T.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!It.test(h.type),i=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(Nt,"+")):(p=h.url.slice(i.length),h.data&&(h.processData||"string"==typeof h.data)&&(i+=(kt.test(i)?"&":"?")+h.data,delete h.data),!1===h.cache&&(i=i.replace(Mt,"$1"),p=(kt.test(i)?"&":"?")+"_="+$t+++p),h.url=i+p),h.ifModified&&(T.lastModified[i]&&C.setRequestHeader("If-Modified-Since",T.lastModified[i]),T.etag[i]&&C.setRequestHeader("If-None-Match",T.etag[i])),(h.data&&h.hasContent&&!1!==h.contentType||t.contentType)&&C.setRequestHeader("Content-Type",h.contentType),C.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+Ht+"; q=0.01":""):h.accepts["*"]),h.headers)C.setRequestHeader(d,h.headers[d]);if(h.beforeSend&&(!1===h.beforeSend.call(v,C,h)||l))return C.abort();if(x="abort",y.add(h.complete),C.done(h.success),C.fail(h.error),r=zt(qt,h,t,C)){if(C.readyState=1,f&&m.trigger("ajaxSend",[C,h]),l)return C;h.async&&h.timeout>0&&(s=n.setTimeout(function(){C.abort("timeout")},h.timeout));try{l=!1,r.send(_,A)}catch(e){if(l)throw e;A(-1,e)}}else A(-1,"No Transport");function A(e,t,a,u){var c,d,p,_,w,x=t;l||(l=!0,s&&n.clearTimeout(s),r=void 0,o=u||"",C.readyState=e>0?4:0,c=e>=200&&e<300||304===e,a&&(_=function(e,t,n){for(var r,i,o,a,u=e.contents,s=e.dataTypes;"*"===s[0];)s.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in u)if(u[i]&&u[i].test(r)){s.unshift(i);break}if(s[0]in n)o=s[0];else{for(i in n){if(!s[0]||e.converters[i+" "+s[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==s[0]&&s.unshift(o),n[o]}(h,C,a)),_=function(e,t,n,r){var i,o,a,u,s,c={},l=e.dataTypes.slice();if(l[1])for(a in e.converters)c[a.toLowerCase()]=e.converters[a];for(o=l.shift();o;)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!s&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),s=o,o=l.shift())if("*"===o)o=s;else if("*"!==s&&s!==o){if(!(a=c[s+" "+o]||c["* "+o]))for(i in c)if((u=i.split(" "))[1]===o&&(a=c[s+" "+u[0]]||c["* "+u[0]])){!0===a?a=c[i]:!0!==c[i]&&(o=u[0],l.unshift(u[1]));break}if(!0!==a)if(a&&e.throws)t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+s+" to "+o}}}return{state:"success",data:t}}(h,_,C,c),c?(h.ifModified&&((w=C.getResponseHeader("Last-Modified"))&&(T.lastModified[i]=w),(w=C.getResponseHeader("etag"))&&(T.etag[i]=w)),204===e||"HEAD"===h.type?x="nocontent":304===e?x="notmodified":(x=_.state,d=_.data,c=!(p=_.error))):(p=x,!e&&x||(x="error",e<0&&(e=0))),C.status=e,C.statusText=(t||x)+"",c?g.resolveWith(v,[d,x,C]):g.rejectWith(v,[C,x,p]),C.statusCode(b),b=void 0,f&&m.trigger(c?"ajaxSuccess":"ajaxError",[C,h,c?d:p]),y.fireWith(v,[C,x]),f&&(m.trigger("ajaxComplete",[C,h]),--T.active||T.event.trigger("ajaxStop")))}return C},getJSON:function(e,t,n){return T.get(e,t,n,"json")},getScript:function(e,t){return T.get(e,void 0,t,"script")}}),T.each(["get","post"],function(e,t){T[t]=function(e,n,r,i){return y(n)&&(i=i||r,r=n,n=void 0),T.ajax(T.extend({url:e,type:t,dataType:i,data:n,success:r},T.isPlainObject(e)&&e))}}),T._evalUrl=function(e,t){return T.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){T.globalEval(e,t)}})},T.fn.extend({wrapAll:function(e){var t;return this[0]&&(y(e)&&(e=e.call(this[0])),t=T(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return y(e)?this.each(function(t){T(this).wrapInner(e.call(this,t))}):this.each(function(){var t=T(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=y(e);return this.each(function(n){T(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){T(this).replaceWith(this.childNodes)}),this}}),T.expr.pseudos.hidden=function(e){return!T.expr.pseudos.visible(e)},T.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},T.ajaxSettings.xhr=function(){try{return new n.XMLHttpRequest}catch(e){}};var Yt={0:200,1223:204},Vt=T.ajaxSettings.xhr();g.cors=!!Vt&&"withCredentials"in Vt,g.ajax=Vt=!!Vt,T.ajaxTransport(function(e){var t,r;if(g.cors||Vt&&!e.crossDomain)return{send:function(i,o){var a,u=e.xhr();if(u.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(a in e.xhrFields)u[a]=e.xhrFields[a];for(a in e.mimeType&&u.overrideMimeType&&u.overrideMimeType(e.mimeType),e.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest"),i)u.setRequestHeader(a,i[a]);t=function(e){return function(){t&&(t=r=u.onload=u.onerror=u.onabort=u.ontimeout=u.onreadystatechange=null,"abort"===e?u.abort():"error"===e?"number"!=typeof u.status?o(0,"error"):o(u.status,u.statusText):o(Yt[u.status]||u.status,u.statusText,"text"!==(u.responseType||"text")||"string"!=typeof u.responseText?{binary:u.response}:{text:u.responseText},u.getAllResponseHeaders()))}},u.onload=t(),r=u.onerror=u.ontimeout=t("error"),void 0!==u.onabort?u.onabort=r:u.onreadystatechange=function(){4===u.readyState&&n.setTimeout(function(){t&&r()})},t=t("abort");try{u.send(e.hasContent&&e.data||null)}catch(e){if(t)throw e}},abort:function(){t&&t()}}}),T.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),T.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return T.globalEval(e),e}}}),T.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),T.ajaxTransport("script",function(e){var t,n;if(e.crossDomain||e.scriptAttrs)return{send:function(r,i){t=T(" -@endpush \ No newline at end of file +@endpush diff --git a/packages/Webkul/Admin/src/Resources/views/dashboard/index.blade.php b/packages/Webkul/Admin/src/Resources/views/dashboard/index.blade.php index ed5ff69bb..8de719884 100755 --- a/packages/Webkul/Admin/src/Resources/views/dashboard/index.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/dashboard/index.blade.php @@ -274,7 +274,7 @@ {{ __('admin::app.dashboard.order-count', ['count' => $item->total_orders]) }}  .  {{ __('admin::app.dashboard.revenue', [ - 'total' => core()->formatBasePrice($item->total_base_grand_total_invoiced) + 'total' => core()->formatBasePrice($item->total_base_grand_total) ]) }}
diff --git a/packages/Webkul/Admin/src/Resources/views/settings/sliders/edit.blade.php b/packages/Webkul/Admin/src/Resources/views/settings/sliders/edit.blade.php index cd24bd2a1..af5e28126 100755 --- a/packages/Webkul/Admin/src/Resources/views/settings/sliders/edit.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/settings/sliders/edit.blade.php @@ -52,7 +52,7 @@
- path) }}"' > + @foreach ($errors->get('image.*') as $key => $message) diff --git a/packages/Webkul/Attribute/src/Database/Factories/AttributeFactory.php b/packages/Webkul/Attribute/src/Database/Factories/AttributeFactory.php new file mode 100644 index 000000000..95a538780 --- /dev/null +++ b/packages/Webkul/Attribute/src/Database/Factories/AttributeFactory.php @@ -0,0 +1,84 @@ +define(Attribute::class, function (Faker $faker, array $attributes) { + $types = [ + 'text', + 'textarea', + 'price', + 'boolean', + 'select', + 'multiselect', + 'datetime', + 'date', + 'image', + 'file', + 'checkbox', + ]; + + $locales = Locale::pluck('code')->all(); + + // array $attributes does not contain any locale code + if (count(array_diff_key(array_flip($locales), $attributes) ) === count($locales)) { + $localeCode = $locales[0]; + + $attributes[$localeCode] = [ + 'name' => $faker->word, + ]; + } + + return [ + 'admin_name' => $faker->word, + 'code' => $faker->word, + 'type' => array_rand($types), + 'validation' => '', + 'position' => $faker->randomDigit, + 'is_required' => false, + 'is_unique' => false, + 'value_per_locale' => false, + 'value_per_channel' => false, + 'is_filterable' => false, + 'is_configurable' => false, + 'is_user_defined' => true, + 'is_visible_on_front' => true, + 'swatch_type' => null, + 'use_in_flat' => true, + ]; +}); + +$factory->state(Attribute::class, 'validation_numeric', [ + 'validation' => 'numeric', +]); + +$factory->state(Attribute::class, 'validation_email', [ + 'validation' => 'email', +]); + +$factory->state(Attribute::class, 'validation_decimal', [ + 'validation' => 'decimal', +]); + +$factory->state(Attribute::class, 'validation_url', [ + 'validation' => 'url', +]); + +$factory->state(Attribute::class, 'required', [ + 'is_required' => true, +]); + +$factory->state(Attribute::class, 'unique', [ + 'is_unique' => true, +]); + +$factory->state(Attribute::class, 'filterable', [ + 'is_filterable' => true, +]); + +$factory->state(Attribute::class, 'configurable', [ + 'is_configurable' => true, +]); \ No newline at end of file diff --git a/packages/Webkul/Attribute/src/Database/Factories/AttributeOptionFactory.php b/packages/Webkul/Attribute/src/Database/Factories/AttributeOptionFactory.php new file mode 100644 index 000000000..2612fcc76 --- /dev/null +++ b/packages/Webkul/Attribute/src/Database/Factories/AttributeOptionFactory.php @@ -0,0 +1,83 @@ +define(AttributeOption::class, function (Faker $faker, array $attributes) { + + $locales = Locale::pluck('code')->all(); + + // array $attributes does not contain any locale code + if (count(array_diff_key(array_flip($locales), $attributes) ) === count($locales)) { + $localeCode = $locales[0]; + + $attributes[$localeCode] = [ + 'label' => $faker->word, + ]; + } + + return [ + 'admin_name' => $faker->word, + 'sort_order' => $faker->randomDigit, + 'attribute_id' => function () { + return factory(Attribute::class)->create()->id; + }, + 'swatch_value' => null, + ]; +}); + +$factory->defineAs(AttributeOption::class, 'swatch_color', function (Faker $faker, array $attributes) { + return [ + 'admin_name' => $faker->word, + 'sort_order' => $faker->randomDigit, + 'attribute_id' => function () { + return factory(Attribute::class) + ->create(['swatch_type' => 'color']) + ->id; + }, + 'swatch_value' => $faker->hexColor, + ]; +}); + +$factory->defineAs(AttributeOption::class, 'swatch_image', function (Faker $faker, array $attributes) { + return [ + 'admin_name' => $faker->word, + 'sort_order' => $faker->randomDigit, + 'attribute_id' => function () { + return factory(Attribute::class) + ->create(['swatch_type' => 'image']) + ->id; + }, + 'swatch_value' => '/tests/_data/ProductImageExampleForUpload.jpg', + ]; +}); + +$factory->defineAs(AttributeOption::class, 'swatch_dropdown', function (Faker $faker, array $attributes) { + return [ + 'admin_name' => $faker->word, + 'sort_order' => $faker->randomDigit, + 'attribute_id' => function () { + return factory(Attribute::class) + ->create(['swatch_type' => 'dropdown']) + ->id; + }, + 'swatch_value' => null, + ]; +}); + +$factory->defineAs(AttributeOption::class, 'swatch_text', function (Faker $faker, array $attributes) { + return [ + 'admin_name' => $faker->word, + 'sort_order' => $faker->randomDigit, + 'attribute_id' => function () { + return factory(Attribute::class) + ->create(['swatch_type' => 'text']) + ->id; + }, + 'swatch_value' => null, + ]; +}); \ No newline at end of file diff --git a/packages/Webkul/Attribute/src/Providers/AttributeServiceProvider.php b/packages/Webkul/Attribute/src/Providers/AttributeServiceProvider.php index fa312fe69..72a4daea1 100755 --- a/packages/Webkul/Attribute/src/Providers/AttributeServiceProvider.php +++ b/packages/Webkul/Attribute/src/Providers/AttributeServiceProvider.php @@ -2,6 +2,7 @@ namespace Webkul\Attribute\Providers; +use Illuminate\Database\Eloquent\Factory as EloquentFactory; use Illuminate\Support\ServiceProvider; class AttributeServiceProvider extends ServiceProvider @@ -14,6 +15,8 @@ class AttributeServiceProvider extends ServiceProvider public function boot() { $this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations'); + + $this->app->make(EloquentFactory::class)->load(__DIR__ . '/../Database/Factories'); } /** diff --git a/packages/Webkul/Customer/src/Http/Controllers/CustomerController.php b/packages/Webkul/Customer/src/Http/Controllers/CustomerController.php index b29d8ead2..e1e50d0b4 100755 --- a/packages/Webkul/Customer/src/Http/Controllers/CustomerController.php +++ b/packages/Webkul/Customer/src/Http/Controllers/CustomerController.php @@ -93,8 +93,9 @@ class CustomerController extends Controller 'gender' => 'required', 'date_of_birth' => 'date|before:today', 'email' => 'email|unique:customers,email,'.$id, + 'password' => 'confirmed|min:6|required_with:oldpassword', 'oldpassword' => 'required_with:password', - 'password' => 'confirmed|min:6' + 'password_confirmation' => 'required_with:password', ]); $data = collect(request()->input())->except('_token')->toArray(); @@ -139,27 +140,26 @@ class CustomerController extends Controller $customerRepository = $this->customerRepository->findorFail($id); - $orders = $customerRepository->all_orders->whereIn('status', ['pending', 'processing'])->first(); - - if ( $orders ) { - session()->flash('error', trans('admin::app.response.order-pending')); - - return redirect()->route($this->_config['redirect']); - } - try { - if ( Hash::check($data['password'], $customerRepository->password) ) { + if (Hash::check($data['password'], $customerRepository->password)) { + $orders = $customerRepository->all_orders->whereIn('status', ['pending', 'processing'])->first(); - $this->customerRepository->delete($id); + if ($orders) { + session()->flash('error', trans('admin::app.response.order-pending')); - session()->flash('success', trans('admin::app.response.delete-success', ['name' => 'Customer'])); + return redirect()->route($this->_config['redirect']); + } else { + $this->customerRepository->delete($id); - return redirect()->route('customer.session.index'); + session()->flash('success', trans('admin::app.response.delete-success', ['name' => 'Customer'])); + + return redirect()->route('customer.session.index'); + } } else { session()->flash('error', trans('shop::app.customer.account.address.delete.wrong-password')); - } - return redirect()->route('customer.session.index'); + return redirect()->back(); + } } catch(\Exception $e) { session()->flash('error', trans('admin::app.response.delete-failed', ['name' => 'Customer'])); diff --git a/packages/Webkul/Product/src/Helpers/View.php b/packages/Webkul/Product/src/Helpers/View.php index f52748552..1cf9002df 100755 --- a/packages/Webkul/Product/src/Helpers/View.php +++ b/packages/Webkul/Product/src/Helpers/View.php @@ -13,7 +13,7 @@ class View extends AbstractProduct /** * Returns the visible custom attributes * - * @param Product $product + * @param Webkul\Product\Models\Product $product * @return integer */ public function getAdditionalData($product) @@ -36,15 +36,23 @@ class View extends AbstractProduct } else if($value) { if ($attribute->type == 'select') { $attributeOption = $attributeOptionReposotory->find($value); - if ($attributeOption) - $value = $attributeOption->label ?? $attributeOption->admin_name; + + if ($attributeOption) { + $value = $attributeOption->label ?? null; + + if (! $value) { + continue; + } + } } else if ($attribute->type == 'multiselect' || $attribute->type == 'checkbox') { $lables = []; $attributeOptions = $attributeOptionReposotory->findWhereIn('id', explode(",", $value)); foreach ($attributeOptions as $attributeOption) { - $lables[] = $attributeOption->label ?? $attributeOption->admin_name; + if ($label = $attributeOption->label) { + $lables[] = $label; + } } $value = implode(", ", $lables); diff --git a/packages/Webkul/Product/src/Repositories/ProductRepository.php b/packages/Webkul/Product/src/Repositories/ProductRepository.php index 7854d170f..6c868c2fb 100755 --- a/packages/Webkul/Product/src/Repositories/ProductRepository.php +++ b/packages/Webkul/Product/src/Repositories/ProductRepository.php @@ -112,7 +112,7 @@ class ProductRepository extends Repository { $params = request()->input(); - $results = app('Webkul\Product\Repositories\ProductFlatRepository')->scopeQuery(function($query) use($params, $categoryId) { + $results = app(ProductFlatRepository::class)->scopeQuery(function($query) use($params, $categoryId) { $channel = request()->get('channel') ?: (core()->getCurrentChannelCode() ?: core()->getDefaultChannelCode()); $locale = request()->get('locale') ?: app()->getLocale(); @@ -212,7 +212,7 @@ class ProductRepository extends Repository */ public function findBySlugOrFail($slug, $columns = null) { - $product = app('Webkul\Product\Repositories\ProductFlatRepository')->findOneWhere([ + $product = app(ProductFlatRepository::class)->findOneWhere([ 'url_key' => $slug, 'locale' => app()->getLocale(), 'channel' => core()->getCurrentChannelCode(), @@ -236,7 +236,7 @@ class ProductRepository extends Repository */ public function findBySlug($slug) { - return app('Webkul\Product\Repositories\ProductFlatRepository')->findOneWhere([ + return app(ProductFlatRepository::class)->findOneWhere([ 'url_key' => $slug, 'locale' => app()->getLocale(), 'channel' => core()->getCurrentChannelCode(), @@ -250,7 +250,7 @@ class ProductRepository extends Repository */ public function getNewProducts() { - $results = app('Webkul\Product\Repositories\ProductFlatRepository')->scopeQuery(function($query) { + $results = app(ProductFlatRepository::class)->scopeQuery(function($query) { $channel = request()->get('channel') ?: (core()->getCurrentChannelCode() ?: core()->getDefaultChannelCode()); $locale = request()->get('locale') ?: app()->getLocale(); @@ -275,7 +275,7 @@ class ProductRepository extends Repository */ public function getFeaturedProducts() { - $results = app('Webkul\Product\Repositories\ProductFlatRepository')->scopeQuery(function($query) { + $results = app(ProductFlatRepository::class)->scopeQuery(function($query) { $channel = request()->get('channel') ?: (core()->getCurrentChannelCode() ?: core()->getDefaultChannelCode()); $locale = request()->get('locale') ?: app()->getLocale(); @@ -300,7 +300,7 @@ class ProductRepository extends Repository */ public function searchProductByAttribute($term) { - $results = app('Webkul\Product\Repositories\ProductFlatRepository')->scopeQuery(function($query) use($term) { + $results = app(ProductFlatRepository::class)->scopeQuery(function($query) use($term) { $channel = request()->get('channel') ?: (core()->getCurrentChannelCode() ?: core()->getDefaultChannelCode()); $locale = request()->get('locale') ?: app()->getLocale(); diff --git a/packages/Webkul/Product/src/Type/AbstractType.php b/packages/Webkul/Product/src/Type/AbstractType.php index 39568653d..d257ae928 100644 --- a/packages/Webkul/Product/src/Type/AbstractType.php +++ b/packages/Webkul/Product/src/Type/AbstractType.php @@ -167,7 +167,9 @@ abstract class AbstractType $product->update($data); foreach ($product->attribute_family->custom_attributes as $attribute) { - if ($attribute->type == 'boolean') { + $route = request()->route() ? request()->route()->getName() : ""; + + if ($attribute->type == 'boolean' && $route != 'admin.catalog.products.massupdate') { $data[$attribute->code] = isset($data[$attribute->code]) && $data[$attribute->code] ? 1 : 0; } @@ -175,7 +177,7 @@ abstract class AbstractType continue; } - if ($attribute->type == 'date' && $data[$attribute->code] == '') { + if ($attribute->type == 'date' && $data[$attribute->code] == '' && $route != 'admin.catalog.products.massupdate') { $data[$attribute->code] = null; } diff --git a/packages/Webkul/Shop/src/Http/Controllers/DownloadableProductController.php b/packages/Webkul/Shop/src/Http/Controllers/DownloadableProductController.php index 79c8d31b2..63813bf2f 100644 --- a/packages/Webkul/Shop/src/Http/Controllers/DownloadableProductController.php +++ b/packages/Webkul/Shop/src/Http/Controllers/DownloadableProductController.php @@ -47,7 +47,7 @@ class DownloadableProductController extends Controller /** * Display a listing of the resource. * - * @return \Illuminate\View\View + * @return \Illuminate\View\View */ public function index() { return view($this->_config['view']); @@ -77,7 +77,7 @@ class DownloadableProductController extends Controller } $remainingDownloads = $downloadableLinkPurchased->download_bought - ($downloadableLinkPurchased->download_used + 1); - + if ($downloadableLinkPurchased->download_bought) { $this->downloadableLinkPurchasedRepository->update([ 'download_used' => $downloadableLinkPurchased->download_used + 1, diff --git a/packages/Webkul/Shop/src/Http/Controllers/ReviewController.php b/packages/Webkul/Shop/src/Http/Controllers/ReviewController.php index b27b2a1b9..450271b1e 100755 --- a/packages/Webkul/Shop/src/Http/Controllers/ReviewController.php +++ b/packages/Webkul/Shop/src/Http/Controllers/ReviewController.php @@ -44,8 +44,7 @@ class ReviewController extends Controller public function __construct( ProductRepository $productRepository, ProductReviewRepository $productReviewRepository - ) - { + ) { $this->productRepository = $productRepository; $this->productReviewRepository = $productReviewRepository; @@ -57,15 +56,17 @@ class ReviewController extends Controller * Show the form for creating a new resource. * * @param string $slug - * @return \Illuminate\View\View + * @return \Illuminate\View\View */ public function create($slug) { - $product = $this->productRepository->findBySlugOrFail($slug); + if (auth()->guard('customer')->check() || core()->getConfigData('catalog.products.review.guest_review')) { + $product = $this->productRepository->findBySlugOrFail($slug); - $guest_review = core()->getConfigData('catalog.products.review.guest_review'); + return view($this->_config['view'], compact('product', 'guest_review')); + } - return view($this->_config['view'], compact('product', 'guest_review')); + abort(404); } /** @@ -103,7 +104,7 @@ class ReviewController extends Controller * Display reviews of particular product. * * @param string $slug - * @return \Illuminate\View\View + * @return \Illuminate\View\View */ public function show($slug) { diff --git a/packages/Webkul/Shop/src/Resources/assets/js/lang/locales.js b/packages/Webkul/Shop/src/Resources/assets/js/lang/locales.js index 3b0e3f538..d01d696c7 100644 --- a/packages/Webkul/Shop/src/Resources/assets/js/lang/locales.js +++ b/packages/Webkul/Shop/src/Resources/assets/js/lang/locales.js @@ -3,26 +3,26 @@ export const messages = { required : (field) => 'حقل' + field + ' مطلوب', alpha : (field) => field + ' يجب ان يحتوي على حروف فقط', alpha_num : (field) => field + ' قد يحتوي فقط على حروف وارقام', - min : (field) => 'الحقل ' + field + ' يجب ان يحتوي على {length} حروف على الأقل', + min : (field, length) => 'الحقل ' + field + ' يجب ان يحتوي على ' + length + ' حروف على الأقل', numeric : (field) => field + ' يمكن ان يحتوي فقط على ارقام', oneOf : (field) => 'الحقل ' + field + 'يجب ان يكون قيمة صحيحة', regex : (field) => 'الحقل' + field+ ' غير صحيح', required_if : (field) => 'حقل' + field + ' مطلوب', - size : (field) => field + ' يجب ان يكون اقل من {size} كيلوبايت', - min_value : (field) => 'قيمة الحقل' + field + ' يجب ان تكون اكبر من {min} او تساويها', + size : (field, size) => field + ' يجب ان يكون اقل من ' + size + ' كيلوبايت', + min_value : (field, min) => 'قيمة الحقل' + field + ' يجب ان تكون اكبر من ' + min + ' او تساويها', alpha_spaces : (field) => field + ' قد يحتوي فقط على حروف ومسافات', - between : (field) => 'قيمة ' +field+ ' يجب ان تكون ما بين {min} و {max}', + between : (field, min, max) => 'قيمة ' +field+ ' يجب ان تكون ما بين ' + min + ' و ' + max, confirmed : (field) => field + ' لا يماثل التأكيد', - digits : (field) => field + ' يجب ان تحتوي فقط على ارقام والا يزيد عددها عن {length} رقم', - dimensions : (field) => field + ' يجب ان تكون بمقاس {width} بكسل في {height} بكسل', + digits : (field, length) => field + ' يجب ان تحتوي فقط على ارقام والا يزيد عددها عن ' + length + ' رقم', + dimensions : (field, width, height) => field + ' يجب ان تكون بمقاس ' + width + ' بكسل في ' + height + ' بكسل', email : (field) => field + ' يجب ان يكون بريدا اليكتروني صحيح', excluded : (field) => 'الحقل' + field +'غير صحيح', ext : (field) =>'نوع مل'+ field + 'غير صحيح', image : (field) => field + ' يجب ان تكون صورة', integer : (field) => 'الحقل ' +field + ' يجب ان يكون عدداً صحيحاً', - length : (field) => 'حقل'+ field + ' يجب الا يزيد عن {length}', - max_value : (field) => 'قيمة الحقل '+ field + ' يجب ان تكون اصغر من {min} او تساويها', - max : (field) => 'الحقل' + field + 'يجب ان يحتوي على {length} حروف على الأكثر', + length : (field, length) => 'حقل'+ field + ' يجب الا يزيد عن ' + length, + max_value : (field, min) => 'قيمة الحقل '+ field + ' يجب ان تكون اصغر من ' + min + ' او تساويها', + max : (field, length) => 'الحقل' + field + 'يجب ان يحتوي على ' + length + ' حروف على الأكثر', mimes : (field) => 'نوع ملف' + field + 'غير صحيح' } } diff --git a/packages/Webkul/Shop/src/Resources/views/checkout/onepage.blade.php b/packages/Webkul/Shop/src/Resources/views/checkout/onepage.blade.php index 0433dbf2a..7956cc53f 100755 --- a/packages/Webkul/Shop/src/Resources/views/checkout/onepage.blade.php +++ b/packages/Webkul/Shop/src/Resources/views/checkout/onepage.blade.php @@ -300,6 +300,7 @@ this_this.current_step = this_this.step_numbers[response.data.jump_to_section]; shippingMethods = response.data.shippingMethods; + paymentMethods = response.data.paymentMethods; this_this.getOrderSummary(); }) diff --git a/packages/Webkul/Shop/src/Resources/views/customers/account/profile/index.blade.php b/packages/Webkul/Shop/src/Resources/views/customers/account/profile/index.blade.php index 8389fe924..02abd9341 100755 --- a/packages/Webkul/Shop/src/Resources/views/customers/account/profile/index.blade.php +++ b/packages/Webkul/Shop/src/Resources/views/customers/account/profile/index.blade.php @@ -30,6 +30,9 @@