首页 / 跨境电商轻量软件 / 实操指南:开发促销活动规则接口的5个逻辑设计

实操指南:开发促销活动规则接口的5个逻辑设计

实操指南:开发促销活动规则接口的5个逻辑设计

引言:促销活动规则接口的重要性

在当今电子商务蓬勃发展的时代,促销活动已成为电商平台吸引用户、提升销量的核心手段。无论是限时折扣、满减优惠、买赠活动还是会员专享,这些促销规则都需要通过精心设计的接口来实现。对于使用WordPress开源系统的开发者而言,如何设计高效、灵活且易于维护的促销活动规则接口,是提升电商网站竞争力的关键。

本指南将基于WordPress开发环境,详细解析促销活动规则接口的5个核心逻辑设计,帮助行业新人和程序员快速掌握这一关键技术。我们将从基础架构设计开始,逐步深入到复杂的规则组合与扩展机制,每个部分都配有实际代码示例和最佳实践建议。

一、基础架构设计:构建可扩展的规则引擎

1.1 规则数据模型设计

在WordPress中设计促销规则接口,首先需要建立合理的数据模型。我们建议使用自定义文章类型(Custom Post Type)来存储促销活动,同时利用自定义字段(Custom Fields)或元数据(Metadata)来存储规则参数。

// 注册促销活动自定义文章类型
function register_promotion_post_type() {
    $args = array(
        'public' => true,
        'label'  => '促销活动',
        'supports' => array('title', 'editor', 'custom-fields'),
        'menu_icon' => 'dashicons-tag',
        'has_archive' => true,
    );
    register_post_type('promotion', $args);
}
add_action('init', 'register_promotion_post_type');

// 添加促销规则元数据
function add_promotion_meta_fields() {
    add_meta_box(
        'promotion_rules',
        '促销规则设置',
        'render_promotion_rules_meta_box',
        'promotion',
        'normal',
        'high'
    );
}
add_action('add_meta_boxes', 'add_promotion_meta_fields');

1.2 规则接口基类设计

创建一个抽象基类,定义所有促销规则必须实现的方法,确保接口的一致性:

abstract class Promotion_Rule_Base {
    protected $rule_id;
    protected $rule_data;
    
    public function __construct($rule_id, $rule_data) {
        $this->rule_id = $rule_id;
        $this->rule_data = $rule_data;
    }
    
    // 验证规则是否适用于当前购物车
    abstract public function is_applicable($cart_data);
    
    // 应用规则计算折扣
    abstract public function apply($cart_data);
    
    // 获取规则描述
    abstract public function get_description();
    
    // 验证规则配置是否有效
    abstract public function validate_configuration();
}

1.3 规则工厂模式实现

使用工厂模式创建规则实例,提高代码的可维护性和扩展性:

class Promotion_Rule_Factory {
    private static $rule_types = array();
    
    public static function register_rule_type($type, $class_name) {
        self::$rule_types[$type] = $class_name;
    }
    
    public static function create_rule($rule_id, $rule_type, $rule_data) {
        if (!isset(self::$rule_types[$rule_type])) {
            throw new Exception("未知的规则类型: {$rule_type}");
        }
        
        $class_name = self::$rule_types[$rule_type];
        return new $class_name($rule_id, $rule_data);
    }
    
    public static function get_available_rule_types() {
        return array_keys(self::$rule_types);
    }
}

二、核心规则逻辑实现:五种常见促销类型

2.1 折扣规则设计

折扣规则是最基础的促销类型,支持百分比折扣和固定金额折扣:

class Discount_Rule extends Promotion_Rule_Base {
    const TYPE_PERCENTAGE = 'percentage';
    const TYPE_FIXED_AMOUNT = 'fixed_amount';
    
