Discount Codes: Implement Promo System
Learn: Discount Codes: Implement Promo System
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
- Promo Code Model - Store code metadata
- Validation Engine - Check eligibility and constraints
- Application Logic - Calculate and apply discounts
- 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