refactor(Core): refactor and optimize code
This commit is contained in:
@@ -3,20 +3,24 @@ namespace Sodino\Services;
|
||||
|
||||
use Sodino\Repositories\RuleRepository;
|
||||
use Sodino\Services\TrackingService;
|
||||
use Sodino\Core\Settings;
|
||||
use Sodino\Core\Cache;
|
||||
|
||||
class PricingService {
|
||||
private $ruleRepository;
|
||||
private $trackingService;
|
||||
private $rulesCache = null;
|
||||
private $settings;
|
||||
private $cache;
|
||||
|
||||
public function __construct(RuleRepository $ruleRepository, TrackingService $trackingService) {
|
||||
$this->ruleRepository = $ruleRepository;
|
||||
$this->trackingService = $trackingService;
|
||||
$this->settings = Settings::getInstance();
|
||||
$this->cache = Cache::getInstance();
|
||||
}
|
||||
|
||||
public function applyDynamicPricing($price, $product) {
|
||||
$settings = $this->getSettings();
|
||||
if (empty($settings['plugin_enabled']) || empty($settings['pricing_enabled'])) {
|
||||
if (!$this->settings->isPricingEnabled()) {
|
||||
return $price;
|
||||
}
|
||||
|
||||
@@ -25,43 +29,58 @@ class PricingService {
|
||||
}
|
||||
|
||||
$price = $this->normalizePrice($price);
|
||||
if (!$settings['cart_pricing_enabled'] && is_cart()) {
|
||||
|
||||
if (!$this->settings->get('cart_pricing_enabled') && is_cart()) {
|
||||
return $price;
|
||||
}
|
||||
|
||||
$originalPrice = $price;
|
||||
$rules = $this->getEnabledRules();
|
||||
$matchedRules = [];
|
||||
$rules = $this->getApplicableRules($product);
|
||||
|
||||
foreach ($rules as $rule) {
|
||||
if ($this->ruleMatches($rule, $product)) {
|
||||
$matchedRules[] = $rule;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($matchedRules)) {
|
||||
if (empty($rules)) {
|
||||
return $price;
|
||||
}
|
||||
|
||||
if (!$settings['allow_multiple_rules']) {
|
||||
$chosenRule = $this->chooseRule($matchedRules, $price, $settings['strategy']);
|
||||
$matchedRules = $chosenRule ? [$chosenRule] : [];
|
||||
if (!$this->settings->get('allow_multiple_rules')) {
|
||||
$chosenRule = $this->chooseRule($rules, $price);
|
||||
$rules = $chosenRule ? [$chosenRule] : [];
|
||||
}
|
||||
|
||||
foreach ($matchedRules as $rule) {
|
||||
foreach ($rules as $rule) {
|
||||
$oldPrice = $price;
|
||||
$price = $this->applyActions($rule, $price);
|
||||
$price = $this->applyRuleActions($rule, $price);
|
||||
|
||||
if ($price < $oldPrice) {
|
||||
$this->trackingService->recordDiscountApplied($product, $oldPrice, $price, $rule->id);
|
||||
$this->ruleRepository->incrementUsage($rule->id);
|
||||
}
|
||||
}
|
||||
|
||||
$price = $this->enforceLimits($originalPrice, $price, $settings);
|
||||
$price = $this->enforceLimits($originalPrice, $price);
|
||||
|
||||
return max(0, $price);
|
||||
}
|
||||
|
||||
private function chooseRule(array $rules, $price, $strategy) {
|
||||
private function getApplicableRules($product) {
|
||||
$cache_key = 'applicable_rules_' . ($product ? $product->get_id() : 'all');
|
||||
|
||||
return $this->cache->remember($cache_key, function() use ($product) {
|
||||
$rules = $this->ruleRepository->getEnabled();
|
||||
$applicable = [];
|
||||
|
||||
foreach ($rules as $rule) {
|
||||
if ($this->ruleMatches($rule, $product)) {
|
||||
$applicable[] = $rule;
|
||||
}
|
||||
}
|
||||
|
||||
return $applicable;
|
||||
}, 300, 'pricing');
|
||||
}
|
||||
|
||||
private function chooseRule(array $rules, $price) {
|
||||
$strategy = $this->settings->get('strategy', 'priority');
|
||||
|
||||
if ($strategy === 'highest_discount') {
|
||||
usort($rules, function ($a, $b) use ($price) {
|
||||
return $this->estimateRuleDiscount($b, $price) <=> $this->estimateRuleDiscount($a, $price);
|
||||
@@ -79,44 +98,19 @@ class PricingService {
|
||||
return $rules[0] ?? null;
|
||||
}
|
||||
|
||||
private function getSettings() {
|
||||
$defaults = [
|
||||
'plugin_enabled' => 1,
|
||||
'pricing_enabled' => 1,
|
||||
'upsell_enabled' => 1,
|
||||
'allow_multiple_rules' => 0,
|
||||
'strategy' => 'priority',
|
||||
'max_discount_percent' => 100,
|
||||
'min_product_price' => 0,
|
||||
'ab_testing_enabled' => 0,
|
||||
'cart_pricing_enabled' => 1,
|
||||
'scheduled_campaigns_enabled' => 1,
|
||||
];
|
||||
|
||||
return wp_parse_args(get_option('sodino_settings', []), $defaults);
|
||||
}
|
||||
|
||||
private function getEnabledRules() {
|
||||
if ($this->rulesCache === null) {
|
||||
$this->rulesCache = $this->ruleRepository->getEnabled();
|
||||
}
|
||||
return $this->rulesCache;
|
||||
}
|
||||
|
||||
private function normalizePrice($price) {
|
||||
if ($price === '' || $price === null) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return floatval($price);
|
||||
}
|
||||
|
||||
private function ruleMatches($rule, $product = null) {
|
||||
if (!$rule->enabled) {
|
||||
if (!$rule->isActive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($rule->usage_limit > 0 && $this->trackingService->getRuleUsageCount($rule->id) >= $rule->usage_limit) {
|
||||
if ($rule->hasReachedLimit()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -126,10 +120,6 @@ class PricingService {
|
||||
}
|
||||
}
|
||||
|
||||
if (!$this->isRuleActive($rule)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($rule->conditions)) {
|
||||
return true;
|
||||
}
|
||||
@@ -143,20 +133,6 @@ class PricingService {
|
||||
return true;
|
||||
}
|
||||
|
||||
private function isRuleActive($rule) {
|
||||
$now = current_time('Y-m-d H:i:s');
|
||||
|
||||
if (!empty($rule->start_date) && $now < $rule->start_date) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($rule->end_date) && $now > $rule->end_date) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function evaluateCondition($condition, $product = null) {
|
||||
$type = $condition['type'] ?? '';
|
||||
$value = $condition['value'] ?? null;
|
||||
@@ -203,24 +179,21 @@ class PricingService {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getCartTotal() {
|
||||
if (!WC()->cart) {
|
||||
if (!function_exists('WC') || !WC()->cart) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return floatval(WC()->cart->get_cart_contents_total());
|
||||
return floatval(WC()->cart->get_subtotal());
|
||||
}
|
||||
|
||||
private function getCartItemCount() {
|
||||
if (!WC()->cart) {
|
||||
if (!function_exists('WC') || !WC()->cart) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return WC()->cart->get_cart_contents_count();
|
||||
return intval(WC()->cart->get_cart_contents_count());
|
||||
}
|
||||
|
||||
private function productHasCategory($product, $categories) {
|
||||
@@ -229,7 +202,11 @@ class PricingService {
|
||||
}
|
||||
|
||||
$product_cats = wp_get_post_terms($product->get_id(), 'product_cat', ['fields' => 'ids']);
|
||||
return (bool) array_intersect($product_cats, $categories);
|
||||
if (is_wp_error($product_cats)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) array_intersect($product_cats, array_map('intval', $categories));
|
||||
}
|
||||
|
||||
private function productIsInIds($product, $ids) {
|
||||
@@ -237,14 +214,13 @@ class PricingService {
|
||||
return false;
|
||||
}
|
||||
|
||||
return in_array($product->get_id(), $ids, true);
|
||||
return in_array($product->get_id(), array_map('intval', $ids), true);
|
||||
}
|
||||
|
||||
private function applyActions($rule, $price) {
|
||||
private function applyRuleActions($rule, $price) {
|
||||
foreach ($rule->actions as $action) {
|
||||
$price = $this->applyAction($action, $price);
|
||||
}
|
||||
|
||||
return $price;
|
||||
}
|
||||
|
||||
@@ -263,6 +239,8 @@ class PricingService {
|
||||
return $price;
|
||||
}
|
||||
return $price - $value;
|
||||
case 'set_price':
|
||||
return $value > 0 ? $value : $price;
|
||||
case 'free_shipping':
|
||||
return $price;
|
||||
default:
|
||||
@@ -270,14 +248,15 @@ class PricingService {
|
||||
}
|
||||
}
|
||||
|
||||
private function enforceLimits($originalPrice, $price, array $settings) {
|
||||
$minPrice = max(0, floatval($settings['min_product_price']));
|
||||
private function enforceLimits($originalPrice, $price) {
|
||||
$minPrice = max(0, floatval($this->settings->get('min_product_price', 0)));
|
||||
$price = max($price, $minPrice);
|
||||
|
||||
$maxDiscountPercent = floatval($settings['max_discount_percent']);
|
||||
$maxDiscountPercent = floatval($this->settings->get('max_discount_percent', 100));
|
||||
if ($maxDiscountPercent > 0 && $maxDiscountPercent < 100) {
|
||||
$limit = $originalPrice * ($maxDiscountPercent / 100);
|
||||
$price = max($originalPrice - $limit, $price);
|
||||
$maxDiscount = $originalPrice * ($maxDiscountPercent / 100);
|
||||
$minAllowedPrice = $originalPrice - $maxDiscount;
|
||||
$price = max($minAllowedPrice, $price);
|
||||
}
|
||||
|
||||
return $price;
|
||||
|
||||
Reference in New Issue
Block a user