Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Discountify Laravel Package

safemood/discountify

Laravel package for dynamic, condition-based discounts. Define custom discount rules, apply percentage discounts, set global discount and tax rate, support dynamic field names, class-based and coupon discounts, optional event tracking, and the ability to skip conditions.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package via Composer:

    composer require safemood/discountify
    
  2. Publish the config file to customize field mappings and behavior:

    php artisan vendor:publish --tag="discountify-config"
    
  3. First use case: Define and apply a simple conditional discount in AppServiceProvider::boot():

    use Safemood\Discountify\Facades\Condition;
    use Safemood\Discountify\Facades\Discountify;
    
    Condition::define(
        'large_order_10_percent',
        fn (array $items) => collect($items)->sum('quantity') > 5,
        10
    );
    
    $total = Discountify::setItems($items)
        ->total(); // Automatically applies the condition if met
    
  4. Explore documentation: Start with the Usage section of the README — especially Define Conditions, Calculate Total Amounts, and Class-Based Discounts.


Implementation Patterns

  • Hybrid condition definitions: Combine callable-based and class-based conditions depending on complexity:

    • Use Condition::define() for simple, inline logic.
    • Use discountify:condition Artisan command + classes (php artisan discountify:condition ShippingThreshold) for reusable, testable logic.
  • Field abstraction: When working with legacy or third-party item structures, use dynamic field mapping:

    Discountify::setFields(['price' => 'unit_price', 'quantity' => 'qty'])
        ->setItems($items)
        ->total();
    
  • Layered discount application:

    • Apply global discounts first via setGlobalDiscount()
    • Add conditional discounts via Condition::define()
    • Finally, apply coupon-based discounts with applyCoupon($code) Example workflow:
    $total = Discountify::setItems($items)
        ->setGlobalDiscount(5) // e.g., seasonal site-wide sale
        ->applyCoupon('WELCOME10') // user coupon
        ->total();
    
  • Extensibility via events: Register listeners to tie discount actions to business logic:

    • DiscountAppliedEvent: Update analytics or trigger loyalty points
    • CouponAppliedEvent: Log redemption attempts or enforce usage limits via Redis
  • State management: Configure state_file_path for persistent coupon tracking (e.g., single-use or usage-limited coupons), especially useful in CLI or headless environments where sessions don’t exist.


Gotchas and Tips

  • Breaking change in v1.0+: define() and defineIf() now require a slug. Existing code without slugs will break — always provide it:

    // ❌ Invalid after v1.0
    Condition::define('condition_name', $callback, 10);
    
    // ✅ Valid
    Condition::define('slug-unique', $callback, 10);
    
  • skip field behavior: Set $skip = true on class-based conditions or pass 'skip' => true in Condition::add() — otherwise conditions are always evaluated, even if the callback returns false.

  • Field name mismatches: Default field names are 'price' and 'quantity'. If your items use 'amount' or 'qty', either update config/discountify.php or call setFields() per request — mixing defaults and custom fields causes silent calculation errors.

  • Discount precedence: The package applies all non-skipped conditions but does not prioritize or chain discounts additively — it uses the highest single discount among matching conditions. Double-check with totalDetailed() to verify which condition(s) applied.

  • Tax calculations: calculateTaxAmount(19, true) applies tax after discounts — ensure tax logic aligns with your legal/financial requirements. The default tax() method applies tax on the pre-discount subtotal.

  • Coupon persistence: By default, coupons are stored in a JSON file. For production, override the state_file_path to a database-backed driver (e.g., Redis or DB table) — especially for high-traffic apps or multi-server deployments where storage/app/discountify/coupons.json won’t be shared.

  • Debugging tip: Always use totalDetailed() during development to verify discount logic, applied rates, savings, and tax breakdown in one go.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport
twbs/bootstrap4
php-http/client-implementation
phpcr/phpcr-implementation
cucumber/gherkin-monorepo
haydenpierce/class-finder
psr/simple-cache-implementation
uri-template/tests