DiscountService (App\Services\DiscountService) is the central pricing engine for Site Store Pro. It governs every price adjustment a customer sees — from category-wide markdowns and quantity breaks to BOGO promotions and stacking order coupons. Understanding how it works lets you build integrations, custom rules, and reporting tools that align with the platform’s pricing logic.
Public Methods
These two methods are your primary entry points when working with discounted pricing programmatically.applyDiscountsToCart
Runs the full 3-phase discount pipeline against a set of cart line items for a given user. Use this when you need the complete, order-ready price breakdown.
getDiscountedPriceForVariant
Calculates the discounted price for a single variant given user context and quantity. Use this for catalog displays and buy-box pricing.
applyDiscountsToCart
$items accepts any iterable collection of cart line objects, and $user accepts either an authenticated User model or a guest user representation. The method runs all three discount phases in sequence and returns a structured array:
Example:
getDiscountedPriceForVariant
$variant accepts a ProductVariant model instance, $user accepts an authenticated user or guest, and $qty is the requested quantity as an integer or numeric string.
Example:
The 3-Phase Discount Pipeline
WhenapplyDiscountsToCart runs, it evaluates discounts in three sequential phases. Each phase builds on the previous one. Later phases cannot override item-level pricing settled in Phase 1 — they add to or further reduce the running total.
1
Phase 1 — Item-Level Evaluation
For each line item in the cart, the service walks through up to five discount rules in ascending priority order. The last applicable rule wins — meaning a higher-priority rule will replace a lower-priority one if both match.The evaluation order per line item is:
Because the last applicable rule wins, a more specific discount (like an item-specific price) will always take precedence over a broader one (like a category discount) as long as it is evaluated later in the sequence. Design your discount rules with this ordering in mind to avoid unintended overrides.
After this phase, every line item has its final per-unit adjusted price.
2
Phase 2 — BOGO Evaluation
After item-level pricing is settled, the service evaluates any active Buy X Get Y (BOGO) promotions.
- Trigger check: Validates that the trigger product X is present in the cart at or above the required
free_range1quantity threshold. - Target discount: Applies the configured
product_y_percentdiscount to the target product Y in the cart. - Slide cart lock: Marks the BOGO target item’s quantity as locked in the slide cart to prevent the customer from editing it to exploit the promotion.
3
Phase 3 — Order-Level Discounts
With item and BOGO pricing settled, the service evaluates discounts that apply to the order as a whole. These are processed in the following priority order (highest priority applied first):
Each candidate discount is validated against:
- Minimum and maximum order spend
- Minimum order quantity
- Minimum order weight
- Customer role eligibility
allow_multiple_order_discounts config flag is enabled, valid discounts at this phase can stack. Otherwise, only the highest-priority applicable discount is applied.Discount Type Reference
Use these type identifiers and slugs when querying thediscounts table or building custom tooling around the discount system.
CurrencyService Integration
App\Services\CurrencyService works alongside DiscountService to ensure that every price returned is formatted correctly for the active storefront language.
The service calls LanguageService::currencyOverride() to check whether the current language has a currency override configured. Based on the result, it dynamically formats:
- Symbol — e.g.
$,€,£ - Symbol placement — prefix or suffix
- Decimal and thousands separators — locale-aware formatting
CurrencyService directly when using applyDiscountsToCart or getDiscountedPriceForVariant — prices are returned as raw floats. Apply CurrencyService formatting at the display layer when rendering prices to the storefront.