Skip to main content

Command Palette

Search for a command to run...

Discount Codes: Implement Promo System

Learn: Discount Codes: Implement Promo System

Updated
8 min readView as Markdown
T

Welcome to TopperBlog! 👋

I'm a tech content creator passionate about helping developers level up their careers and master cutting-edge technologies.

🎯 What I Write About: • AI/ML Engineering & LLMs • Web3 & Blockchain Development
• System Design & Architecture • Interview Preparation (FAANG) • Freelancing & Remote Work • Modern Tech Stacks (Next.js, React, Rust, TypeScript) • Performance Optimization & Best Practices

💼 Mission: Sharing practical, actionable insights that accelerate your tech career and maximize your earning potential.

📚 15+ In-Depth Guides covering everything from earning $10k/month as a freelancer to cracking FAANG interviews.

🌐 Let's connect and grow together in this amazing tech journey!

#TechBlogger #SoftwareEngineering #CareerGrowth #WebDevelopment #AIEngineering

Discount Codes: Promo System Implementation

Problem

E-commerce platforms need robust discount code systems that:

  • Validate codes before applying discounts
  • Enforce expiry dates and usage limits
  • Prevent abuse and fraud
  • Track redemptions accurately
  • Support multiple discount types (percentage, fixed, tiered)

Solution Architecture

Core Components

  1. Promo Code Model - Store code metadata
  2. Validation Engine - Check eligibility and constraints
  3. Application Logic - Calculate and apply discounts
  4. Audit Trail - Track usage and redemptions

Key Features

  • Expiry Management: Date-based and usage-based expiration
  • Constraint Validation: Minimum purchase, user limits, category restrictions
  • Discount Types: Percentage, fixed amount, BOGO, tiered
  • Redemption Tracking: Per-user and global limits
  • Real-time Verification: Instant validation during checkout

Code Implementation

1. Database Schema

-- Promo codes table
CREATE TABLE promo_codes (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    code VARCHAR(50) UNIQUE NOT NULL,
    discount_type ENUM('percentage', 'fixed', 'bogo', 'tiered') NOT NULL,
    discount_value DECIMAL(10, 2) NOT NULL,
    max_discount DECIMAL(10, 2),
    min_purchase DECIMAL(10, 2) DEFAULT 0,
    max_uses INT,
    max_uses_per_user INT DEFAULT 1,
    valid_from TIMESTAMP NOT NULL,
    valid_until TIMESTAMP NOT NULL,
    is_active BOOLEAN DEFAULT TRUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Redemption history
CREATE TABLE redemptions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    promo_code_id UUID NOT NULL REFERENCES promo_codes(id),
    user_id UUID NOT NULL,
    order_id UUID NOT NULL,
    discount_amount DECIMAL(10, 2) NOT NULL,
    redeemed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(order_id)
);

-- Promo code restrictions
CREATE TABLE promo_restrictions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    promo_code_id UUID NOT NULL REFERENCES promo_codes(id),
    restriction_type ENUM('category', 'product', 'user_segment') NOT NULL,
    restriction_value VARCHAR(255) NOT NULL,
    is_inclusive BOOLEAN DEFAULT TRUE
);

CREATE INDEX idx_promo_code ON promo_codes(code);
CREATE INDEX idx_redemptions_user ON redemptions(user_id);
CREATE INDEX idx_redemptions_promo ON redemptions(promo_code_id);

2. TypeScript Models & Types

// types/promo.ts
export enum DiscountType {
  PERCENTAGE = 'percentage',
  FIXED = 'fixed',
  BOGO = 'bogo',
  TIERED = 'tiered'
}

export enum RestrictionType {
  CATEGORY = 'category',
  PRODUCT = 'product',
  USER_SEGMENT = 'user_segment'
}

export interface PromoCode {
  id: string;
  code: string;
  discountType: DiscountType;
  discountValue: number;
  maxDiscount?: number;
  minPurchase: number;
  maxUses?: number;
  maxUsesPerUser: number;
  validFrom: Date;
  validUntil: Date;
  isActive: boolean;
  createdAt: Date;
  updatedAt: Date;
}

