文章目录[隐藏]
实操指南:开发促销活动规则接口的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']) ||
