From 1cc8e025a1e0f89e7fcccf04b81663f861a15048 Mon Sep 17 00:00:00 2001 From: Kevin Adametz Date: Fri, 26 Nov 2021 18:23:10 +0100 Subject: [PATCH] Promotion Frontend dynamic --- .../Controllers/User/PromotionController.php | 1 - .../Controllers/Web/PromotionController.php | 33 +++- app/Models/Product.php | 8 +- app/Models/PromotionAdmin.php | 13 ++ app/Models/Shipping.php | 4 + app/Models/ShippingCountry.php | 3 +- app/Models/ShippingPrice.php | 10 +- app/Services/PromotionCart.php | 105 ++++++++++++ app/Services/Yard.php | 71 +++++--- ...06_004849_create_shipping_prices_table.php | 1 + public/css/shop.css | 24 ++- public/js/iq-promotion-shop-cart.js | 153 ++++++++++++++++++ resources/views/admin/product/edit.blade.php | 3 + resources/views/admin/shipping/edit.blade.php | 25 ++- .../views/user/promotion/index.blade.php | 13 +- .../views/web/layouts/application.blade.php | 1 + .../layouts/includes/layout-footer.blade.php | 22 ++- .../layouts/includes/layout-header.blade.php | 50 +++--- .../views/web/promotion/_checkout.blade.php | 2 +- .../views/web/promotion/_fairplay.blade.php | 2 +- .../web/promotion/_free_product.blade.php | 18 ++- .../views/web/promotion/_intro.blade.php | 20 ++- .../web/promotion/_promotion_cart.blade.php | 50 +++--- .../web/promotion/_reminder_service.blade.php | 8 +- .../views/web/promotion/_shipping.blade.php | 10 +- .../web/promotion/_shop_products.blade.php | 40 +++-- .../web/promotion/_show_around.blade.php | 6 +- resources/views/web/promotion/index.blade.php | 15 +- .../web/promotion/show_product.blade.php | 3 - 29 files changed, 551 insertions(+), 163 deletions(-) create mode 100644 app/Services/PromotionCart.php create mode 100644 public/js/iq-promotion-shop-cart.js diff --git a/app/Http/Controllers/User/PromotionController.php b/app/Http/Controllers/User/PromotionController.php index 5f23467..76a07b9 100644 --- a/app/Http/Controllers/User/PromotionController.php +++ b/app/Http/Controllers/User/PromotionController.php @@ -91,7 +91,6 @@ class PromotionController extends Controller public function load(){ $data = Request::all(); - if(Request::ajax()) { if(isset($data['action']) && $data['action'] === 'validate_url'){ $rules = array( diff --git a/app/Http/Controllers/Web/PromotionController.php b/app/Http/Controllers/Web/PromotionController.php index 1a7da12..a82f589 100644 --- a/app/Http/Controllers/Web/PromotionController.php +++ b/app/Http/Controllers/Web/PromotionController.php @@ -9,6 +9,7 @@ use App\Services\Util; use App\Models\Product; use App\Models\PaymentMethod; use App\Models\PromotionUser; +use App\Services\PromotionCart; use App\Http\Controllers\Controller; @@ -31,16 +32,16 @@ class PromotionController extends Controller if(!$PromotionUser){ abort(402); } - if($PromotionUser->checkOutOfStock()){ + if(!$PromotionUser->promotion_admin->isActive() || $PromotionUser->checkOutOfStock()){ $data = [ 'promotion_user' => $PromotionUser, ]; return view('web.promotion.outofstock', $data); } - + PromotionCart::initYard(); $data = [ 'promotion_user' => $PromotionUser, - 'shop_products' => Product::where('active', true)->whereJsonContains('show_on', ['1', '2', '3'])->orderBy('pos', 'ASC')->get(), + 'shop_products' => Product::where('active', true)->whereJsonContains('show_on', ['3'])->orderBy('pos', 'ASC')->get(), 'user_payment_methods' => PaymentMethod::getDefaultAsArray()->toArray(), ]; return view('web.promotion.index', $data); @@ -93,6 +94,32 @@ class PromotionController extends Controller $product = Product::find($data['id']); //current user form order $ret = view("web.promotion.show_product", compact('product', 'data'))->render(); } + if($data['action'] === 'switch-free-product'){ + \App\Services\PromotionCart::updateFeeProduct($data); + $ret = view("web.promotion._promotion_cart", compact('data'))->render(); + } + if($data['action'] === 'add-shop-product'){ + $data['qty'] = \App\Services\PromotionCart::updateProduct($data, true); + $ret = view("web.promotion._promotion_cart", compact('data'))->render(); + } + if($data['action'] === 'update-shop-product'){ + $data['qty'] = \App\Services\PromotionCart::updateProduct($data); + $ret = view("web.promotion._promotion_cart", compact('data'))->render(); + } + if($data['action'] === 'remove-shop-product'){ + \App\Services\PromotionCart::updateProduct($data); + $data['qty'] = 0; + $ret = view("web.promotion._promotion_cart", compact('data'))->render(); + } + if($data['action'] === 'clear-cart'){ + \App\Services\PromotionCart::clearCart($data); + $ret = view("web.promotion._promotion_cart", compact('data'))->render(); + } + + if($data['action'] === 'switch-shipping'){ + $ret = view("web.promotion._promotion_cart", compact('data'))->render(); + } + return response()->json(['response' => $data, 'html'=>$ret, 'status'=>$status]); } } diff --git a/app/Models/Product.php b/app/Models/Product.php index 37620aa..1d3145e 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -296,7 +296,13 @@ class Product extends Model return $this->hasMany(ProductIngredient::class, 'product_ingredients', 'id'); } - + public function getShortCopy($clean = false, $len = false){ + $ret = $this->short_copy ? $this->short_copy : $this->description; + if($len && $clean){ + return substr_ellipsis($ret, $len, $clean); + } + return $ret; + } public function getActionName($id = 0){ if(isset($this->actions[$id])){ return $this->actions[$id]; diff --git a/app/Models/PromotionAdmin.php b/app/Models/PromotionAdmin.php index 2cf8f0f..794175d 100644 --- a/app/Models/PromotionAdmin.php +++ b/app/Models/PromotionAdmin.php @@ -125,6 +125,19 @@ class PromotionAdmin extends Model } } + public function isActive(){ + if($this->active){ + if($this->from && Carbon::parse($this->from)->gt(Carbon::now()->startOfDay())){ + return false; + } + if($this->to && Carbon::parse($this->to)->lt(Carbon::now()->startOfDay())){ + return false; + } + return true; + } + return false; + } + public function getFromAttribute($value) { if(!$value){ return ""; } diff --git a/app/Models/Shipping.php b/app/Models/Shipping.php index 7a3af40..61f711e 100644 --- a/app/Models/Shipping.php +++ b/app/Models/Shipping.php @@ -78,4 +78,8 @@ class Shipping extends Model public function shipping_prices(){ return $this->hasMany('App\Models\ShippingPrice', 'shipping_id', 'id'); } + + public function getShippingPricesBy($shipping_for){ + return $this->hasMany('App\Models\ShippingPrice', 'shipping_id', 'id')->where('shipping_for', $shipping_for); + } } diff --git a/app/Models/ShippingCountry.php b/app/Models/ShippingCountry.php index c7733a6..1facdf8 100644 --- a/app/Models/ShippingCountry.php +++ b/app/Models/ShippingCountry.php @@ -29,8 +29,7 @@ use Illuminate\Database\Eloquent\Model; class ShippingCountry extends Model { protected $table = 'shipping_countries'; - - + protected $fillable = [ 'shipping_id', 'country_id' ]; diff --git a/app/Models/ShippingPrice.php b/app/Models/ShippingPrice.php index 1e1cf5f..0926e84 100644 --- a/app/Models/ShippingPrice.php +++ b/app/Models/ShippingPrice.php @@ -47,7 +47,12 @@ class ShippingPrice extends Model protected $table = 'shipping_prices'; protected $fillable = [ - 'shipping_id', 'price', 'price_comp', 'num_comp', 'tax_rate', 'factor', 'total_from', 'total_to', 'weight_from', 'weight_to', + 'shipping_id', 'price', 'price_comp', 'num_comp', 'tax_rate', 'factor', 'total_from', 'total_to', 'weight_from', 'weight_to', 'shipping_for', + ]; + + public static $shippingForTypes = [ + 1 => 'Berater Bestellungen', + 2 => 'Shop Bestellungen', ]; public function shipping() @@ -55,6 +60,9 @@ class ShippingPrice extends Model return $this->belongsTo('App\Models\Shipping', 'shipping_id'); } + public function getShippingForType(){ + return isset(self::$shippingForTypes[$this->shipping_for]) ? self::$shippingForTypes[$this->shipping_for] : ""; + } public function setPriceAttribute($value) { diff --git a/app/Services/PromotionCart.php b/app/Services/PromotionCart.php new file mode 100644 index 0000000..9317543 --- /dev/null +++ b/app/Services/PromotionCart.php @@ -0,0 +1,105 @@ +first()){ + $id = $ShippingCountry->id; + } + Yard::instance('shopping')->setShippingCountryWithPrice($id, 'shop'); + } + + public static function getLowestShippingPrice($shipping_for = 2) + { + if($ShippingCountry = ShippingCountry::all()->first()){ + if($ShippingCountry->shipping){ + if($ShippingPrices = $ShippingCountry->shipping->getShippingPricesBy($shipping_for)->orderBy('price', 'ASC')->first()){ + return formatNumber($ShippingPrices->price); + } + } + } + } + + public static function clearCart($data, $add=false) + { + Yard::instance('shopping')->destroy(); + } + + public static function updateProduct($data, $add=false) + { + if($product = Product::find($data['product_id'])){ + $image = ""; + if($product->images->count()){ + $image = $product->images->first()->slug; + } + + //get the card item + $cartItem = Yard::instance('shopping')->add($product->id, $product->getLang('name'), 1, $product->price, $product->tax, + [ + 'image' => $image, + 'slug' => $product->slug, + 'weight' => $product->weight, + ]); + + Yard::setTax($cartItem->rowId, $product->tax); + if(!$add){ + if(isset($data['qty']) && $data['qty'] > 0){ + Yard::instance('shopping')->update($cartItem->rowId, $data['qty']); + }else{ + //if 0 get the item by qty:1 and remove it + Yard::instance('shopping')->remove($cartItem->rowId); + } + } + + Yard::instance('shopping')->reCalculate(); + return $cartItem->qty; + } + } + + public static function updateFeeProduct($data) + { + foreach (Yard::instance('shopping')->content() as $row) { + //wenn kleiner wurde ein produkt entfernt aufgrund der Anzahl + //wenn gleich löschen, da neue Versandkosten + + if($row->options->free_product) { + Yard::instance('shopping')->remove($row->rowId); + } + } + + if(isset($data['free_poduct_id'])) { + if ($product = Product::find($data['free_poduct_id'])) { + $image = ""; + if ($product->images->count()) { + $image = $product->images->first()->slug; + } + $cartItem = Yard::instance('shopping')->add($product->id, $product->getLang('name'), 1, 0, 0, + [ + 'image' => $image, + 'slug' => $product->slug, + 'weight' => 0, + 'free_product' => 1, + 'product_id' => $product->id + ]); + Yard::setTax($cartItem->rowId, 0); + } + } + } + + +} \ No newline at end of file diff --git a/app/Services/Yard.php b/app/Services/Yard.php index 39f4cb2..8524fe6 100644 --- a/app/Services/Yard.php +++ b/app/Services/Yard.php @@ -323,36 +323,46 @@ class Yard extends Cart return; } $shipping = $shippingCountry->shipping; + $shipping_price_for = 1; + if($this->shipping_is_for === 'me' || $this->shipping_is_for === 'ot'){ + $shipping_price_for = 1; + } + if($this->shipping_is_for === 'shop'){ + $shipping_price_for = 2; + } if($this->weight() == 0){ - $shipping_price = $shipping->shipping_prices->first(); + $shipping_price = $shipping->getShippingPricesBy($shipping_price_for)->first(); + if(!$shipping_price){ + $shipping_price = new \App\Models\ShippingPrice(); + } $shipping_price->price = 0; $shipping_price->price_comp = 0; }else{ //first by price - $shipping_price = $this->shippingPriceBySubTotal($shipping->shipping_prices, $this->subtotal(2, '.', '')); + $shipping_price = $this->shippingPriceBySubTotal($shipping->getShippingPricesBy($shipping_price_for), $this->subtotal(2, '.', '')); //sec by weight if(!$shipping_price){ - $shipping_price = $this->shippingPriceByWeight($shipping->shipping_prices, $this->weight()); + $shipping_price = $this->shippingPriceByWeight($shipping->getShippingPricesBy($shipping_price_for), $this->weight()); } //default if(!$shipping_price){ - $shipping_price = $shipping->shipping_prices->first(); + $shipping_price = $shipping->getShippingPricesBy($shipping_price_for)->first(); } } if($shipping_price){ $price = $shipping_price->price; $this->num_comp = 0; - - if($this->shipping_is_for === 'me' && \App\Models\Setting::getContentBySlug('order_partner_is_comp_me')){ - $price = $shipping_price->price_comp; - $this->num_comp = $shipping_price->num_comp; + if($this->weight() > 0){ + if($this->shipping_is_for === 'me' && \App\Models\Setting::getContentBySlug('order_partner_is_comp_me')){ + $price = $shipping_price->price_comp; + $this->num_comp = $shipping_price->num_comp; + } + if($this->shipping_is_for === 'ot' && \App\Models\Setting::getContentBySlug('order_partner_is_comp_ot')){ + $price = $shipping_price->price_comp; + $this->num_comp = $shipping_price->num_comp; + } } - if($this->shipping_is_for === 'ot' && \App\Models\Setting::getContentBySlug('order_partner_is_comp_ot')){ - $price = $shipping_price->price_comp; - $this->num_comp = $shipping_price->num_comp; - } - $this->shipping_price = $price; $this->shipping_tax_rate = $shipping_price->tax_rate; $this->shipping_price_net = round($price / ((100+$shipping_price->tax_rate) / 100), 2); @@ -584,7 +594,7 @@ class Yard extends Cart } - public function getCartItemByProduct($product_id, $set_price='with'){ + public function getCartItemByProduct($product_id, $set_price='with', $commission=true){ if($product = Product::find($product_id)) { $image = ""; if ($product->images->count()) { @@ -594,8 +604,8 @@ class Yard extends Cart if($set_price === 'with'){ $price = $product->getPriceWith(false, true); } - $cartItem = $this->getCartItem($product->id, $product->getLang('name'), 1, $price, - [ + if($commission){ + $options = [ 'image' => $image, 'slug' => $product->slug, 'weight' => $product->weight, @@ -603,8 +613,16 @@ class Yard extends Cart 'amount_commission' => $product->amount_commission, 'value_commission' => $product->value_commission, 'partner_commission' => $product->partner_commission, - ] - ); + ]; + }else{ + $options = [ + 'image' => $image, + 'slug' => $product->slug, + 'weight' => $product->weight, + ]; + } + + $cartItem = $this->getCartItem($product->id, $product->getLang('name'), 1, $price, $options); $content = $this->getContent(); if ($content->has($cartItem->rowId)){ @@ -635,11 +653,19 @@ class Yard extends Cart } + public function rowPrice(CartItem $row, $decimals = null, $decimalPoint = null, $thousandSeperator = null){ + return $this->numberFormat($row->price, $decimals, $decimalPoint, $thousandSeperator); + } + public function rowPriceNet(CartItem $row, $decimals = null, $decimalPoint = null, $thousandSeperator = null){ $price = round($row->price / ((100 + $row->taxRate) /100), 4); return $this->numberFormat($price, $decimals, $decimalPoint, $thousandSeperator); } + public function rowSubtotal(CartItem $row, $decimals = null, $decimalPoint = null, $thousandSeperator = null){ + return $this->numberFormat(($row->price * $row->qty), $decimals, $decimalPoint, $thousandSeperator); + } + public function rowSubtotalNet(CartItem $row, $decimals = null, $decimalPoint = null, $thousandSeperator = null){ $price = round($row->price / ((100 + $row->taxRate) /100), 4); return $this->numberFormat(($price * $row->qty), $decimals, $decimalPoint, $thousandSeperator); @@ -658,6 +684,15 @@ class Yard extends Cart return false; } + public function getFreeProductId(){ + foreach ($this->content() as $row) { + if($row->options->free_product) { + return $row->options->product_id; + } + } + return false; + } + public function getContentByOrder(){ $ret = []; $comp = []; diff --git a/database/migrations/2019_01_06_004849_create_shipping_prices_table.php b/database/migrations/2019_01_06_004849_create_shipping_prices_table.php index ccdb0f4..645b4a3 100644 --- a/database/migrations/2019_01_06_004849_create_shipping_prices_table.php +++ b/database/migrations/2019_01_06_004849_create_shipping_prices_table.php @@ -30,6 +30,7 @@ class CreateShippingPricesTable extends Migration $table->unsignedInteger('weight_from')->nullable(); $table->unsignedInteger('weight_to')->nullable(); + $table->unsignedTinyInteger('shipping_for')->default(1); $table->timestamps(); diff --git a/public/css/shop.css b/public/css/shop.css index ce8ea36..09992a1 100644 --- a/public/css/shop.css +++ b/public/css/shop.css @@ -122,6 +122,10 @@ h4.product-title { font-size: 1.2rem; font-weight: bold; color: rgb(64, 65, 66); + line-height: 1.5rem; +} +.product-item-price .small{ + font-size: 0.85rem; } .badge-cart { background: #659a87 !important; @@ -163,13 +167,31 @@ h4.product-title { text-align: center; } .swiper-button-next, .swiper-button-prev { + background-color: #fff; + height: 100%; + padding: 15px; + top:0; color: rgb(119, 111, 95); outline: 0; + opacity: 0.75; +} +@media (min-width: 992px) { + + .swiper-button-next, .swiper-button-prev { + padding: 25px; + } +} +.swiper-button-next, .swiper-rtl .swiper-button-prev{ + right: 0; +} +.swiper-button-prev, .swiper-rtl .swiper-button-next { + left: 0; } .swiper-button-next:hover, .swiper-button-prev:hover { color: rgb(58, 61, 70); + opacity: 0.9; } -.swiper-pagination-bullet { +.pagination-bullet { outline: 0; } .swiper-pagination-bullet:hover { diff --git a/public/js/iq-promotion-shop-cart.js b/public/js/iq-promotion-shop-cart.js new file mode 100644 index 0000000..50da8e5 --- /dev/null +++ b/public/js/iq-promotion-shop-cart.js @@ -0,0 +1,153 @@ + +function _log(msg){ + console.log(msg); +} + +var IqPromotionShopCart = { + btn_add_free: '.btn-add-free-product', + input_free: '.switcher-input', + btn_shop_add: '.btn-add-product-shop', + //btn_add: '.add-product-shop', + btn_remove: '.remove-product-shop', + //input_event: '.input-event-promotion-onchange', + btn_clear: '#clear-products-basket', + cart_input: '.cart-input-event-onchange', + remove_item: '.remove_item_form_cart', + + url: null, + action: null, + cart_holder: '#promotion_cart_holder', + + free_poduct_id: null, + shipping_option: null, + + + init: function () { + var _self = this; + _self.url = $('input[name=load_url]').val(); + _self.initElements(); + return _self; + }, + initElements: function (){ + var _self = this; + //_log('init'); + $(_self.btn_add_free).on('click', function(event) { + event.preventDefault(); + $(this).find(_self.input_free).prop('checked', true); + _self.switchFreeProduct($(this).find(_self.input_free)); + }); + $(_self.btn_shop_add).on('click', function(event){ + event.preventDefault(); + _self.addShopProduct($(this)); + }); + + $('input[name=switchers_shipping]').on('change', function(event){ + event.preventDefault(); + _self.switchShipping($(this)); + }); + _self.showInit(); + + + /*$_self.update_poduct_price();*/ + + }, + showInit: function (){ + var _self = this; + $(_self.btn_clear).on('click', function (event){ + event.preventDefault(); + _self.performRequest({action: 'clear-cart'}) + .done(_self.refreshItemsAndView) + }); + $(_self.cart_input).on('change', function(event){ + event.preventDefault(); + _self.updateInputCart($(this)); + }); + $(_self.remove_item).on('click', function(event){ + event.preventDefault(); + _self.performRequest({product_id: $(this).data('product-id'), qty: 0, action: 'remove-shop-product'}) + .done(_self.refreshItemsAndView); + }); + }, + switchShipping: function(_ele){ + var _self = this; + _self.shipping_option = _ele.val(); + _self.performRequest({shipping_option: _self.shipping_option, action: 'switch-shipping'}) + .done(_self.refreshItemsAndView); + }, + switchFreeProduct: function(_ele){ + var _self = this; + if(_ele.prop('checked')){ + if(_self.free_poduct_id != _ele.val()){ + _self.free_poduct_id = _ele.val(); + _self.performRequest({free_poduct_id: _self.free_poduct_id, action: 'switch-free-product'}) + .done(_self.refreshItemsAndView); + } + } + }, + addShopProduct: function(_ele){ + var _self = this; + if(_ele.data('product_id')){ + _self.performRequest({product_id: _ele.data('product_id'), action: 'add-shop-product'}) + .done(_self.refreshItemsAndView); + } + }, + + updateInputCart: function (_ele){ + var _self = this; + var qty = parseInt(_ele.val()); + qty = _self.checkNumber(qty); + _ele.val(qty); + _self.performRequest({product_id: _ele.data('product_id'), qty: qty, action: 'update-shop-product'}) + .done(_self.refreshItemsAndView); + }, + checkNumber : function(number){ + if(number < 0 || isNaN(number)){ + return 0; + } + if(number >= 100){ + return 100; + } + return number; + }, + refreshItemsAndView: function (data){ + var _self = IqPromotionShopCart; + //_log(data); + if(data.response.action == 'clear-cart'){ + location.reload(); + } + if(data.response.action == 'add-shop-product' || data.response.action == 'update-shop-product' || data.response.action == 'remove-shop-product'){ + var qty = data.response.qty > 0 ? "x"+data.response.qty : 0; + $('#badge_cart_indicator_'+data.response.product_id).html(qty); + } + $(_self.cart_holder).html(data.html); + _self.showInit(); + }, + performRequest : function(data) { + var _self = this; + var url = _self.url; + _log(data); + // _log(url); + return $.ajax({ + url: url, + data: data, + type: "POST", + dataType: "json", + cache: false, + contentType: 'application/x-www-form-urlencoded; charset=UTF-8', + encode: true, + headers: { + 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') + } + }) + .done(function (data) { + _log('performRequest'); + _log(data); + }).fail(function (jqXHR, textStatus, errorThrown) { + console.log(jqXHR); + console.log(jqXHR.responseText); + console.log(textStatus); + console.log(errorThrown); + console.log("Sorry, there was a problem!"); + }); + } +}; \ No newline at end of file diff --git a/resources/views/admin/product/edit.blade.php b/resources/views/admin/product/edit.blade.php index 0edf257..e5f1803 100755 --- a/resources/views/admin/product/edit.blade.php +++ b/resources/views/admin/product/edit.blade.php @@ -37,4 +37,7 @@ {!! Form::close() !!} + @include('admin.product.images') + + @endsection diff --git a/resources/views/admin/shipping/edit.blade.php b/resources/views/admin/shipping/edit.blade.php index c6232ac..f7ec1f8 100755 --- a/resources/views/admin/shipping/edit.blade.php +++ b/resources/views/admin/shipping/edit.blade.php @@ -74,6 +74,7 @@ {{__('Tax')}} {{__('Preis von - bis')}} {{__('Gewicht von - bis')}} + {{__('Preis für') }} @@ -92,7 +93,8 @@ data-total_from="{{ $price->getFormatTotalFrom() }}" data-total_to="{{ $price->getFormattedTotalTo() }}" data-weight_from="{{ $price->weight_from }}" - data-weight_to="{{ $price->weight_to }}"> + data-weight_to="{{ $price->weight_to }}" + data-shipping_for="{{ $price->shipping_for }}"> @@ -102,6 +104,7 @@ {{ $price->getFormattedTaxRate() }} {{ $price->getFormatTotalFrom() }} - {{ $price->getFormattedTotalTo() }} {{ $price->weight_from }} - {{ $price->weight_to }} + {{ $price->getShippingForType() }} @@ -120,6 +123,7 @@ data-total_to="" data-weight_from="" data-weight_to="" + data-shipping_for="1" >{{__('Neuen Preis erstellen')}} @@ -147,8 +151,8 @@
- - + +
@@ -157,8 +161,8 @@
- - + +
@@ -183,6 +187,16 @@ +
+
+ + +
+