export interface Redemption {
  id: string;
  promoCodeId: string;
  userId: string;
  orderId: string;
  discountAmount: number;
  redeemedAt: Date;
}

export interface PromoRestriction {
  id: string;
  promoCodeId: string;
  restrictionType: RestrictionType;
  restrictionValue: string;
  isInclusive: boolean;
}

export interface ValidationResult {
  isValid: boolean;
  error?: string;
  discountAmount?: number;
  promoCode?: PromoCode;
}

export interface CartItem {
  productId: string;
  category: string;
  quantity: number;
  price: number;
}

export interface Cart {
  items: CartItem[];
  subtotal: number;
  userId: string;
}

3. Validation Engine

// services/promoValidation.ts
import { Pool } from 'pg';
import { PromoCode, ValidationResult, Cart, Redemption } from '../types/promo';

export class PromoValidationService {
  constructor(private db: Pool) {}

  /**
   * Comprehensive promo code validation
   */
  async validatePromoCode(
    code: string,
    cart: Cart,
    userId: string
  ): Promise<ValidationResult> {
    try {
      // Step 1: Fetch promo code
      const promoCode = await this.getPromoCode(code);
      if (!promoCode) {
        return { isValid: false, error: 'Promo code not found' };
      }

      // Step 2: Check if active
      if (!promoCode.isActive) {
        return { isValid: false, error: 'Promo code is inactive' };
      }

      // Step 3: Check expiry
      const expiryCheck = this.checkExpiry(promoCode);
      if (!expiryCheck.isValid) {
        return expiryCheck;
      }

      // Step 4: Check usage limits
      const usageCheck = await this.checkUsageLimits(
        promoCode.id,
        userId
      );
      if (!usageCheck.isValid) {
        return usageCheck;
      }

      // Step 5: Check minimum purchase
      if (cart.subtotal < promoCode.minPurchase) {
        return {
          isValid: false,
          error: `Minimum purchase of $${promoCode.minPurchase} required`
        };
      }

      // Step 6: Check restrictions
      const restrictionCheck = await this.checkRestrictions(
        promoCode.id,
        cart
      );
      if (!restrictionCheck.isValid) {
        return restrictionCheck;
      }

      // Step 7: Calculate discount
      const discountAmount = await this.calculateDiscount(
        promoCode,
        cart
      );

      return {
        isValid: true,
        discountAmount,
        promoCode
      };
    } catch (error) {
      console.error('Promo validation error:', error);
      return { isValid: false, error: 'Validation failed' };
    }
  }

  /**
   * Fetch promo code from database
   */
  private async getPromoCode(code: string): Promise<PromoCode | null> {
    const result = await this.db.query(
      `SELECT * FROM promo_codes WHERE code = $1`,
      [code.toUpperCase()]
    );
    return result.rows[0] || null;
  }

  /**
   * Check if promo code has expired
   */
  private checkExpiry(promoCode: PromoCode): ValidationResult {
    const now = new Date();

    if (now < promoCode.validFrom) {
      return {
        isValid: false,
        error: `Promo code not yet active (starts ${promoCode.validFrom.toLocaleDateString()})`
      };
    }

    if (now > promoCode.validUntil) {
      return {
        isValid: false,
        error: 'Promo code has expired'
      };
    }

    return { isValid: true };
  }

  /**
   * Check global and per-user usage limits
   */
  private async checkUsageLimits(
    promoCodeId: string,
    userId: string
  ): Promise<ValidationResult> {
    const result = await this.db.query(
      `SELECT 
        COUNT(*) as total_uses,
        COUNT(CASE WHEN user_id = $2 THEN 1 END) as user_uses
       FROM redemptions 
       WHERE promo_code_id = $1`,
      [promoCodeId, userId]
    );

    const { total_uses, user_uses } = result.rows[0];
    const promoCode = await this.db.query(
      `SELECT max_uses, max_uses_per_user FROM promo_codes WHERE id = $1`,
      [promoCodeId]
    );

    const { max_uses, max_uses_per_user } = promoCode.rows[0];

    if (max_uses && total_uses >= max_uses) {
      return { isValid: false, error: 'Promo code usage limit reached' };
    }

    if (max_uses_per_user && user_uses >= max_uses_per_user) {
      return {
        isValid: false,
        error: 'You have already used this promo code'
      };
    }

    return { isValid: true };
  }

