Machine Coding Problem

E-commerce Cart & Checkout

macoAllcommercepromotion-enginetax-logic
Commonly Asked By:AmazonWalmartShopifyeBay

Requirements & System Scope

Functional Scope (In-Scope)

  • Snapshot Pricing Protection: Freezes the unit cost at the precise millisecond of cart insertion, mitigating mid-checkout pricing shifts.
  • Tiered Promotion Application: Supports standard percentage discounts and item-specific bulk triggers with custom priority weights.
  • Modular Tax & Shipping Estimators: Calculates location-based jurisdictional taxes and volumetric freight surcharges dynamically.
  • Session Cart Merge Pipelines: Safely reconciles anonymous guest cart items into authenticated user balances on login.

Explicit Boundaries (Out-of-Scope)

  • Direct ACH/Credit Payment Routing: Payments are captured via simulated gateway tokens without card validations or bank routing handshakes.
  • Physical Warehouse Fulfillment: Excludes packing logistics, barcode labels creation, and delivery vehicle dispatching.

Class Diagram & Entity Relationships

Structural blueprint tracking carts, orders, taxes, and promotional workflows:

Loading...
  • CartItem Instance: Stores immutable price snapshots explicitly, avoiding reliance on catalog queries during payment.
  • TaxCalculator Module: Maintains tax code structures and applies appropriate percentage factors dynamically.

Design Patterns & SOLID Principles

  • Strategy Pattern: Structures swappable tax models (e.g., standard flat VAT, state-by-state origin taxes, destination zip rules).
  • Command Pattern: Treats cart updates and coupons addition as discrete operations to facilitate rolling back checkout pipelines.
  • Single Responsibility Principle (SRP): Decouples shipping weight estimation from tax rules.

Core Execution Workflows

Checkout Pipeline & Cart Merging

  1. Two-Phase Checkout Stock Verification:
    1. Execute hard check comparing required line-item quantities with physical stock databases under thread safety.
    2. Deduct inventory numbers immediately upon positive match.
    3. Proceed with calculation steps: compute coupon percentage drops, calculate taxes, estimate shipping.
    4. If payment failures pop up, rollback deductions immediately.
  2. Anonymous Cart Merge:
    1. Extract cookie identifiers containing guest selection tables.
    2. Lookup registered user account profiles.
    3. Scan for product ID duplicates, aggregate quantities, and save back to user database.

Concurrency & Thread Safety Strategy

Enforcing atomic consistency under concurrent multi-user inventory checks:

  • Deadlock Prevention via Sorted Acquisition: Products are sorted by ID globally before grabbing individual reentrant locks, completely preventing circular lock waiting.
  • Atomic Counter Operations: Safely manages multi-core inventory deductions without thundering herd lock conflicts.

Complete Clean Code Blueprint

Production reference implementations demonstrating snapshot pricing, promotions, and atomic inventory checkout in Java and Python:

// ─── JAVA BLUEPRINT ──────────────────────────────────────────────────────────
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

enum TaxCategory {
    PHYSICAL_GOODS, DIGITAL_GOODS, FOOD, MEDICINE
}

class Product {
    private final String productId;
    private final String name;
    private final double weightKg;
    private final double basePrice;
    private volatile double livePrice;
    private final TaxCategory taxCategory;

    public Product(String productId, String name, double weightKg, double basePrice, TaxCategory taxCategory) {
        this.productId = productId;
        this.name = name;
        this.weightKg = weightKg;
        this.basePrice = basePrice;
        this.livePrice = basePrice;
        this.taxCategory = taxCategory;
    }

    public String getProductId() { return productId; }
    public String getName() { return name; }
    public double getWeightKg() { return weightKg; }
    public double getBasePrice() { return basePrice; }
    public double getLivePrice() { return livePrice; }
    public void setLivePrice(double livePrice) { this.livePrice = livePrice; }
    public TaxCategory getTaxCategory() { return taxCategory; }
}