    public function is_applicable($cart_data) {
        // 检查活动时间
        $current_time = current_time('timestamp');
        $start_time = strtotime($this->rule_data['start_date']);
        $end_time = strtotime($this->rule_data['end_date']);
        
        if ($current_time < $start_time || $current_time > $end_time) {
            return false;
        }
        
        // 检查最低消费金额
        if (isset($this->rule_data['min_amount']) && 
            $cart_data['subtotal'] < $this->rule_data['min_amount']) {
            return false;
        }
        
        // 检查适用商品
        if (!$this->check_applicable_products($cart_data['items'])) {
            return false;
        }
        
        return true;
    }
    
    public function apply($cart_data) {
        if (!$this->is_applicable($cart_data)) {
            return $cart_data;
        }
        
        $discount_amount = 0;
        
        if ($this->rule_data['discount_type'] === self::TYPE_PERCENTAGE) {
            $discount_amount = $cart_data['subtotal'] * ($this->rule_data['discount_value'] / 100);
        } else {
            $discount_amount = min($this->rule_data['discount_value'], $cart_data['subtotal']);
        }
        
        // 应用折扣
        $cart_data['discount'] += $discount_amount;
        $cart_data['total'] = $cart_data['subtotal'] - $cart_data['discount'];
        
        // 记录应用详情
        $cart_data['applied_rules'][] = array(
            'rule_id' => $this->rule_id,
            'rule_name' => $this->rule_data['name'],
            'discount_amount' => $discount_amount,
            'type' => 'discount'
        );
        
        return $cart_data;
    }
    
    private function check_applicable_products($cart_items) {
        // 实现商品检查逻辑
        // 可以基于商品ID、分类、标签等进行过滤
        return true;
    }
    
    public function get_description() {
        $type = $this->rule_data['discount_type'];
        $value = $this->rule_data['discount_value'];
        
        if ($type === self::TYPE_PERCENTAGE) {
            return "享受{$value}%折扣";
        } else {
            return "立减{$value}元";
        }
    }
    
    public function validate_configuration() {
        // 验证折扣配置
        $errors = array();
        
        if (!isset($this->rule_data['discount_type']) || 
            !in_array($this->rule_data['discount_type'], [self::TYPE_PERCENTAGE, self::TYPE_FIXED_AMOUNT])) {
            $errors[] = "折扣类型无效";
        }
        
        if (!isset($this->rule_data['discount_value']) || 
            !is_numeric($this->rule_data['discount_value']) || 
            $this->rule_data['discount_value'] <= 0) {
            $errors[] = "折扣值必须为正数";
        }
        
        if ($this->rule_data['discount_type'] === self::TYPE_PERCENTAGE && 
            $this->rule_data['discount_value'] > 100) {
            $errors[] = "百分比折扣不能超过100%";
        }
        
        return empty($errors) ? true : $errors;
    }
}

2.2 满减规则设计

满减规则鼓励用户达到特定消费金额,是提升客单价的有效手段:

class Spend_X_Get_Y_Discount_Rule extends Promotion_Rule_Base {
    public function is_applicable($cart_data) {
        // 检查是否达到满减门槛
        return $cart_data['subtotal'] >= $this->rule_data['threshold'];
    }
    
    public function apply($cart_data) {
        if (!$this->is_applicable($cart_data)) {
            return $cart_data;
        }
        
        $discount_amount = $this->calculate_discount($cart_data['subtotal']);
        
        // 应用折扣
        $cart_data['discount'] += $discount_amount;
        $cart_data['total'] = $cart_data['subtotal'] - $cart_data['discount'];
        
        // 记录应用详情
        $cart_data['applied_rules'][] = array(
            'rule_id' => $this->rule_id,
            'rule_name' => $this->rule_data['name'],
            'discount_amount' => $discount_amount,
            'type' => 'spend_x_get_y'
        );
        
        return $cart_data;
    }
    
