Promotions
Promotions are a powerful feature in Vanilo Cloud that allows you to create various types of discounts and special offers for shoppers.
Core Concepts
A promotion consists of:
- Basic properties (name, description, validity period, etc.)
 - Rules that determine in what conditions the promotion applies
 - Actions that define what the promotion does
 - Coupon codes (optional) that can be used to activate the promotion
 
Promotion Properties
$promotion = Promotion::create([
    'name' => 'Summer Sale',
    'description' => 'Special summer discount',
    'priority' => 1,
    'is_exclusive' => false,
    'usage_limit' => 100,
    'usage_count' => 0,
    'is_coupon_based' => false,
    'starts_at' => '2025-06-01 00:00:00',
    'ends_at' => '2025-08-31 23:59:59',
    'applies_to_discounted' => true
]);
Each promotion has the following configurable properties:
- Name: The display name of the promotion
 - Description: Detailed explanation of the promotion
 - Priority: Determines which promotion takes precedence when multiple promotions apply (higher number = higher priority)
 - Exclusive: When enabled, this promotion will be the only one applied to an order
 - Usage Limit: Maximum number of times the promotion can be used (optional)
 - Coupon Based: Whether the promotion requires a coupon code
 - Start Date: When the promotion becomes active (optional)
 - End Date: When the promotion expires (optional)
 - Applies to Discounted Items: Whether the promotion can be applied to items already on sale
 
Validity
A promotion is considered valid when:
- It has started (if 
starts_atis set) - It hasn't expired (if 
ends_atis set) - It hasn't reached its usage limit (if 
usage_limitis set) 
If neither start date, end date and usage limit is set, the promotion is considered valid indefinitely.
Rules
Rules determine when a promotion applies. Each rule must pass for the promotion to be eligible. Multiple rules can be combined, and all must be satisfied.
To add rules to a promotion, use the addRule method:
$promotion->addRule('cart_quantity', ['count' => 3]);
$promotion->addRule('cart_minimum_value', ['amount' => 100]);
The first parameter is the rule type, and the second is the rule configuration.
The rule type can be either the ID or the class name of a registered rule type.
Cart Quantity Rule Type
This rule checks if the cart contains a minimum number of items, like "Buy 3 or more items".
The configuration is as follows:
{
    "count": 3
}
The above configuration means "Buy 3 or more items to qualify", where count is the minimum number of items required in the cart.
Cart Minimum Value Rule
This rule checks if the cart total reaches a minimum amount.
Configuration example: "Spend $100 or more to qualify":
{
    "amount": 100
}
Actions
Actions define what happens when a promotion is applied. Multiple actions can be added to a single promotion.
To add actions to a promotion, use the addAction method:
$promotion->addAction('cart_fixed_discount', ['amount' => 10]);
$promotion->addAction('cart_percentage_discount', ['percentage' => 20]);
The first parameter is the action type, and the second is the action configuration.
The action type can be either the ID or the class name of a registered action type.
Cart Fixed Discount
Applies a fixed amount discount to the entire cart (items only, excluding shipping fees).
Sample configuration, "$10 off your order":
{
   "amount": 10
}
- amount: Fixed discount amount to apply
 - Example: "$10 off your order"
 
Cart Percentage Discount
Applies a percentage discount to the cart, like "20% off your order".
It takes a single configuration property, the percentage, which is the discount percentage to apply.
Example "20% off your order":
{
    "percentage": 20
}
Staggered Discount
Applies different discounts on individual cart items, based on the quantity of each line item.
The configuration takes a single thresholds property, which is an object mapping cart quantity thresholds to
discount percentages.
Example "Buy 10 get 5% off, 20 to get 7% off; 30 get 10% off":
{
   "thresholds": {
      "10": 5,
      "20": 7,
      "30": 10
   }
}
Coupons
Coupons are optional codes that can be associated with promotions. They provide additional control over promotion usage.
$coupon = Coupon::create([
    'code' => 'SUMMER2025',
    'promotion_id' => $promotion->id,
    'usage_limit' => 50,
    'per_customer_usage_limit' => 1,
    'usage_count' => 0,
    'expires_at' => '2025-08-31 23:59:59'
]);
It is possible to directly look up a promotion based on the coupon code:
$promotion = Promotion::findByCouponCode('SUMMER2025');
Coupon Properties
- Code: The unique code customers enter
 - Usage Limit: Maximum number of times the coupon can be used
 - Per Customer Limit: Maximum number of times a single customer can use the coupon
 - Expiration Date: When the coupon becomes invalid
 
Using Coupons
Customers can enter coupon codes during checkout. The system will:
- Validate the coupon code
 - Check if the promotion is still valid
 - Verify all rules are satisfied
 - Apply the promotion's actions if eligible
 
Best Practices
- Priority Management
- Use higher priority numbers for more important promotions
 - Set exclusive promotions carefully to avoid conflicts
 
 - Usage Limits
- Set appropriate usage limits to control promotion costs
 - Consider per-customer limits for personalized offers
 
 - Validity Periods
- Set clear start and end dates for time-sensitive promotions
 - Monitor usage to adjust limits if needed
 
 - Rule Combinations
- Combine rules to create targeted promotions
 - Test rule combinations to ensure they work as intended
 
 - Action Stacking
- Be mindful of how multiple actions interact
 - Consider the order of operations when combining different types of discounts
 
 
Extending the System
Adding New Rule Types
- Create a new rule class implementing 
PromotionRuleTypeinterface - Register the rule type in your application's 
AppServiceProviderclass. 
class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        PromotionRuleTypes::register('new_rule_type', NewRuleType::class);
    }
}
Adding New Action Types
- Create a new action class implementing 
PromotionActionTypeinterface - Register the action type in your application's 
AppServiceProviderclass. 
class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        PromotionActionTypes::register('new_action_type', NewActionType::class);
    }
}