class CartItem {
    private final String productId;
    private int quantity;
    private final double snapshotPrice; // Snapshot pricing pattern

    public CartItem(String productId, int quantity, double snapshotPrice) {
        this.productId = productId;
        this.quantity = quantity;
        this.snapshotPrice = snapshotPrice;
    }

    public String getProductId() { return productId; }
    public int getQuantity() { return quantity; }
    public void setQuantity(int quantity) { this.quantity = quantity; }
    public double getSnapshotPrice() { return snapshotPrice; }
}

class Cart {
    private final String cartId;
    private final String userId; // Null if guest/anonymous
    private final Map<String, CartItem> items = new ConcurrentHashMap<>();

    public Cart(String cartId, String userId) {
        this.cartId = cartId;
        this.userId = userId;
    }

    public String getCartId() { return cartId; }
    public String getUserId() { return userId; }
    public Collection<CartItem> getItems() { return items.values(); }

    public void addItem(Product product, int quantity) {
        items.compute(product.getProductId(), (id, currentItem) -> {
            if (currentItem == null) {
                return new CartItem(id, quantity, product.getLivePrice());
            } else {
                currentItem.setQuantity(currentItem.getQuantity() + quantity);
                return currentItem;
            }
        });
    }

    public void removeItem(String productId) {
        items.remove(productId);
    }
}

interface Promotion {
    String getCode();
    int getPriority(); // Prioritized application order
    double apply(double currentSubtotal, Collection<CartItem> items);
}

class PercentagePromo implements Promotion {
    private final String code;
    private final double discountPercentage;
    private final int priority;

    public PercentagePromo(String code, double discountPercentage, int priority) {
        this.code = code;
        this.discountPercentage = discountPercentage;
        this.priority = priority;
    }

    @Override
    public String getCode() { return code; }
    @Override
    public int getPriority() { return priority; }
    @Override
    public double apply(double currentSubtotal, Collection<CartItem> items) {
        return currentSubtotal * (1.0 - (discountPercentage / 100.0));
    }
}

class BulkDiscountPromo implements Promotion {
    private final String code;
    private final String targetProductId;
    private final int minQty;
    private final double discountPerItem;
    private final int priority;

    public BulkDiscountPromo(String code, String targetProductId, int minQty, double discountPerItem, int priority) {
        this.code = code;
        this.targetProductId = targetProductId;
        this.minQty = minQty;
        this.discountPerItem = discountPerItem;
        this.priority = priority;
    }

    @Override
    public String getCode() { return code; }
    @Override
    public int getPriority() { return priority; }
    @Override
    public double apply(double currentSubtotal, Collection<CartItem> items) {
        double totalDiscount = 0.0;
        for (CartItem item : items) {
            if (item.getProductId().equals(targetProductId) && item.getQuantity() >= minQty) {
                totalDiscount += item.getQuantity() * discountPerItem;
            }
        }
        return Math.max(0.0, currentSubtotal - totalDiscount);
    }
}

class TaxCalculator {
    private final Map<String, Map<TaxCategory, Double>> taxRules = new ConcurrentHashMap<>();

    public void addRule(String jurisdiction, TaxCategory category, double rate) {
        taxRules.computeIfAbsent(jurisdiction, k -> new ConcurrentHashMap<>()).put(category, rate);
    }

    public double calculateTax(String jurisdiction, TaxCategory category, double amount) {
        Map<TaxCategory, Double> rules = taxRules.get(jurisdiction);
        if (rules == null) return 0.0;
        double rate = rules.getOrDefault(category, 0.0);
        return amount * rate;
    }
}

class ShippingEstimator {
    public double estimateShipping(String destinationZip, double totalWeightKg) {
        double baseRate = 5.00;
        double weightSurcharge = totalWeightKg * 1.50;
        // Surcharge based on zip length
        double zipFactor = destinationZip.length() * 0.50;
        return baseRate + weightSurcharge + zipFactor;
    }
}

class OrderService {
    private final ConcurrentHashMap<String, AtomicInteger> inventory = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String, ReentrantLock> productLocks = new ConcurrentHashMap<>();