  /**
   * Check category and product restrictions
   */
  private async checkRestrictions(
    promoCodeId: string,
    cart: Cart
  ): Promise<ValidationResult> {
    const restrictions = await this.db.query(
      `SELECT * FROM promo_restrictions WHERE promo_code_id = $1`,
      [promoCodeId]
    );

    if (restrictions.rows.length === 0) {
      return { isValid: true }; // No restrictions
    }

    const categoryRestrictions = restrictions.rows.filter(
      r => r.restriction_type === 'category'
    );
    const productRestrictions = restrictions.rows.filter(
      r => r.restriction_type === 'product'
    );

    // Check category restrictions
    if (categoryRestrictions.length > 0) {
      const allowedCategories = categoryRestrictions
        .filter(r => r.is_inclusive)
        .map(r => r.restriction_value);
      const excludedCategories = categoryRestrictions
        .filter(r => !r.is_inclusive)
        .map(r => r.restriction_value);

      const cartHasValidCategory = cart.items.some(item => {
        const isAllowed = allowedCategories.length === 0 ||
          allowedCategories.includes(item.category);
        const isNotExcluded = !excludedCategories.includes(item.category);
        return isAllowed && isNotExcluded;
      });

      if (!cartHasValidCategory && allowedCategories.length > 0) {
        return {
          isValid: false,
          error: `Promo code only applies to: ${allowedCategories.join(', ')}`
        };
      }
    }

    return { isValid: true };
  }

  /**
   * Calculate discount amount based on type
   */
  private async calculateDiscount(
    promoCode: PromoCode,
    cart: Cart
  ): Promise<number> {
    let discount = 0;

    switch (promoCode.discountType) {
      case 'percentage':
        discount = (cart.subtotal * promoCode.discountValue) / 100;
        break;

      case 'fixed':
        discount = promoCode.discountValue;
        break;

      case 'tiered':
        discount = this.calculateTieredDiscount(promoCode, cart.subtotal);
        break;

      case 'bogo':
        discount = this.calculateBogoDiscount(promoCode, cart);
        break;
    }

    // Apply max discount cap if set
    if (promoCode.maxDiscount) {
      discount = Math.min(discount, promoCode.maxDiscount);
    }

    // Ensure discount doesn't exceed subtotal
    discount = Math.min(discount, cart.subtotal);

    return Math.round(discount * 100) / 100;
  }

  /**
   * Calculate tiered discount
   */
  private calculateTieredDiscount(
    promoCode: PromoCode,
    subtotal: number
  ): number {
    // Example: $0-50: 5%, $50-100: 10%, $100+: 15%
    const tiers = [
      { min: 0, max: 50, discount: 5 },
      { min: 50, max: 100, discount: 10 },
      { min: 100, max: Infinity, discount: 15 }
    ];

    const tier = tiers.find(t => subtotal >= t.min && subtotal < t.max);
    return tier ? (subtotal * tier.discount) / 100 : 0;
  }

  /**
   * Calculate BOGO (Buy One Get One) discount
   */
  private calculateBogoDiscount(
    promoCode: PromoCode,
    cart: Cart
  ): number {
    const totalItems = cart.items.reduce((sum, item) => sum + item.quantity, 0);
    const freeItems = Math.floor(totalItems / 2);
    const avgPrice = cart.subtotal / totalItems;
    return freeItems * avgPrice;
  }
}

4. Promo Code Service

// services/promoService.ts
export class PromoCodeService {
  constructor(private db: Pool) {}

  /**
   * Create new promo code
   */
  async createPromoCode(data: {
    code: string;
    discountType: DiscountType;
    discountValue: number;
    maxDiscount?: number;
    minPurchase?: number;
    maxUses?: number;
    maxUsesPerUser?: number;
    validFrom: Date;
    validUntil: Date;
  }): Promise<PromoCode> {
    const result = await this.db.query(
      `INSERT INTO promo_codes 
       (code, discount_type, discount_value, max_discount, min_purchase, 
        max_uses, max_uses_per_user, valid_from, valid_until)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
       RETURNING *`,
      [
        data.code.toUpperCase(),
        data.discountType,
        data.discountValue,
        data.maxDiscount || null,
        data.minPurchase || 0,
        data.maxUses || null,
        data.maxUsesPerUser || 1,
        data.validFrom,
        data.validUntil
      ]
    );

    return result.rows[0];
  }

