Machine Coding Problem

Discount Engine

macoAllcommercestacking-policyatomic-usage
Commonly Asked By:AmazonWalmartPayPal

Requirements & Scope

Functional Specifications

  • Dynamic Promotion Applicability: Computes multi-level discounts including Percentage off, Flat Amount off, Free Shipping, and Buy One Get One (BOGO) deals.
  • Smart Stacking Policy Resolver: Supports resolving discounts with EXCLUSIVE rules (only best promo), ADDITIVE rules (stack all matching), and BEST_DEAL optimization.
  • Atomic Usage Safeguards: Locks global promotion pools and tracks per-user redemption limits atomically, ensuring thread safety and automatic recovery on transaction failure.

Operational Constraints

  • Thread Concurrency: Must handle thousands of checkouts per second without race conditions or negative limit overflows.
  • Atomic Payment Rollbacks: In the event of a checkout checkout failures, previously claimed usage counters must be perfectly rolled back.

Architecture & Entities

Object model mapping strategies, stacking guards, and concurrency limits:

Loading...
  • DiscountStrategy: Interface encapsulating target category checks and value computations.
  • UsageGuard: Atomic double-check-and-decrement layer to lock campaign capacities securely.

Design Patterns Applied

  • Strategy Pattern: Encapsulates discount logic per promotion type (BOGO, Percentage, Flat) dynamically, avoiding complex nested conditional switches.
  • Optimistic Atomic Operations: Leverages Compare-And-Swap (CAS) state primitives inside UsageGuard to bypass expensive system-level locks.
  • Saga/Transactional Recovery Pattern: Ensures promotional claims are queued sequentially and rolled back completely if downstream checkout steps fail.

Checkout & Rollback Workflow

Sequence of Operations

  1. Applicability Check: Scan all active campaigns. Discard expired rules or rule subsets missing minimum cart values.
  2. Resolve Stacking Rules: Apply stacking policies to resolve competing deals to a unified list.
  3. Atomic Locking: Try locking resources sequentially using CAS on globalUsageLimit counters.
  4. Payment Gateway Callback: Process credit/crypto card payment transaction.
  5. Commit or Rollback: On failure, trigger Saga rollbacks to increment all acquired counts immediately.

Clean Code Blueprint

Production reference implementations showcasing polymorphic discount engines, stacking resolution logic, and lock releases:

// ─── JAVA BLUEPRINT ──────────────────────────────────────────────────────────
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

enum PromotionType {
    PERCENTAGE, FLAT_OFF, FREE_SHIPPING, BOGO
}

enum StackingGroup {
    CART_TOTAL, ITEM_LEVEL, SHIPPING
}

enum StackingPolicy {
    EXCLUSIVE,    // Only one exclusive promotion can be applied (usually the best one)
    ADDITIVE,     // All matching promotions can stack
    BEST_DEAL     // Automatically calculate the single highest discount combination
}

class OrderItem {
    private final String itemId;
    private final String category;
    private final double unitPrice;
    private final int quantity;

    public OrderItem(String itemId, String category, double unitPrice, int quantity) {
        this.itemId = itemId;
        this.category = category;
        this.unitPrice = unitPrice;
        this.quantity = quantity;
    }

    public String getItemId() { return itemId; }
    public String getCategory() { return category; }
    public double getUnitPrice() { return unitPrice; }
    public int getQuantity() { return quantity; }
    public double getTotalPrice() { return unitPrice * quantity; }
}

class OrderContext {
    private final String orderId;
    private final String userId;
    private final List<OrderItem> items;
    private final double shippingCost;

    public OrderContext(String orderId, String userId, List<OrderItem> items, double shippingCost) {
        this.orderId = orderId;
        this.userId = userId;
        this.items = items;
        this.shippingCost = shippingCost;
    }

    public String getOrderId() { return orderId; }
    public String getUserId() { return userId; }
    public List<OrderItem> getItems() { return items; }
    public double getShippingCost() { return shippingCost; }
    
    public double getCartSubtotal() {
        return items.stream().mapToDouble(OrderItem::getTotalPrice).sum();
    }
}

