hejunjie/promotion-engine 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

hejunjie/promotion-engine

Composer 安装命令:

composer require hejunjie/promotion-engine

包简介

一个 灵活可扩展 的 PHP 促销策略引擎,让购物车的各种复杂促销逻辑(满减、打折、阶梯优惠、会员折扣…)实现更优雅、可维护 | A flexible and scalable PHP promotional strategy engine that enables various complex promotional logics (money off, discounts, tiered offers, member discounts, etc.) in shopping carts to be implemented more elegantly and maintainably.

README 文档

README

English | 简体中文

A flexible and extensible PHP promotion strategy engine that abstracts complex shopping cart promotion logic — money-off, discounts, tiered offers, member discounts — out of if-else spaghetti and into composable rule classes.

This project has been parsed by Zread. If you need a quick overview of the project, you can click here to view it:Understand this project

Features

  • 🧩 Rules as classes:Each promotion strategy is an independent rule class — clear, testable, and reusable
  • 🔀 Three calculation modes:Independent, sequential (stacked), and lock modes for different business scenarios
  • 🏷️ Tag filtering:Rules match items by product tags, making category-specific promotions effortless
  • 📊 Priority control:Rules execute in priority order, giving you full control over discount stacking
  • 🔌 Easy to extend:Add custom rules by extending AbstractPromotionRule — no changes to the engine core
  • 🪶 Zero dependencies:Requires only PHP >= 7.4, no third-party libraries

Requirements

  • PHP >= 7.4 (also supports PHP 8.x)
  • Composer

Installation

composer require hejunjie/promotion-engine

Quick Start

use Hejunjie\PromotionEngine\Models\Cart;
use Hejunjie\PromotionEngine\Models\User;
use Hejunjie\PromotionEngine\PromotionEngine;
use Hejunjie\PromotionEngine\Rules;

// Create a VIP user
$user = new User(true);

// Create a shopping cart
$cart = new Cart();
$cart->addItem('Chips', 30, 2, ['snacks']);
$cart->addItem('T-shirt', 100, 1, ['clothes']);
$cart->addItem('Mouse', 200, 1, ['electronics']);

// Initialize the engine and set calculation mode
$engine = new PromotionEngine();
$engine->setMode('independent');

// Register rules
$engine->addRule(new Rules\FullReductionRule(300, 30));   // ¥30 off when total ≥ ¥300
$engine->addRule(new Rules\VipDiscountRule(0.95));         // VIP 5% off

// Calculate
$result = $engine->calculate($cart, $user);

echo "Original: ¥{$result['original']}\n";   // Original: ¥360
echo "Discount: -¥{$result['discount']}\n";  // Discount: -¥48
echo "Final: ¥{$result['final']}\n";         // Final: ¥312
print_r($result['details']);                 // Discount detail array

Calculation Modes

The engine supports three calculation modes, switchable via setMode()

Mode Identifier Behavior
Independent independent Each rule calculates its discount against the original price independently, then all discounts are summed
Sequential sequential Rules execute in order. Each rule's discount is distributed back into item prices, so subsequent rules calculate against already-discounted prices (stacked discounts)
Lock lock Each item can be discounted by at most one rule. Discounted items are locked and skipped by subsequent rules
// Independent: each rule works against original prices
$engine->setMode('independent');

// Sequential: discount-on-discount
$engine->setMode('sequential');

// Lock: each item receives only one discount
$engine->setMode('lock');

Note

In independent mode, rule order does not affect the final discount. In sequential and lock modes, rules execute in priority order.

Built-in Rules

All rules accept two optional trailing parameters for tag filtering and priority

// Only applies to items tagged 'snacks', priority 10 (lower = higher priority)
new Rules\FullReductionRule(100, 20, ['snacks'], 10);
Rule Description Example
FullReductionRule Spend ¥X, get ¥Y off new FullReductionRule(100, 20)
FullDiscountRule Spend ¥X, get Z% off new FullDiscountRule(200, 0.9)
FullQuantityReductionRule Buy X items, get ¥Y off new FullQuantityReductionRule(3, 20)
FullQuantityDiscountRule Buy X items, get Z% off new FullQuantityDiscountRule(5, 0.9)
TieredDiscountRule Tiered discount (highest eligible tier) new TieredDiscountRule([100 => 0.9, 200 => 0.8, 500 => 0.7])
TieredReductionRule Tiered money-off (highest eligible tier) new TieredReductionRule([100 => 10, 200 => 30, 500 => 80])
NthItemDiscountRule Nth item at Z% off new NthItemDiscountRule(3, 0.5)
NthItemReductionRule Nth item at special price ¥X new NthItemReductionRule(3, 9.9)
VipDiscountRule VIP members get Z% off new VipDiscountRule(0.9)
VipReductionRule VIP members get ¥X off new VipReductionRule(5)