  /**
   * Add restriction to promo code
   */
  async addRestriction(
    promoCodeId: string,
    restrictionType: RestrictionType,
    restrictionValue: string,
    isInclusive: boolean = true
  ): Promise<void> {
    await this.db.query(
      `INSERT INTO promo_restrictions 
       (promo_code_id, restriction_type, restriction_value, is_inclusive)
       VALUES ($1, $2, $3, $4)`,
      [promoCodeId, restrictionType, restrictionValue, isInclusive]
    );
  }

  /**
   * Record redemption
   */
  async recordRedemption(
    promoCodeId: string,
    userId: string,
    orderId: string,
    discountAmount: number
  ): Promise<Redemption> {
    const result = await this.db.query(
      `INSERT INTO redemptions 
       (promo_code_id, user_id, order_id, discount_amount)
       VALUES ($1, $2, $3, $4)
       RETURNING *`,
      [promoCodeId, userId, orderId, discountAmount]
    );

    return result.rows[0];
  }

  /**
   * Get promo code statistics
   */
  async getPromoStats(promoCodeId: string): Promise<{
    totalRedemptions: number;
    totalDiscountGiven: number;
    uniqueUsers: number;
    averageDiscount: number;
  }> {
    const result = await this.db.query(
      `SELECT 
        COUNT(*) as total_redemptions,
        SUM(discount_amount) as total_discount,
        COUNT(DISTINCT user_id) as unique_users,
        AVG(discount_amount) as avg_discount
       FROM redemptions 
       WHERE promo_code_id = $1`,
      [promoCodeId]
    );

    const row = result.rows[0];
    return {
      totalRedemptions: parseInt(row.total_redemptions),
      totalDiscountGiven: parseFloat(row.total_discount || 0),
      uniqueUsers: parseInt(row.unique_users),
      averageDiscount: parseFloat(row.avg_discount || 0)
    };
  }

  /**
   * Deactivate expired promo codes
   */
  async deactivateExpiredCodes(): Promise<number> {
    const result = await this.db.query(
      `UPDATE promo_codes 
       SET is_active = FALSE 
       WHERE valid_until < NOW() AND is_active = TRUE
       RETURNING id`
    );

    return result.rowCount;
  }
}

5. API Endpoints

```typescript // routes/promo.ts import express from 'express'; import { PromoValidationService } from '../services/promoValidation'; import { PromoCodeService } from '../services/promoService';

const router = express.Router();

/**

  • Validate promo code
  • POST /api/promo/validate */ router.post('/validate', async (req, res) => { try { const { code, cart, userId } = req.body;

    const validationService = new PromoValidationService(req.db); const result = await validationService.validatePromoCode( code, cart, userId );

    res.json(result); } catch (error) { res.status(500).json({ error: 'Validation failed' }); } });

/**

  • Apply promo code to order
  • POST /api/promo/apply */ router.post('/apply', async (req, res) => { try { const { code, orderId, userId, cart } = req.body;

    const validationService = new PromoValidationService(req.db); const validation = await validationService.validatePromoCode( code, cart, userId );

    if (!validation.isValid) { return res.status(400).json({ error: validation.error }); }

    const promoService = new PromoCodeService(req.db); const redemption = await promoService.recordRedemption( validation.promoCode!.id, userId, orderId, validation.discountAmount! );

    res.json({ success: true, discountAmount: validation.discountAmount, redemption }); } catch (error) { res.status(500).json({ error: 'Failed to apply promo code' }); } });

/**

  • Get promo code statistics
  • GET /api/promo/:promoCodeId/stats */ router.get('/:promoCodeId/stats', async (req, res) => { try { const promoService = new PromoCodeService(req.db); const stats = await promoService.getPromoStats(req.params.promoCodeId); res.json(stats); } catch (error) { res.status(500).json({ error: 'Failed to fetch stats' }); } });

/**

  • Create