class Promotion {
    private final String id;
    private final String code;
    private final PromotionType type;
    private final double value; // Percentage rate (e.g. 0.1) or Flat amount
    private final String targetCategory; // Optional category filter
    private final double minSpendRequirement;
    private final StackingGroup stackingGroup;
    private final boolean isExclusive;
    private final AtomicInteger globalUsageLimit;

    public Promotion(String id, String code, PromotionType type, double value, 
                     String targetCategory, double minSpend, StackingGroup group, 
                     boolean isExclusive, int limit) {
        this.id = id;
        this.code = code;
        this.type = type;
        this.value = value;
        this.targetCategory = targetCategory;
        this.minSpendRequirement = minSpend;
        this.stackingGroup = group;
        this.isExclusive = isExclusive;
        this.globalUsageLimit = new AtomicInteger(limit);
    }

    public String getId() { return id; }
    public String getCode() { return code; }
    public PromotionType getType() { return type; }
    public double getValue() { return value; }
    public String getTargetCategory() { return targetCategory; }
    public double getMinSpendRequirement() { return minSpendRequirement; }
    public StackingGroup getStackingGroup() { return stackingGroup; }
    public boolean isExclusive() { return isExclusive; }
    
    public int getRemainingLimit() { return globalUsageLimit.get(); }
    
    public boolean tryAcquireUsage() {
        while (true) {
            int current = globalUsageLimit.get();
            if (current <= 0) return false;
            if (globalUsageLimit.compareAndSet(current, current - 1)) {
                return true;
            }
        }
    }

    public void releaseUsage() {
        globalUsageLimit.incrementAndGet();
    }
}

class DiscountResult {
    private final Promotion promotion;
    private final double discountAmount;
    private final String description;

    public DiscountResult(Promotion promotion, double discountAmount, String description) {
        this.promotion = promotion;
        this.discountAmount = discountAmount;
        this.description = description;
    }

    public Promotion getPromotion() { return promotion; }
    public double getDiscountAmount() { return discountAmount; }
    public String getDescription() { return description; }
}

interface DiscountStrategy {
    DiscountResult calculateDiscount(OrderContext order, Promotion promo, double currentSubtotal);
}

class PercentageDiscountStrategy implements DiscountStrategy {
    @Override
    public DiscountResult calculateDiscount(OrderContext order, Promotion promo, double currentSubtotal) {
        if (currentSubtotal < promo.getMinSpendRequirement()) {
            return new DiscountResult(promo, 0.0, "Min spend requirement not met");
        }
        
        double discount = 0.0;
        if (promo.getTargetCategory() != null) {
            double categoryTotal = order.getItems().stream()
                .filter(i -> i.getCategory().equalsIgnoreCase(promo.getTargetCategory()))
                .mapToDouble(OrderItem::getTotalPrice).sum();
            discount = categoryTotal * promo.getValue();
        } else {
            discount = currentSubtotal * promo.getValue();
        }
        return new DiscountResult(promo, discount, String.format("%.0f%% discount applied", promo.getValue() * 100));
    }
}

class FlatDiscountStrategy implements DiscountStrategy {
    @Override
    public DiscountResult calculateDiscount(OrderContext order, Promotion promo, double currentSubtotal) {
        if (currentSubtotal < promo.getMinSpendRequirement()) {
            return new DiscountResult(promo, 0.0, "Min spend requirement not met");
        }
        double discount = Math.min(currentSubtotal, promo.getValue());
        return new DiscountResult(promo, discount, String.format("Flat $%.2f off total", promo.getValue()));
    }
}

class FreeShippingStrategy implements DiscountStrategy {
    @Override
    public DiscountResult calculateDiscount(OrderContext order, Promotion promo, double currentSubtotal) {
        if (currentSubtotal < promo.getMinSpendRequirement()) {
            return new DiscountResult(promo, 0.0, "Min spend requirement not met");
        }
        return new DiscountResult(promo, order.getShippingCost(), "Free Shipping Applied");
    }
}