    private function calculate_discount($subtotal) {
        $threshold = $this->rule_data['threshold'];
        $discount = $this->rule_data['discount'];
        
        // 支持多级满减
        if (isset($this->rule_data['multi_level']) && $this->rule_data['multi_level']) {
            $levels = $this->rule_data['levels'];
            usort($levels, function($a, $b) {
                return $b['threshold'] - $a['threshold'];
            });
            
            foreach ($levels as $level) {
                if ($subtotal >= $level['threshold']) {
                    return $level['discount'];
                }
            }
        }
        
        return $discount;
    }
    
    public function get_description() {
        $threshold = $this->rule_data['threshold'];
        $discount = $this->rule_data['discount'];
        
        if (isset($this->rule_data['multi_level']) && $this->rule_data['multi_level']) {
            $descriptions = array();
            foreach ($this->rule_data['levels'] as $level) {
                $descriptions[] = "满{$level['threshold']}减{$level['discount']}";
            }
            return implode(',', $descriptions);
        }
        
        return "满{$threshold}减{$discount}";
    }
    
    public function validate_configuration() {
        $errors = array();
        
        if (!isset($this->rule_data['threshold']) || $this->rule_data['threshold'] <= 0) {
            $errors[] = "满减门槛必须大于0";
        }
        
        if (!isset($this->rule_data['discount']) || $this->rule_data['discount'] <= 0) {
            $errors[] = "折扣金额必须大于0";
        }
        
        if (isset($this->rule_data['multi_level']) && $this->rule_data['multi_level']) {
            if (!isset($this->rule_data['levels']) || !is_array($this->rule_data['levels'])) {
                $errors[] = "多级满减必须设置级别";
            } else {
                foreach ($this->rule_data['levels'] as $index => $level) {
                    if (!isset($level['threshold']) || !isset($level['discount'])) {
                        $errors[] = "第" . ($index + 1) . "级满减配置不完整";
                    }
                }
            }
        }
        
        return empty($errors) ? true : $errors;
    }
}

2.3 买赠规则设计

买赠规则通过赠送商品或礼品来刺激消费:

class Buy_X_Get_Y_Free_Rule extends Promotion_Rule_Base {
    public function is_applicable($cart_data) {
        // 检查购物车中指定商品的数量
        $target_product_count = $this->count_target_products($cart_data['items']);
        
        return $target_product_count >= $this->rule_data['buy_quantity'];
    }
    
    public function apply($cart_data) {
        if (!$this->is_applicable($cart_data)) {
            return $cart_data;
        }
        
        $target_product_count = $this->count_target_products($cart_data['items']);
        $free_quantity = floor($target_product_count / $this->rule_data['buy_quantity']) * 
                         $this->rule_data['get_quantity'];
        
        // 添加赠品到购物车
        $free_product = array(
            'product_id' => $this->rule_data['free_product_id'],
            'quantity' => $free_quantity,
            'price' => 0,
            'is_free_gift' => true,
            'rule_id' => $this->rule_id
        );
        
        $cart_data['items'][] = $free_product;
        
        // 更新购物车总计
        $cart_data = $this->recalculate_cart_totals($cart_data);
        
        // 记录应用详情
        $cart_data['applied_rules'][] = array(
            'rule_id' => $this->rule_id,
            'rule_name' => $this->rule_data['name'],
            'free_product_id' => $this->rule_data['free_product_id'],
            'free_quantity' => $free_quantity,
            'type' => 'buy_x_get_y_free'
        );
        
        return $cart_data;
    }
    
    private function count_target_products($cart_items) {
        $count = 0;
        $target_products = $this->rule_data['target_products'];
        
        foreach ($cart_items as $item) {
            if (in_array($item['product_id'], $target_products) && 
                !isset($item['is_free_gift'])) {
                $count += $item['quantity'];
            }
        }
        
        return $count;
    }
    