    public void addInventory(String productId, int qty) {
        inventory.put(productId, new AtomicInteger(qty));
    }

    // High performance fine-grained locking with deadlock prevention
    public String placeOrder(Cart cart, String jurisdiction, String promoCode, Map<String, Product> productCatalog, TaxCalculator taxCalculator, ShippingEstimator shippingEstimator, List<Promotion> activePromos) {
        if (cart.getItems().isEmpty()) {
            throw new IllegalArgumentException("Cart is empty.");
        }

        // Sort items by Product ID to guarantee a global lock acquisition order (prevents deadlocks)
        List<CartItem> sortedItems = cart.getItems().stream()
            .sorted(Comparator.comparing(CartItem::getProductId))
            .collect(Collectors.toList());

        List<ReentrantLock> locksToAcquire = new ArrayList<>();
        for (CartItem item : sortedItems) {
            locksToAcquire.add(productLocks.computeIfAbsent(item.getProductId(), k -> new ReentrantLock()));
        }

        // Acquire locks in sorted sequence
        for (ReentrantLock lock : locksToAcquire) {
            lock.lock();
        }

        try {
            // 1. Double-check stock under lock
            for (CartItem item : sortedItems) {
                AtomicInteger stock = inventory.get(item.getProductId());
                if (stock == null || stock.get() < item.getQuantity()) {
                    throw new IllegalStateException("Insufficient inventory for product: " + item.getProductId());
                }
            }

            // 2. Deduct inventory atomically
            for (CartItem item : sortedItems) {
                inventory.get(item.getProductId()).addAndGet(-item.getQuantity());
            }

            // 3. Compute Subtotal based on Snapshot prices
            double subtotal = 0.0;
            double totalWeight = 0.0;
            for (CartItem item : sortedItems) {
                subtotal += item.getSnapshotPrice() * item.getQuantity();
                Product p = productCatalog.get(item.getProductId());
                if (p != null) {
                    totalWeight += p.getWeightKg() * item.getQuantity();
                }
            }

            // 4. Apply promo
            double discountedSubtotal = subtotal;
            if (promoCode != null) {
                Optional<Promotion> promoOpt = activePromos.stream()
                    .filter(p -> p.getCode().equalsIgnoreCase(promoCode))
                    .findFirst();
                if (promoOpt.isPresent()) {
                    discountedSubtotal = promoOpt.get().apply(subtotal, cart.getItems());
                }
            }

            // 5. Compute Tax proportionally split across items
            double tax = 0.0;
            for (CartItem item : sortedItems) {
                Product p = productCatalog.get(item.getProductId());
                if (p != null) {
                    double itemShare = (item.getSnapshotPrice() * item.getQuantity()) / subtotal;
                    double itemDiscountedPrice = discountedSubtotal * itemShare;
                    tax += taxCalculator.calculateTax(jurisdiction, p.getTaxCategory(), itemDiscountedPrice);
                }
            }

            // 6. Estimating shipping
            double shipping = shippingEstimator.estimateShipping(jurisdiction, totalWeight);
            double grandTotal = discountedSubtotal + tax + shipping;

            return "ORDER-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase() + " | Paid: $" + Math.round(grandTotal * 100.0) / 100.0;
        } finally {
            // Release locks in reverse order
            for (int i = locksToAcquire.size() - 1; i >= 0; i--) {
                locksToAcquire.get(i).unlock();
            }
        }
    }

