feat: Implement upsell functionality with repository and service layers
This commit is contained in:
149
app/Services/UpsellService.php
Normal file
149
app/Services/UpsellService.php
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
namespace Sodino\Services;
|
||||
|
||||
use Sodino\Repositories\UpsellRepository;
|
||||
|
||||
class UpsellService {
|
||||
private $upsellRepository;
|
||||
private $cache = null;
|
||||
|
||||
public function __construct(UpsellRepository $upsellRepository) {
|
||||
$this->upsellRepository = $upsellRepository;
|
||||
}
|
||||
|
||||
public function getActiveUpsells() {
|
||||
if ($this->cache === null) {
|
||||
$this->cache = $this->upsellRepository->getActive();
|
||||
}
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
public function getMatchingUpsells($cart) {
|
||||
if (!$cart || $cart->is_empty()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$matches = [];
|
||||
foreach ($this->getActiveUpsells() as $upsell) {
|
||||
if ($this->cartMatchesTrigger($upsell, $cart) && !$this->isProductAlreadyInCart($cart, $upsell->target_product_id)) {
|
||||
$matches[] = $upsell;
|
||||
}
|
||||
}
|
||||
|
||||
usort($matches, function ($a, $b) {
|
||||
return $b->priority <=> $a->priority;
|
||||
});
|
||||
|
||||
return $matches;
|
||||
}
|
||||
|
||||
public function applyUpsellDiscount($product, $upsell) {
|
||||
if (!$product || !$upsell) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$price = floatval($product->get_price());
|
||||
if ($upsell->discount_type === 'percentage') {
|
||||
return max(0, $price * (1 - floatval($upsell->discount_value) / 100));
|
||||
}
|
||||
|
||||
if ($upsell->discount_type === 'fixed') {
|
||||
return max(0, $price - floatval($upsell->discount_value));
|
||||
}
|
||||
|
||||
return $price;
|
||||
}
|
||||
|
||||
public function getTriggerLabel($upsell) {
|
||||
switch ($upsell->trigger_type) {
|
||||
case 'product':
|
||||
return __('محصول خاص', 'sodino');
|
||||
case 'category':
|
||||
return __('دستهبندی', 'sodino');
|
||||
case 'cart_total':
|
||||
return __('مبلغ سبد خرید', 'sodino');
|
||||
default:
|
||||
return __('نامشخص', 'sodino');
|
||||
}
|
||||
}
|
||||
|
||||
public function getDiscountLabel($upsell) {
|
||||
if ($upsell->discount_type === 'fixed') {
|
||||
return sprintf('%s تومان', number_format_i18n($upsell->discount_value));
|
||||
}
|
||||
|
||||
if ($upsell->discount_type === 'percentage') {
|
||||
return sprintf('%s %%', esc_html($upsell->discount_value));
|
||||
}
|
||||
|
||||
return __('بدون تخفیف', 'sodino');
|
||||
}
|
||||
|
||||
private function cartMatchesTrigger($upsell, $cart) {
|
||||
if (!$upsell->isActive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$triggerType = $upsell->trigger_type;
|
||||
$triggerValue = $upsell->trigger_value;
|
||||
|
||||
switch ($triggerType) {
|
||||
case 'product':
|
||||
return $this->cartContainsProduct($cart, intval($triggerValue));
|
||||
case 'category':
|
||||
return $this->cartContainsCategory($cart, intval($triggerValue));
|
||||
case 'cart_total':
|
||||
return floatval($cart->get_cart_contents_total()) >= floatval($triggerValue);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function cartContainsProduct($cart, $productId) {
|
||||
if (!$productId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($cart->get_cart() as $cartItem) {
|
||||
if ((int) $cartItem['product_id'] === $productId || (int) $cartItem['variation_id'] === $productId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function cartContainsCategory($cart, $categoryId) {
|
||||
if (!$categoryId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($cart->get_cart() as $cartItem) {
|
||||
$product = wc_get_product($cartItem['product_id']);
|
||||
if (!$product) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$terms = wp_get_post_terms($product->get_id(), 'product_cat', ['fields' => 'ids']);
|
||||
if (is_array($terms) && in_array($categoryId, $terms, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isProductAlreadyInCart($cart, $productId) {
|
||||
if (!$productId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($cart->get_cart() as $cartItem) {
|
||||
if ((int) $cartItem['product_id'] === $productId || (int) $cartItem['variation_id'] === $productId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user