    private function recalculate_cart_totals($cart_data) {
        $subtotal = 0;
        
        foreach ($cart_data['items'] as $item) {
            if (!isset($item['is_free_gift'])) {
                $subtotal += $item['price'] * $item['quantity'];
            }
        }
        
        $cart_data['subtotal'] = $subtotal;
        $cart_data['total'] = $subtotal - $cart_data['discount'];
        
        return $cart_data;
    }
    
    public function get_description() {
        $buy_qty = $this->rule_data['buy_quantity'];
        $get_qty = $this->rule_data['get_quantity'];
        $free_product_name = get_the_title($this->rule_data['free_product_id']);
        
        return "买{$buy_qty}赠{$get_qty} - {$free_product_name}";
    }
    
    public function validate_configuration() {
        $errors = array();
        
        if (!isset($this->rule_data['buy_quantity']) || $this->rule_data['buy_quantity'] <= 0) {
            $errors[] = "购买数量必须大于0";
        }
        
        if (!isset($this->rule_data['get_quantity']) || $this->rule_data['get_quantity'] <= 0) {
            $errors[] = "赠送数量必须大于0";
        }
        
        if (!isset($this->rule_data['free_product_id']) || 
            !get_post($this->rule_data['free_product_id'])) {
            $errors[] = "赠品商品不存在";
        }
        
        if (!isset($this->rule_data['target_products']) || 
            !is_array($this->rule_data['target_products']) || 
            empty($this->rule_data['target_products'])) {
            $errors[] = "必须指定适用商品";
        }
        
        return empty($errors) ? true : $errors;
    }
}

2.4 会员专享规则设计

会员专享规则为不同等级的会员提供差异化优惠:

class Member_Exclusive_Rule extends Promotion_Rule_Base {
    public function is_applicable($cart_data) {
        // 检查用户会员等级
        $user_id = get_current_user_id();
        
        if ($user_id === 0) {
            return false; // 未登录用户
        }
        
        $user_member_level = $this->get_user_member_level($user_id);
        $required_level = $this->rule_data['required_member_level'];
        
        return $this->compare_member_levels($user_member_level, $required_level);
    }
    
    public function apply($cart_data) {
        if (!$this->is_applicable($cart_data)) {
            return $cart_data;
        }
        
        // 根据会员等级计算折扣
        $user_id = get_current_user_id();
        $user_member_level = $this->get_user_member_level($user_id);
        $discount_rate = $this->get_discount_for_member_level($user_member_level);
        
        $discount_amount = $cart_data['subtotal'] * ($discount_rate / 100);
        
        // 应用折扣
        $cart_data['discount'] += $discount_amount;
        $cart_data['total'] = $cart_data['subtotal'] - $cart_data['discount'];
        
        // 记录应用详情
        $cart_data['applied_rules'][] = array(
            'rule_id' => $this->rule_id,
            'rule_name' => $this->rule_data['name'],
            'discount_amount' => $discount_amount,
            'member_level' => $user_member_level,
            'type' => 'member_exclusive'
        );
        
        return $cart_data;
    }
    
    private function get_user_member_level($user_id) {
        // 这里需要根据实际的会员系统实现
        // 假设使用用户元数据存储会员等级
        $level = get_user_meta($user_id, 'member_level', true);
        return $level ? $level : 'regular';
    }
    
    private function compare_member_levels($user_level, $required_level) {
        // 定义会员等级顺序
        $level_order = array('regular', 'silver', 'gold', 'platinum', 'diamond');
        
        $user_index = array_search($user_level, $level_order);
        $required_index = array_search($required_level, $level_order);
        
        return $user_index !== false && $required_index !== false && 
               $user_index >= $required_index;
    }
    
    private function get_discount_for_member_level($member_level) {
        // 根据会员等级获取对应的折扣率
        $discount_map = $this->rule_data['discount_by_level'];
        
        return isset($discount_map[$member_level]) ? 
               $discount_map[$member_level] : 0;
    }
    