Advanced Usage

Tag Filtering

Use product tags to restrict rules to specific categories:

$cart = new Cart();
$cart->addItem('Cola', 5, 10, ['drinks']);
$cart->addItem('Keyboard', 300, 1, ['electronics']);

// Only drinks: 20% off when buying 3 or more
$engine->addRule(new Rules\FullQuantityDiscountRule(3, 0.8, ['drinks']));

// Only electronics: ¥50 off when spending ¥200
$engine->addRule(new Rules\FullReductionRule(200, 50, ['electronics']));

Custom Rules

Extend AbstractPromotionRule and implement the apply() method:

use Hejunjie\PromotionEngine\Models\Cart;
use Hejunjie\PromotionEngine\Models\User;
use Hejunjie\PromotionEngine\PromotionResult;
use Hejunjie\PromotionEngine\Rules\AbstractPromotionRule;

class BirthdayDiscountRule extends AbstractPromotionRule
{
    public function apply(Cart $cart, User $user, array $eligibleIndexes = []): PromotionResult
    {
        $items = $this->filterEligibleItems($cart, $eligibleIndexes);
        $total = $cart->calculateItemsTotal($items);

        if ($total > 0) {
            $discount = round($total * 0.1, 2);
            return new PromotionResult($discount, 'Birthday 10% off');
        }

        return new PromotionResult(0, 'Birthday discount not triggered');
    }
}

// Use the custom rule
$engine->addRule(new BirthdayDiscountRule(['all'], 1));

Priority Control

Lower numbers have higher priority (default is 1). Priority determines execution order in multi-rule scenarios:

// Money-off runs first (priority 5), then VIP discount (priority 10)
$engine->addRule(new Rules\FullReductionRule(300, 30, [], 5));
$engine->addRule(new Rules\VipDiscountRule(0.9, [], 10));

Directory Structure

src/
├── PromotionEngine.php             # Engine entry point, rule management and calculation dispatch
├── PromotionResult.php             # Rule result value object (discount amount + description)
├── Calculators/
│   ├── IndependentCalculator.php   # Independent mode
│   ├── SequentialCalculator.php    # Sequential (stacked) mode
│   └── LockCalculator.php          # Lock mode
├── Contracts/
│   ├── PromotionCalculatorInterface.php  # Calculator interface
│   └── PromotionRuleInterface.php        # Rule interface
├── Models/
│   ├── Cart.php                    # Shopping cart model
│   └── User.php                    # User model
└── Rules/
    ├── AbstractPromotionRule.php         # Abstract rule base class
    ├── FullReductionRule.php             # Spend X, get Y off
    ├── FullDiscountRule.php              # Spend X, get Z% off
    ├── FullQuantityReductionRule.php     # Buy X items, get Y off
    ├── FullQuantityDiscountRule.php      # Buy X items, get Z% off
    ├── TieredDiscountRule.php            # Tiered discount
    ├── TieredReductionRule.php           # Tiered money-off
    ├── NthItemDiscountRule.php           # Nth item discount
    ├── NthItemReductionRule.php          # Nth item special price
    ├── VipDiscountRule.php               # VIP discount
    └── VipReductionRule.php              # VIP money-off

Contributing

PRs are welcome! Areas that especially need help:

  • New promotion rules (coupons, buy-one-get-one, flash sales, etc.)
  • Unit tests
  • Performance improvements

Fork the repository, submit a Pull Request, or open an Issue to discuss ideas.

hejunjie/promotion-engine 适用场景与选型建议

hejunjie/promotion-engine 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 5 次下载、GitHub Stars 达 18, 最近一次更新时间为 2025 年 07 月 29 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 hejunjie/promotion-engine 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 hejunjie/promotion-engine 我们能提供哪些服务?
定制开发 / 二次开发

基于 hejunjie/promotion-engine 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 5
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 18
  • 点击次数: 31
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 18
  • Watchers: 0
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-07-29