diff --git a/packages/Webkul/Admin/src/Resources/lang/en/app.php b/packages/Webkul/Admin/src/Resources/lang/en/app.php index b13b2ec4e..130303f57 100755 --- a/packages/Webkul/Admin/src/Resources/lang/en/app.php +++ b/packages/Webkul/Admin/src/Resources/lang/en/app.php @@ -527,7 +527,12 @@ return [ 'checkbox' => 'Checkbox', 'multiselect' => 'Multiselect', 'new-option' => 'New Option', - 'is-default' => 'Is Default' + 'is-default' => 'Is Default', + 'customer-group' => 'Customer Group', + 'add-group-price' => 'Add Customer Group Price', + 'all-group' => 'All Groups', + 'fixed' => 'Fixed', + 'discount' => 'Discount', ], 'attributes' => [ diff --git a/packages/Webkul/Admin/src/Resources/views/catalog/products/accordians/customer-group-price.blade.php b/packages/Webkul/Admin/src/Resources/views/catalog/products/accordians/customer-group-price.blade.php new file mode 100644 index 000000000..a8295f37d --- /dev/null +++ b/packages/Webkul/Admin/src/Resources/views/catalog/products/accordians/customer-group-price.blade.php @@ -0,0 +1,162 @@ +@section('css') + @parent + +@stop + +{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.customer_group_prices.before', ['product' => $product]) !!} + + + +{!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.customer_group_prices.after', ['product' => $product]) !!} + +@push('scripts') + @parent + + + + + + +@endpush \ No newline at end of file diff --git a/packages/Webkul/Admin/src/Resources/views/catalog/products/edit.blade.php b/packages/Webkul/Admin/src/Resources/views/catalog/products/edit.blade.php index c1cfcf2e1..ec4ca4e69 100755 --- a/packages/Webkul/Admin/src/Resources/views/catalog/products/edit.blade.php +++ b/packages/Webkul/Admin/src/Resources/views/catalog/products/edit.blade.php @@ -144,6 +144,12 @@ @endforeach + @if ($attributeGroup->name == 'Price') + + @include ('admin::catalog.products.accordians.customer-group-price') + + @endif + {!! view_render_event('bagisto.admin.catalog.product.edit_form_accordian.' . $attributeGroup->name . '.controls.after', ['product' => $product]) !!} diff --git a/packages/Webkul/BookingProduct/src/Helpers/Booking.php b/packages/Webkul/BookingProduct/src/Helpers/Booking.php index ebdcf73d5..0e944cc6b 100644 --- a/packages/Webkul/BookingProduct/src/Helpers/Booking.php +++ b/packages/Webkul/BookingProduct/src/Helpers/Booking.php @@ -531,7 +531,7 @@ class Booking */ public function validateCartItem($item) { - $price = $item->product->getTypeInstance()->getFinalPrice(); + $price = $item->product->getTypeInstance()->getFinalPrice($item->quantity); if ($price == $item->base_price) { return; diff --git a/packages/Webkul/BookingProduct/src/Helpers/EventTicket.php b/packages/Webkul/BookingProduct/src/Helpers/EventTicket.php index 3302f26b4..d7bda887e 100644 --- a/packages/Webkul/BookingProduct/src/Helpers/EventTicket.php +++ b/packages/Webkul/BookingProduct/src/Helpers/EventTicket.php @@ -119,7 +119,7 @@ class EventTicket extends Booking */ public function validateCartItem($item) { - $price = $item->product->getTypeInstance()->getFinalPrice(); + $price = $item->product->getTypeInstance()->getFinalPrice($item->quantity); $bookingProduct = $this->bookingProductRepository->findOneByField('product_id', $item->product_id); diff --git a/packages/Webkul/BookingProduct/src/Helpers/RentalSlot.php b/packages/Webkul/BookingProduct/src/Helpers/RentalSlot.php index 2ca56dfa7..71d1a937e 100644 --- a/packages/Webkul/BookingProduct/src/Helpers/RentalSlot.php +++ b/packages/Webkul/BookingProduct/src/Helpers/RentalSlot.php @@ -224,7 +224,7 @@ class RentalSlot extends Booking */ public function validateCartItem($item) { - $price = $item->product->getTypeInstance()->getFinalPrice(); + $price = $item->product->getTypeInstance()->getFinalPrice($item->quantity); $bookingProduct = $this->bookingProductRepository->findOneByField('product_id', $item->product_id); diff --git a/packages/Webkul/CartRule/src/Helpers/CartRule.php b/packages/Webkul/CartRule/src/Helpers/CartRule.php index b10d2721b..ba76ef565 100644 --- a/packages/Webkul/CartRule/src/Helpers/CartRule.php +++ b/packages/Webkul/CartRule/src/Helpers/CartRule.php @@ -140,9 +140,11 @@ class CartRule public static $cartRules; public static $cartID; }; + if ($staticCartRules::$cartID === cart()->getCart()->id && $staticCartRules::$cartRules) { return $staticCartRules::$cartRules; } + $staticCartRules::$cartID = cart()->getCart()->id; $customerGroupId = null; diff --git a/packages/Webkul/Product/src/Contracts/ProductCustomerGroupPrice.php b/packages/Webkul/Product/src/Contracts/ProductCustomerGroupPrice.php new file mode 100644 index 000000000..d930da4fe --- /dev/null +++ b/packages/Webkul/Product/src/Contracts/ProductCustomerGroupPrice.php @@ -0,0 +1,7 @@ +bigIncrements('id'); + $table->integer('qty')->default(0); + $table->string('value_type'); + $table->decimal('value', 12, 4)->default(0); + + $table->integer('product_id')->unsigned(); + $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade'); + + $table->integer('customer_group_id')->nullble()->unsigned(); + $table->foreign('customer_group_id')->references('id')->on('customer_groups')->onDelete('cascade'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('product_customer_group_prices'); + } +} diff --git a/packages/Webkul/Product/src/Models/Product.php b/packages/Webkul/Product/src/Models/Product.php index 8253a79f8..4ba4b12c6 100755 --- a/packages/Webkul/Product/src/Models/Product.php +++ b/packages/Webkul/Product/src/Models/Product.php @@ -178,6 +178,14 @@ class Product extends Model implements ProductContract return $this->hasMany(ProductBundleOptionProxy::modelClass()); } + /** + * Get the product customer group prices that owns the product. + */ + public function customer_group_prices() + { + return $this->hasMany(ProductCustomerGroupPriceProxy::modelClass()); + } + /** * @param integer $qty * diff --git a/packages/Webkul/Product/src/Models/ProductCustomerGroupPrice.php b/packages/Webkul/Product/src/Models/ProductCustomerGroupPrice.php new file mode 100644 index 000000000..b71d2b7d2 --- /dev/null +++ b/packages/Webkul/Product/src/Models/ProductCustomerGroupPrice.php @@ -0,0 +1,35 @@ +belongsTo(ProductProxy::modelClass()); + } + + /** + * Get the product that owns the customer group price. + */ + public function customer_group() + { + return $this->belongsTo(CustomerGroupProxy::modelClass()); + } +} \ No newline at end of file diff --git a/packages/Webkul/Product/src/Models/ProductCustomerGroupPriceProxy.php b/packages/Webkul/Product/src/Models/ProductCustomerGroupPriceProxy.php new file mode 100644 index 000000000..68d9ce166 --- /dev/null +++ b/packages/Webkul/Product/src/Models/ProductCustomerGroupPriceProxy.php @@ -0,0 +1,10 @@ +customer_group_prices()->pluck('id'); + + if (isset($data['customer_group_prices'])) { + foreach ($data['customer_group_prices'] as $customerGroupPriceId => $row) { + $row['customer_group_id'] = $row['customer_group_id'] == '' ? null : $row['customer_group_id']; + + if (Str::contains($customerGroupPriceId, 'customer_group_price_')) { + $this->create(array_merge([ + 'product_id' => $product->id, + ], $row)); + } else { + if (is_numeric($index = $previousCustomerGroupPriceIds->search($customerGroupPriceId))) { + $previousCustomerGroupPriceIds->forget($index); + } + + $this->update($row, $customerGroupPriceId); + } + } + } + + foreach ($previousCustomerGroupPriceIds as $customerGroupPriceId) { + $this->delete($customerGroupPriceId); + } + } +} \ No newline at end of file diff --git a/packages/Webkul/Product/src/Type/AbstractType.php b/packages/Webkul/Product/src/Type/AbstractType.php index 859652958..6707df257 100644 --- a/packages/Webkul/Product/src/Type/AbstractType.php +++ b/packages/Webkul/Product/src/Type/AbstractType.php @@ -11,7 +11,7 @@ use Webkul\Product\Repositories\ProductInventoryRepository; use Webkul\Product\Repositories\ProductImageRepository; use Webkul\Product\Models\ProductAttributeValue; use Webkul\Product\Helpers\ProductImage; -use Cart; +use Webkul\Checkout\Facades\Cart; abstract class AbstractType { @@ -246,6 +246,8 @@ abstract class AbstractType $this->productInventoryRepository->saveInventories($data, $product); $this->productImageRepository->uploadImages($data, $product); + + app('Webkul\Product\Repositories\ProductCustomerGroupPriceRepository')->saveCustomerGroupPrices($data, $product); } return $product; @@ -449,11 +451,12 @@ abstract class AbstractType /** * Get product minimal price * + * @param int $qty * @return float */ - public function getMinimalPrice() + public function getMinimalPrice($qty = null) { - if ($this->haveSpecialPrice()) { + if ($this->haveSpecialPrice($qty)) { return $this->product->special_price; } @@ -473,57 +476,148 @@ abstract class AbstractType /** * Get product minimal price * + * @param int $qty * @return float */ - public function getFinalPrice() + public function getFinalPrice($qty = null) { - return $this->getMinimalPrice(); + return $this->getMinimalPrice($qty); } /** * Returns the product's minimal price * + * @param int $qty * @return float */ - public function getSpecialPrice() + public function getSpecialPrice($qty = null) { - return $this->haveSpecialPrice() ? $this->product->special_price : $this->product->price; + return $this->haveSpecialPrice($qty) ? $this->product->special_price : $this->product->price; } /** + * @param int $qty * @return bool */ - public function haveSpecialPrice() + public function haveSpecialPrice($qty = null) { + $customerGroupPrice = $this->getCustomerGroupPrice($this->product, $qty); + $rulePrice = app('Webkul\CatalogRule\Helpers\CatalogRuleProductPrice')->getRulePrice($this->product); - if ((is_null($this->product->special_price) || ! (float) $this->product->special_price) && ! $rulePrice) { + if ((is_null($this->product->special_price) || ! (float) $this->product->special_price) + && ! $rulePrice + && $customerGroupPrice == $this->product->price + ) { return false; } + $haveSpecialPrice = false; + if (! (float) $this->product->special_price) { if ($rulePrice && $rulePrice->price < $this->product->price) { $this->product->special_price = $rulePrice->price; - return true; + $haveSpecialPrice = true; } } else { if ($rulePrice && $rulePrice->price <= $this->product->special_price) { $this->product->special_price = $rulePrice->price; - return true; + $haveSpecialPrice = true; } else { if (core()->isChannelDateInInterval($this->product->special_price_from, $this->product->special_price_to)) { - return true; + $haveSpecialPrice = true; } elseif ($rulePrice) { $this->product->special_price = $rulePrice->price; - return true; + $haveSpecialPrice = true; } } } - return false; + if ($haveSpecialPrice) { + $this->product->special_price = min($this->product->special_price, $customerGroupPrice); + } else { + $this->product->special_price = $customerGroupPrice; + } + + return true; + } + + /** + * Get product group price + * + * @return float + */ + public function getCustomerGroupPrice($product, $qty) + { + if (is_null($qty)) { + $qty = 1; + } + + $customerGroupId = null; + + if (Cart::getCurrentCustomer()->check()) { + $customerGroupId = Cart::getCurrentCustomer()->user()->customer_group_id; + } else { + $customerGroupRepository = app('Webkul\Customer\Repositories\CustomerGroupRepository'); + + if ($customerGuestGroup = $customerGroupRepository->findOneByField('code', 'guest')) { + $customerGroupId = $customerGuestGroup->id; + } + } + + $customerGroupPrices = $product->customer_group_prices()->where(function ($query) use ($customerGroupId) { + $query->where('customer_group_id', $customerGroupId) + ->orWhereNull('customer_group_id'); + } + )->get(); + + if (! $customerGroupPrices->count()) { + return $product->price; + } + + $lastQty = 1; + + $lastPrice = $product->price; + + $lastCustomerGroupId = null; + + foreach ($customerGroupPrices as $price) { + if ($price->customer_group_id != $customerGroupId && $price->customer_group_id) { + continue; + } + + if ($qty < $price->qty) { + continue; + } + + if ($price->qty < $lastQty) { + continue; + } + + if ($price->qty == $lastQty + && $lastCustomerGroupId != null + && $price->customer_group_id == null + ) { + continue; + } + + if ($price->value < $lastPrice) { + if ($price->value_type == 'percentage') { + $lastPrice = $product->price * ($price->value / 100); + } else { + $lastPrice = $price->value; + } + + $lastQty = $price->qty; + + $lastCustomerGroupId = $price->customer_group_id; + } + } + + return $lastPrice; } /** @@ -685,7 +779,7 @@ abstract class AbstractType */ public function validateCartItem($item) { - $price = $item->product->getTypeInstance()->getFinalPrice(); + $price = $item->product->getTypeInstance()->getFinalPrice($item->quantity); if ($price == $item->base_price) { return; diff --git a/packages/Webkul/Product/src/Type/Configurable.php b/packages/Webkul/Product/src/Type/Configurable.php index 5301b0837..f3689ee7c 100644 --- a/packages/Webkul/Product/src/Type/Configurable.php +++ b/packages/Webkul/Product/src/Type/Configurable.php @@ -542,7 +542,7 @@ class Configurable extends AbstractType */ public function validateCartItem($item) { - $price = $item->child->product->getTypeInstance()->getFinalPrice(); + $price = $item->child->product->getTypeInstance()->getFinalPrice($item->quantity); if ($price == $item->base_price) { return; diff --git a/packages/Webkul/Product/src/Type/Downloadable.php b/packages/Webkul/Product/src/Type/Downloadable.php index 1220e091c..f4487c151 100644 --- a/packages/Webkul/Product/src/Type/Downloadable.php +++ b/packages/Webkul/Product/src/Type/Downloadable.php @@ -235,7 +235,7 @@ class Downloadable extends AbstractType */ public function validateCartItem($item) { - $price = $item->product->getTypeInstance()->getFinalPrice(); + $price = $item->product->getTypeInstance()->getFinalPrice($item->quantity); foreach ($item->product->downloadable_links as $link) { if (! in_array($link->id, $item->additional['links'])) {