    public function get_description() {
        $levels = array();
        foreach ($this->rule_data['discount_by_level'] as $level => $discount) {
            $levels[] = "{$level}会员{$discount}%折扣";
        }
        

2.5 组合规则设计

组合规则允许将多个促销规则组合使用,实现更复杂的营销策略:

class Combined_Promotion_Rule extends Promotion_Rule_Base {
    private $sub_rules = array();
    
    public function __construct($rule_id, $rule_data) {
        parent::__construct($rule_id, $rule_data);
        $this->initialize_sub_rules();
    }
    
    private function initialize_sub_rules() {
        if (!isset($this->rule_data['sub_rules']) || 
            !is_array($this->rule_data['sub_rules'])) {
            return;
        }
        
        foreach ($this->rule_data['sub_rules'] as $sub_rule_data) {
            try {
                $sub_rule = Promotion_Rule_Factory::create_rule(
                    $sub_rule_data['id'],
                    $sub_rule_data['type'],
                    $sub_rule_data['data']
                );
                $this->sub_rules[] = $sub_rule;
            } catch (Exception $e) {
                error_log("初始化子规则失败: " . $e->getMessage());
            }
        }
    }
    
    public function is_applicable($cart_data) {
        // 检查组合规则的整体条件
        if (!$this->check_combined_conditions($cart_data)) {
            return false;
        }
        
        // 检查子规则的适用性
        $applicable_sub_rules = array();
        foreach ($this->sub_rules as $sub_rule) {
            if ($sub_rule->is_applicable($cart_data)) {
                $applicable_sub_rules[] = $sub_rule;
            }
        }
        
        // 根据组合类型判断是否适用
        $combination_type = $this->rule_data['combination_type'] ?? 'all';
        
        switch ($combination_type) {
            case 'all':
                return count($applicable_sub_rules) === count($this->sub_rules);
            case 'any':
                return !empty($applicable_sub_rules);
            case 'at_least':
                $min_count = $this->rule_data['min_rule_count'] ?? 1;
                return count($applicable_sub_rules) >= $min_count;
            default:
                return false;
        }
    }
    
    public function apply($cart_data) {
        if (!$this->is_applicable($cart_data)) {
            return $cart_data;
        }
        
        // 确定要应用的子规则
        $applicable_sub_rules = array();
        foreach ($this->sub_rules as $sub_rule) {
            if ($sub_rule->is_applicable($cart_data)) {
                $applicable_sub_rules[] = $sub_rule;
            }
        }
        
        // 根据优先级排序
        usort($applicable_sub_rules, function($a, $b) {
            $priority_a = $a->get_priority() ?? 0;
            $priority_b = $b->get_priority() ?? 0;
            return $priority_b - $priority_a; // 优先级高的先应用
        });
        
        // 应用子规则
        $original_cart_data = $cart_data;
        $applied_rules_info = array();
        
        foreach ($applicable_sub_rules as $sub_rule) {
            $cart_data = $sub_rule->apply($cart_data);
            
            // 记录每个子规则的应用结果
            if (isset($cart_data['applied_rules'])) {
                $last_rule = end($cart_data['applied_rules']);
                if ($last_rule) {
                    $applied_rules_info[] = $last_rule;
                }
            }
        }
        
        // 添加组合规则的应用记录
        $cart_data['applied_rules'][] = array(
            'rule_id' => $this->rule_id,
            'rule_name' => $this->rule_data['name'],
            'type' => 'combined',
            'sub_rules_applied' => $applied_rules_info,
            'total_discount' => $original_cart_data['subtotal'] - $cart_data['total']
        );
        
        return $cart_data;
    }
    
    private function check_combined_conditions($cart_data) {
        // 检查组合规则特有的条件
        $conditions = $this->rule_data['conditions'] ?? array();
        
        foreach ($conditions as $condition) {
            if (!$this->evaluate_condition($condition, $cart_data)) {
                return false;
            }
        }
        
        return true;
    }
    
    private function evaluate_condition($condition, $cart_data) {
        $type = $condition['type'] ?? '';
        $value = $condition['value'] ?? '';
        $operator = $condition['operator'] ?? 'equals';
        
        switch ($type) {
            case 'total_amount':
                $cart_value = $cart_data['subtotal'];
                return $this->compare_values($cart_value, $value, $operator);
                
            case 'product_count':
                $product_count = count($cart_data['items']);
                return $this->compare_values($product_count, $value, $operator);
                
            case 'contains_category':
                $category_ids = $this->get_cart_category_ids($cart_data);
                $target_category = intval($value);
                return in_array($target_category, $category_ids);
                
            case 'user_segment':
                $user_id = get_current_user_id();
                $user_segment = $this->get_user_segment($user_id);
                return $user_segment === $value;
                
            default:
                return true;
        }
    }
    
    private function compare_values($actual, $expected, $operator) {
        switch ($operator) {
            case 'equals': return $actual == $expected;
            case 'greater_than': return $actual > $expected;
            case 'less_than': return $actual < $expected;
            case 'greater_than_or_equal': return $actual >= $expected;
            case 'less_than_or_equal': return $actual <= $expected;
            default: return false;
        }
    }
    
    public function get_description() {
        $descriptions = array();
        foreach ($this->sub_rules as $sub_rule) {
            $descriptions[] = $sub_rule->get_description();
        }
        
        $combination_type = $this->rule_data['combination_type'] ?? 'all';
        $connector = $combination_type === 'all' ? '且' : '或';
        
        return "组合优惠:" . implode(" {$connector} ", $descriptions);
    }
    
    public function validate_configuration() {
        $errors = array();
        
        if (!isset($this->rule_data['sub_rules']) || 
            !is_array($this->rule_data['sub_rules']) || 
            empty($this->rule_data['sub_rules'])) {
            $errors[] = "组合规则必须包含至少一个子规则";
        }
        
        if (isset($this->rule_data['combination_type']) && 
            !in_array($this->rule_data['combination_type'], ['all', 'any', 'at_least'])) {
            $errors[] = "无效的组合类型";
        }
        
        if (isset($this->rule_data['combination_type']) && 
            $this->rule_data['combination_type'] === 'at_least' && 
            (!isset($this->rule_data['min_rule_count']) || 
             $this->rule_data['min_rule_count'] < 1)) {
            $errors[] = "至少应用规则数量必须大于0";
        }
        
        // 验证子规则
        if (isset($this->rule_data['sub_rules'])) {
            foreach ($this->rule_data['sub_rules'] as $index => $sub_rule_data) {
                try {
                    $sub_rule = Promotion_Rule_Factory::create_rule(
                        $sub_rule_data['id'] ?? 'temp_' . $index,
                        $sub_rule_data['type'],
                        $sub_rule_data['data']
                    );
                    
                    $validation_result = $sub_rule->validate_configuration();
                    if ($validation_result !== true) {
                        $errors[] = "子规则" . ($index + 1) . "配置错误: " . 
                                   implode(', ', $validation_result);
                    }
                } catch (Exception $e) {
                    $errors[] = "子规则" . ($index + 1) . "创建失败: " . $e->getMessage();
                }
            }
        }
        
        return empty($errors) ? true : $errors;
    }
}

三、规则冲突与优先级管理

3.1 冲突检测机制

当多个促销规则同时适用时,需要检测和处理规则冲突:

class Promotion_Rule_Conflict_Resolver {
    private $applied_rules = array();
    private $conflict_strategy;
    
    const STRATEGY_FIRST_WINS = 'first_wins';
    const STRATEGY_HIGHEST_DISCOUNT = 'highest_discount';
    const STRATEGY_MOST_RESTRICTIVE = 'most_restrictive';
    const STRATEGY_COMBINE_ALL = 'combine_all';
    
    public function __construct($strategy = self::STRATEGY_FIRST_WINS) {
        $this->conflict_strategy = $strategy;
    }
    
    public function add_rule($rule) {
        $this->applied_rules[] = $rule;
    }
    
    public function resolve_conflicts($cart_data) {
        if (count($this->applied_rules) <= 1) {
            return $this->applied_rules;
        }
        
        // 检测冲突
        $conflicts = $this->detect_conflicts();
        
        if (empty($conflicts)) {
            return $this->applied_rules;
        }
        
        // 根据策略解决冲突
        switch ($this->conflict_strategy) {
            case self::STRATEGY_FIRST_WINS:
                return $this->resolve_first_wins($conflicts);
                
            case self::STRATEGY_HIGHEST_DISCOUNT:
                return $this->resolve_highest_discount($conflicts, $cart_data);
                
            case self::STRATEGY_MOST_RESTRICTIVE:
                return $this->resolve_most_restrictive($conflicts);
                
            case self::STRATEGY_COMBINE_ALL:
                return $this->resolve_combine_all($conflicts, $cart_data);
                
            default:
                return $this->applied_rules;
        }
    }
    
    private function detect_conflicts() {
        $conflicts = array();
        
        for ($i = 0; $i < count($this->applied_rules); $i++) {
            for ($j = $i + 1; $j < count($this->applied_rules); $j++) {
                $rule_a = $this->applied_rules[$i];
                $rule_b = $this->applied_rules[$j];
                
                if ($this->are_rules_conflicting($rule_a, $rule_b)) {
                    $conflicts[] = array(
                        'rule_a' => $rule_a,
                        'rule_b' => $rule_b,
                        'conflict_type' => $this->get_conflict_type($rule_a, $rule_b)
                    );
                }
            }
        }
        
        return $conflicts;
    }
    
    private function are_rules_conflicting($rule_a, $rule_b) {
        // 检查规则类型是否冲突
        $type_a = $rule_a->get_type();
        $type_b = $rule_b->get_type();
        
        // 定义冲突矩阵
        $conflict_matrix = array(
            'discount' => array('discount', 'member_exclusive'),
            'spend_x_get_y' => array('spend_x_get_y'),
            'member_exclusive' => array('discount', 'member_exclusive')
        );
        
        if (isset($conflict_matrix[$type_a]) && 
            in_array($type_b, $conflict_matrix[$type_a])) {
            return true;
        }
        
        // 检查规则作用范围是否重叠
        $scope_a = $rule_a->get_scope();
        $scope_b = $rule_b->get_scope();
        
        return $this->scopes_overlap($scope_a, $scope_b);
    }
    
    private function get_conflict_type($rule_a, $rule_b) {
        $type_a = $rule_a->get_type();
        $type_b = $rule_b->get_type();
        
        if ($type_a === $type_b) {
            return 'same_type';
        }
        
        if (($type_a === 'discount' && $type_b === 'member_exclusive') || 
            ($type_a === 'member_exclusive' && $type_b === 'discount')) {
            return 'discount_overlap';
        }
        
        return 'scope_overlap';
    }
    
    private function resolve_first_wins($conflicts) {
        // 保留第一个规则,移除冲突的后续规则
        $resolved_rules = array();
        $excluded_rules = array();
        
        foreach ($conflicts as $conflict) {
            $excluded_rules[] = $conflict['rule_b']->get_id();
        }
        
        foreach ($this->applied_rules as $rule) {
            if (!in_array($rule->get_id(), $excluded_rules)) {
                $resolved_rules[] = $rule;
            }
        }
        
        return $resolved_rules;
    }
    
    private function resolve_highest_discount($conflicts, $cart_data) {
        // 计算每个规则的折扣金额
        $rule_discounts = array();
        
        foreach ($this->applied_rules as $rule) {
            $temp_cart = $rule->apply($cart_data);
            $discount = $cart_data['subtotal'] - $temp_cart['total'];
            $rule_discounts[$rule->get_id()] = $discount;
        }
        
        // 解决冲突,保留折扣最高的规则
        $resolved_rules = array();
        
        foreach ($conflicts as $conflict) {
            $discount_a = $rule_discounts[$conflict['rule_a']->get_id()];
            $discount_b = $rule_discounts[$conflict['rule_b']->get_id()];
            
            if ($discount_a >= $discount_b) {
                $resolved_rules[$conflict['rule_a']->get_id()] = $conflict['rule_a'];
            } else {
                $resolved_rules[$conflict['rule_b']->get_id()] = $conflict['rule_b'];
            }
        }
        
        return array_values($resolved_rules);
    }
}

3.2 优先级系统实现

为促销规则添加优先级管理,确保重要规则优先应用:

class Promotion_Rule_Priority_Manager {
    private $rules_with_priority = array();
    
    public function add_rule_with_priority($rule, $priority = 0) {
        $this->rules_with_priority[] = array(
            'rule' => $rule,
            'priority' => $priority,
            'id' => $rule->get_id()
        );
    }
    
    public function sort_rules_by_priority() {
        usort($this->rules_with_priority, function($a, $b) {
            // 优先级高的排在前面
            if ($a['priority'] != $b['priority']) {
                return $b['priority'] - $a['priority'];
            }
            
            // 如果优先级相同,按ID排序确保稳定性
            return strcmp($a['id'], $b['id']);
        });
        
        return array_column($this->rules_with_priority, 'rule');
    }
    
    public function get_rules_by_priority_group() {
        $groups = array();
        
        foreach ($this->rules_with_priority as $item) {
            $priority = $item['priority'];
            if (!isset($groups[$priority])) {
                $groups[$priority] = array();
            }
            $groups[$priority][] = $item['rule'];
        }
        
        // 按优先级从高到低排序
        krsort($groups);
        
        return $groups;
    }
    
    public function apply_rules_in_priority_order($cart_data) {
        $sorted_rules = $this->sort_rules_by_priority();
        $result_cart = $cart_data;
        
        foreach ($sorted_rules as $rule) {
            if ($rule->is_applicable($result_cart)) {
                $result_cart = $rule->apply($result_cart);
            }
        }
        
        return $result_cart;
    }
}

四、规则验证与测试框架

4.1 规则配置验证器

确保促销规则配置的正确性和完整性:

class Promotion_Rule_Validator {
    public static function validate_rule_configuration($rule_type, $rule_data) {
        $errors = array();
        
        // 通用验证
        $errors = array_merge($errors, self::validate_common_fields($rule_data));
        
        // 特定规则类型验证
        switch ($rule_type) {
            case 'discount':
                $errors = array_merge($errors, self::validate_discount_rule($rule_data));
                break;
                
            case 'spend_x_get_y':
                $errors = array_merge($errors, self::validate_spend_x_get_y_rule($rule_data));
                break;
                
            case 'buy_x_get_y_free':
                $errors = array_merge($errors, self::validate_buy_x_get_y_free_rule($rule_data));
                break;
                
            case 'member_exclusive':
                $errors = array_merge($errors, self::validate_member_exclusive_rule($rule_data));
                break;
                
            case 'combined':
                $errors = array_merge($errors, self::validate_combined_rule($rule_data));
                break;
                
            default:
                $errors[] = "未知的规则类型: {$rule_type}";
        }
        
        return empty($errors) ? true : $errors;
    }
    
    private static function validate_common_fields($rule_data) {
        $errors = array();
        
        if (!isset($rule_data['name']) || empty(trim($rule_data['name']))) {
            $errors[] = "规则名称不能为空";
        }
        
        if (!isset($rule_data['start_date']) || 
            !self::is_valid_date($rule_data['start_date'])) {
            $errors[] = "开始日期无效";
        }
        
        if (!isset($rule_data['end_date']) || 
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/252.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

工作时间:周一至周五,9:00-17:30,节假日休息
返回顶部