class BogoStrategy implements DiscountStrategy {
    @Override
    public DiscountResult calculateDiscount(OrderContext order, Promotion promo, double currentSubtotal) {
        double discount = 0.0;
        for (OrderItem item : order.getItems()) {
            if (promo.getTargetCategory() == null || item.getCategory().equalsIgnoreCase(promo.getTargetCategory())) {
                int freePairs = item.getQuantity() / 2;
                discount += freePairs * item.getUnitPrice();
            }
        }
        return new DiscountResult(promo, discount, "BOGO Category Promotion Applied");
    }
}

class UsageGuard {
    private final Map<String, Set<String>> userPromoRedemptions = new ConcurrentHashMap<>();

    public boolean checkAndTrackUserLimit(String userId, String promoId) {
        Set<String> redeemed = userPromoRedemptions.computeIfAbsent(userId, k -> ConcurrentHashMap.newKeySet());
        return redeemed.add(promoId);
    }

    public void releaseUserRedemption(String userId, String promoId) {
        Set<String> redeemed = userPromoRedemptions.get(userId);
        if (redeemed != null) {
            redeemed.remove(promoId);
        }
    }
}

class DiscountEngine {
    private final Map<PromotionType, DiscountStrategy> strategies = new HashMap<>();
    private final UsageGuard usageGuard = new UsageGuard();

    public DiscountEngine() {
        strategies.put(PromotionType.PERCENTAGE, new PercentageDiscountStrategy());
        strategies.put(PromotionType.FLAT_OFF, new FlatDiscountStrategy());
        strategies.put(PromotionType.FREE_SHIPPING, new FreeShippingStrategy());
        strategies.put(PromotionType.BOGO, new BogoStrategy());
    }

    public List<DiscountResult> calculateBestDiscounts(OrderContext order, List<Promotion> activePromotions, StackingPolicy policy) {
        List<DiscountResult> applicable = new ArrayList<>();
        double subtotal = order.getCartSubtotal();

        for (Promotion promo : activePromotions) {
            if (promo.getRemainingLimit() <= 0) continue;
            DiscountStrategy strategy = strategies.get(promo.getType());
            if (strategy != null) {
                DiscountResult res = strategy.calculateDiscount(order, promo, subtotal);
                if (res.getDiscountAmount() > 0) {
                    applicable.add(res);
                }
            }
        }

        if (applicable.isEmpty()) return Collections.emptyList();

        List<DiscountResult> finalSelection = new ArrayList<>();

        if (policy == StackingPolicy.EXCLUSIVE) {
            applicable.stream()
                .max(Comparator.comparingDouble(DiscountResult::getDiscountAmount))
                .ifPresent(finalSelection::add);
        } 
        else if (policy == StackingPolicy.BEST_DEAL) {
            // Greedily select non-overlapping/compatible strategies or pick best single exclusive vs. stacked
            applicable.sort((a, b) -> Double.compare(b.getDiscountAmount(), a.getDiscountAmount()));
            for (DiscountResult res : applicable) {
                if (res.getPromotion().isExclusive() && finalSelection.isEmpty()) {
                    finalSelection.add(res);
                    break;
                }
                if (!res.getPromotion().isExclusive()) {
                    finalSelection.add(res);
                }
            }
        } 
        else if (policy == StackingPolicy.ADDITIVE) {
            // Apply all non-exclusives, or if exclusive exists, pick highest exclusive or stacked
            boolean hasExclusive = applicable.stream().anyMatch(r -> r.getPromotion().isExclusive());
            if (hasExclusive) {
                applicable.stream().filter(r -> !r.getPromotion().isExclusive()).forEach(finalSelection::add);
            } else {
                finalSelection.addAll(applicable);
            }
        }

        return finalSelection;
    }

    public boolean checkout(OrderContext order, List<DiscountResult> appliedDiscounts) {
        List<Promotion> acquiredPromos = new ArrayList<>();
        boolean success = true;

        try {
            for (DiscountResult res : appliedDiscounts) {
                Promotion promo = res.getPromotion();
                if (!usageGuard.checkAndTrackUserLimit(order.getUserId(), promo.getId())) {
                    success = false;
                    break;
                }
                if (!promo.tryAcquireUsage()) {
                    usageGuard.releaseUserRedemption(order.getUserId(), promo.getId());
                    success = false;
                    break;
                }
                acquiredPromos.add(promo);
            }

            if (!success) {
                rollback(order.getUserId(), acquiredPromos);
                return false;
            }

            boolean paymentSuccess = processPayment(order);
            if (!paymentSuccess) {
                throw new RuntimeException("Payment Failed");
            }
            return true;

        } catch (Exception e) {
            rollback(order.getUserId(), acquiredPromos);
            return false;
        }
    }