    // Merge Guest Cart into User's Auth Cart
    public void mergeCarts(Cart guestCart, Cart userCart) {
        for (CartItem item : guestCart.getItems()) {
            userCart.getItems().stream()
                .filter(x -> x.getProductId().equals(item.getProductId()))
                .findFirst()
                .ifPresentOrElse(
                    existing -> existing.setQuantity(existing.getQuantity() + item.getQuantity()),
                    () -> userCart.addItem(new Product(item.getProductId(), "Product", 0, item.getSnapshotPrice(), TaxCategory.PHYSICAL_GOODS), item.getQuantity())
                );
        }
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("=== STARTING E-COMMERCE CART & CHECKOUT SIMULATION ===");
        OrderService orderService = new OrderService();
        TaxCalculator taxCalculator = new TaxCalculator();
        ShippingEstimator shippingEstimator = new ShippingEstimator();

        // 1. Setup tax rates
        taxCalculator.addRule("NY-10001", TaxCategory.PHYSICAL_GOODS, 0.08); // 8%
        taxCalculator.addRule("NY-10001", TaxCategory.DIGITAL_GOODS, 0.04);  // 4%
        taxCalculator.addRule("NY-10001", TaxCategory.FOOD, 0.00);           // Tax free food

        // 2. Catalog & Inventory Setup
        Map<String, Product> catalog = new ConcurrentHashMap<>();
        Product ps5 = new Product("prod-ps5", "PlayStation 5", 4.5, 499.99, TaxCategory.PHYSICAL_GOODS);
        Product milk = new Product("prod-milk", "Organic Milk", 1.0, 3.49, TaxCategory.FOOD);
        
        catalog.put(ps5.getProductId(), ps5);
        catalog.put(milk.getProductId(), milk);

        orderService.addInventory("prod-ps5", 2); // Extremely hot item: Only 2 units!
        orderService.addInventory("prod-milk", 100);

        List<Promotion> promotions = List.of(
            new PercentagePromo("SAVE10", 10.0, 1),
            new BulkDiscountPromo("MILKLOVE", "prod-milk", 3, 0.50, 2)
        );

        // 3. Guest cart merge test
        System.out.println("--- Testing Anonymous Cart Merging ---");
        Cart guestCart = new Cart("cart-guest", null);
        guestCart.addItem(milk, 2);

        Cart userCart = new Cart("cart-user", "user-789");
        userCart.addItem(milk, 1);

        orderService.mergeCarts(guestCart, userCart);
        System.out.println("  User cart items after merging guest cart:");
        for (CartItem ci : userCart.getItems()) {
            System.out.println("    Product: " + ci.getProductId() + ", Qty: " + ci.getQuantity() + ", Snapshot Price: $" + ci.getSnapshotPrice());
        }

        // 4. Concurrency Checkout Test (High contention on limited stock)
        System.out.println("\n--- Concurrent Checkout Race ---");
        ExecutorService executor = Executors.newFixedThreadPool(5);
        CountDownLatch latch = new CountDownLatch(1);

        Runnable checkoutUserA = () -> {
            try {
                latch.await();
                Cart cartA = new Cart("cart-A", "user-A");
                cartA.addItem(ps5, 2); // Wants all remaining stock!
                String receipt = orderService.placeOrder(cartA, "NY-10001", "SAVE10", catalog, taxCalculator, shippingEstimator, promotions);
                System.out.println("  [SUCCESS] User A checkout succeeded: " + receipt);
            } catch (Exception e) {
                System.out.println("  [FAILED] User A checkout failed: " + e.getMessage());
            }
        };

        Runnable checkoutUserB = () -> {
            try {
                latch.await();
                Cart cartB = new Cart("cart-B", "user-B");
                cartB.addItem(ps5, 1); // Wants 1 unit
                String receipt = orderService.placeOrder(cartB, "NY-10001", "SAVE10", catalog, taxCalculator, shippingEstimator, promotions);
                System.out.println("  [SUCCESS] User B checkout succeeded: " + receipt);
            } catch (Exception e) {
                System.out.println("  [FAILED] User B checkout failed: " + e.getMessage());
            }
        };

        executor.submit(checkoutUserA);
        executor.submit(checkoutUserB);

        latch.countDown();
        executor.shutdown();
        executor.awaitTermination(2, TimeUnit.SECONDS);

        System.out.println("=== E-COMMERCE CART & CHECKOUT SIMULATION COMPLETE ===");
    }
}

πŸ’¬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...