    private void rollback(String userId, List<Promotion> acquiredPromos) {
        for (Promotion acquired : acquiredPromos) {
            acquired.releaseUsage();
            usageGuard.releaseUserRedemption(userId, acquired.getId());
        }
    }

    private boolean processPayment(OrderContext order) {
        return true; 
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("=== JAVA DISCOUNT ENGINE SIMULATION ===");
        DiscountEngine engine = new DiscountEngine();

        List<OrderItem> items = Arrays.asList(
            new OrderItem("item1", "Electronics", 200.0, 1),
            new OrderItem("item2", "Apparel", 50.0, 2)
        );
        OrderContext order = new OrderContext("ORD123", "USER_A", items, 15.0);

        List<Promotion> promos = Arrays.asList(
            new Promotion("P1", "ELEC10", PromotionType.PERCENTAGE, 0.1, "Electronics", 100.0, StackingGroup.ITEM_LEVEL, false, 5),
            new Promotion("P2", "FLAT20", PromotionType.FLAT_OFF, 20.0, null, 150.0, StackingGroup.CART_TOTAL, false, 10),
            new Promotion("P3", "FREESHIP", PromotionType.FREE_SHIPPING, 0.0, null, 50.0, StackingGroup.SHIPPING, false, 2)
        );

        System.out.println("Calculating best discounts under StackingPolicy.BEST_DEAL...");
        List<DiscountResult> applied = engine.calculateBestDiscounts(order, promos, StackingPolicy.BEST_DEAL);

        for (DiscountResult discount : applied) {
            System.out.println(" - Applied promo: " + discount.getPromotion().getCode() + " | Discount: $" + discount.getDiscountAmount() + " (" + discount.getDescription() + ")");
        }

        boolean checkoutSuccess = engine.checkout(order, applied);
        System.out.println("Checkout status: " + (checkoutSuccess ? "SUCCESS" : "FAILED"));
        System.out.println("Remaining limits: P1=" + promos.get(0).getRemainingLimit() + ", P2=" + promos.get(1).getRemainingLimit());
        System.out.println("=== END OF JAVA SIMULATION ===");
    }
}

Interactive Simulator

❖Atomic Discount & Promotion Engine

Multi-rule stacking policies, automatic best-deal calculation, and thread-safe Saga checkout rollbacks.

πŸ›οΈ Add Mock Items to Order

πŸ›’ Cart Item Registry

Premium Wireless Earbuds
$120 each β€’ Subtotal: $120.00
1
Heavyweight Cotton Hoodie
$80 each β€’ Subtotal: $160.00
2

βš™οΈ Stacking Policy Configuration

🎟️ Global Campaign Stock (Atomic)

WELCOME20(20%)
18 / 20 left
SUPERFLAT(3000%)
8 / 10 left
FREE_SHIP(Free Ship)
4 / 5 left
BOGO_APPAREL(BOGO)
6 / 8 left
VIP_EXCLUSIVE(35%)
5 / 5 left

πŸ’³ Invoice Summary

Cart Subtotal:$280.00
Est. Standard Shipping:$15.00
βœ“ Promo [WELCOME20] applied:-$56.00
βœ“ Promo [SUPERFLAT] applied:-$30.00
βœ“ Promo [FREE_SHIP] applied:-$15.00
βœ“ Promo [BOGO_APPAREL] applied:-$80.00
Grand Total:$114.00
πŸ–³ Atomic Locks & Saga State Log
[13:50:00] Discount engine initialized with 5 active policies.

πŸ’¬Review

Help Us Improve

How helpful was this walkthrough?

Click a star to rate. We actively use this feedback to refine and update our system design content.

Placeholder
Optional but highly appreciated!

Discussion

Share your thoughts, ask questions, or help others.

Loading comments...