first commit

This commit is contained in:
2026-03-10 12:43:27 +05:30
commit edb525eb80
79 changed files with 25644 additions and 0 deletions

586
CouponGuide.md Normal file
View File

@@ -0,0 +1,586 @@
# 🎟️ Complete Coupon System Guide
## 📦 What's Included
### Backend
1. **Admin Coupon Controller** - Full CRUD + Statistics
2. **User Coupon Controller** - Validation & Application
3. **Coupon Routes** - Both admin and user endpoints
### Frontend
1. **CouponApply Component** - For checkout page
2. **Available Coupons Modal** - Browse & select coupons
---
## 🚀 Setup Instructions
### Step 1: Backend Setup
#### 1.1 Add Controllers
Create two controller files:
**File 1:** `src/controllers/admin/couponController.js`
(Use the `couponController_Admin.js` file)
**File 2:** `src/controllers/couponController.js`
(Use the `couponController_User.js` file)
#### 1.2 Add Routes
Create: `src/routes/couponRoutes.js`
(Use the `couponRoutes.js` file)
#### 1.3 Register Routes in App
In your `server.js` or `app.js`:
```javascript
const couponRoutes = require('./routes/couponRoutes');
app.use('/api/coupons', couponRoutes);
```
---
### Step 2: Frontend Setup
#### 2.1 Create Component
Create: `src/components/CouponApply.jsx`
(Use the `CouponApply.jsx` file)
#### 2.2 Use in Checkout Page
```javascript
// pages/Checkout.jsx
import CouponApply from '../components/CouponApply';
import { useState } from 'react';
const Checkout = () => {
const [appliedCoupon, setAppliedCoupon] = useState(null);
const [orderTotal, setOrderTotal] = useState(2599);
const handleCouponApplied = (couponData) => {
setAppliedCoupon(couponData);
setOrderTotal(couponData.finalAmount);
};
const handleCouponRemoved = () => {
setAppliedCoupon(null);
setOrderTotal(2599); // Reset to original amount
};
return (
<div className="max-w-4xl mx-auto p-6">
{/* Cart Items */}
{/* Coupon Section */}
<CouponApply
orderAmount={orderTotal}
onCouponApplied={handleCouponApplied}
onCouponRemoved={handleCouponRemoved}
/>
{/* Order Summary */}
<div className="mt-6 bg-white p-6 rounded-lg">
<div className="flex justify-between mb-2">
<span>Subtotal:</span>
<span>2,599</span>
</div>
{appliedCoupon && (
<div className="flex justify-between mb-2 text-green-600">
<span>Discount ({appliedCoupon.couponCode}):</span>
<span>-{appliedCoupon.discountAmount}</span>
</div>
)}
<div className="flex justify-between text-xl font-bold border-t pt-2">
<span>Total:</span>
<span>{orderTotal.toLocaleString()}</span>
</div>
</div>
</div>
);
};
```
---
## 📡 API Endpoints
### Admin Endpoints
#### 1. Get All Coupons
```http
GET /api/coupons/admin?page=1&limit=20&isActive=true&type=PERCENTAGE&search=SAVE
Authorization: Bearer <admin_token>
```
**Response:**
```json
{
"status": true,
"message": "Coupons fetched successfully",
"data": {
"coupons": [
{
"id": "...",
"code": "SAVE20",
"description": "20% off on all items",
"type": "PERCENTAGE",
"value": 20,
"minOrderAmount": 1000,
"maxUses": 100,
"usedCount": 25,
"usagePercentage": 25,
"isExpired": false,
"remainingUses": 75,
"isActive": true,
"validFrom": "2024-01-01",
"validUntil": "2024-12-31"
}
],
"pagination": {
"total": 50,
"page": 1,
"limit": 20,
"pages": 3
}
}
}
```
#### 2. Create Coupon
```http
POST /api/coupons/admin
Authorization: Bearer <admin_token>
Content-Type: application/json
{
"code": "SAVE20",
"description": "Get 20% off on orders above 1000",
"type": "PERCENTAGE",
"value": 20,
"minOrderAmount": 1000,
"maxUses": 100,
"validFrom": "2024-01-01T00:00:00Z",
"validUntil": "2024-12-31T23:59:59Z",
"isActive": true
}
```
**Coupon Types:**
- `PERCENTAGE` - Percentage discount (e.g., 20%)
- `FIXED_AMOUNT` - Fixed amount off (e.g., ₹500)
- `FREE_SHIPPING` - Free shipping
#### 3. Update Coupon
```http
PUT /api/coupons/admin/:id
Authorization: Bearer <admin_token>
{
"value": 25,
"maxUses": 150
}
```
#### 4. Toggle Coupon Status
```http
PATCH /api/coupons/admin/:id/toggle
Authorization: Bearer <admin_token>
```
#### 5. Get Coupon Statistics
```http
GET /api/coupons/admin/stats
Authorization: Bearer <admin_token>
```
**Response:**
```json
{
"status": true,
"data": {
"totalCoupons": 50,
"activeCoupons": 35,
"expiredCoupons": 10,
"totalRedemptions": 2450,
"mostUsedCoupons": [...]
}
}
```
---
### User Endpoints
#### 1. Get Available Coupons
```http
GET /api/coupons/available?orderAmount=2599
```
**Response:**
```json
{
"status": true,
"data": [
{
"code": "SAVE20",
"description": "20% off on orders above ₹1000",
"type": "PERCENTAGE",
"value": 20,
"minOrderAmount": 1000,
"discountPreview": "20% OFF",
"remainingUses": 75,
"validUntil": "2024-12-31"
}
]
}
```
#### 2. Validate Coupon
```http
POST /api/coupons/validate
Content-Type: application/json
{
"code": "SAVE20",
"orderAmount": 2599
}
```
**Response:**
```json
{
"status": true,
"message": "Coupon applied successfully",
"data": {
"couponCode": "SAVE20",
"couponType": "PERCENTAGE",
"discountAmount": 519.80,
"originalAmount": 2599,
"finalAmount": 2079.20,
"savings": 519.80,
"savingsPercentage": 20
}
}
```
#### 3. Apply Coupon to Order
```http
POST /api/coupons/apply
Authorization: Bearer <token>
{
"couponCode": "SAVE20",
"orderId": "order_123"
}
```
#### 4. Remove Coupon
```http
POST /api/coupons/remove
Authorization: Bearer <token>
{
"orderId": "order_123"
}
```
---
## 💡 Usage Examples
### Example 1: Admin Creates Percentage Coupon
```javascript
const createCoupon = async () => {
const response = await axios.post(
'http://localhost:3000/api/coupons/admin',
{
code: 'WELCOME10',
description: 'Get 10% off on your first order',
type: 'PERCENTAGE',
value: 10,
minOrderAmount: 500,
maxUses: 1000,
validFrom: new Date(),
validUntil: new Date('2024-12-31'),
isActive: true,
},
{
headers: {
Authorization: `Bearer ${adminToken}`,
},
}
);
};
```
### Example 2: Admin Creates Fixed Amount Coupon
```javascript
{
code: 'FLAT500',
description: 'Flat ₹500 off on orders above ₹2000',
type: 'FIXED_AMOUNT',
value: 500,
minOrderAmount: 2000,
maxUses: 500,
validFrom: new Date(),
validUntil: new Date('2024-12-31'),
}
```
### Example 3: Admin Creates Free Shipping Coupon
```javascript
{
code: 'FREESHIP',
description: 'Free shipping on all orders',
type: 'FREE_SHIPPING',
value: 0,
minOrderAmount: null,
maxUses: null,
validFrom: new Date(),
validUntil: new Date('2024-12-31'),
}
```
### Example 4: Customer Applies Coupon
```javascript
// In your checkout component
const [discount, setDiscount] = useState(0);
<CouponApply
orderAmount={2599}
onCouponApplied={(data) => {
setDiscount(data.discountAmount);
console.log('Saved:', data.savings);
}}
onCouponRemoved={() => {
setDiscount(0);
}}
/>
```
---
## 🎨 Coupon Validation Rules
### Automatic Validations
1. **Active Status** - Must be active
2. **Date Range** - Must be within validFrom and validUntil
3. **Usage Limit** - Must have remaining uses
4. **Minimum Order** - Order amount must meet minimum requirement
5. **Code Uniqueness** - Code must be unique (enforced on creation)
### Error Messages
```
❌ "This coupon is no longer active"
❌ "This coupon is not yet valid"
❌ "This coupon has expired"
❌ "This coupon has reached its usage limit"
❌ "Minimum order amount of ₹1000 required"
❌ "Invalid coupon code"
```
---
## 📊 Coupon Types Explained
### 1. PERCENTAGE Discount
```
Order Amount: ₹2,599
Coupon: 20% OFF
Discount: ₹519.80
Final Amount: ₹2,079.20
```
### 2. FIXED_AMOUNT Discount
```
Order Amount: ₹2,599
Coupon: ₹500 OFF
Discount: ₹500
Final Amount: ₹2,099
```
### 3. FREE_SHIPPING
```
Order Amount: ₹2,599
Shipping: ₹50
Coupon: FREE SHIPPING
Discount: ₹50
Final Amount: ₹2,549
```
---
## 🔧 Advanced Features
### Feature 1: User-Specific Coupons
Add a `userId` field to restrict coupons:
```prisma
model Coupon {
// ... existing fields
userId String? // Optional: restrict to specific user
user User? @relation(fields: [userId], references: [id])
}
```
### Feature 2: Product-Specific Coupons
```prisma
model Coupon {
// ... existing fields
applicableCategories String[] // Only for these categories
applicableProducts String[] // Only for these products
}
```
### Feature 3: First-Time User Coupons
```javascript
// In validation logic
const userOrders = await prisma.order.count({
where: { userId, status: 'DELIVERED' }
});
if (coupon.firstTimeOnly && userOrders > 0) {
return { isValid: false, message: 'Coupon only for first-time users' };
}
```
---
## ✅ Testing Checklist
### Backend Testing
- [ ] Create percentage coupon
- [ ] Create fixed amount coupon
- [ ] Create free shipping coupon
- [ ] Validate active coupon
- [ ] Validate expired coupon
- [ ] Validate coupon below min order
- [ ] Validate coupon at usage limit
- [ ] Apply coupon to order
- [ ] Remove coupon from order
- [ ] Toggle coupon status
- [ ] Get coupon statistics
### Frontend Testing
- [ ] Apply valid coupon
- [ ] Apply invalid coupon
- [ ] View available coupons
- [ ] Remove applied coupon
- [ ] See discount in order summary
- [ ] Responsive design
- [ ] Loading states
- [ ] Error handling
---
## 🎯 Common Use Cases
### Use Case 1: Flash Sale
```javascript
{
code: 'FLASH50',
type: 'PERCENTAGE',
value: 50,
validFrom: new Date('2024-12-25T00:00:00'),
validUntil: new Date('2024-12-25T23:59:59'),
maxUses: 100
}
```
### Use Case 2: Minimum Purchase Promotion
```javascript
{
code: 'BUY1000GET200',
type: 'FIXED_AMOUNT',
value: 200,
minOrderAmount: 1000,
}
```
### Use Case 3: New Customer Welcome
```javascript
{
code: 'WELCOME',
type: 'PERCENTAGE',
value: 15,
description: 'Welcome! Get 15% off on your first order',
maxUses: null, // Unlimited
}
```
---
## 📈 Analytics & Reporting
Track coupon performance:
```javascript
// Get most successful coupons
const topCoupons = await prisma.coupon.findMany({
orderBy: { usedCount: 'desc' },
take: 10,
});
// Calculate total savings given
const totalSavings = await calculateTotalDiscounts();
// Conversion rate
const conversionRate = (usedCount / impressions) * 100;
```
---
**Your coupon system is ready! 🎉**
Full features:
✅ Admin CRUD operations
✅ Smart validation
✅ Multiple coupon types
✅ Usage tracking
✅ Statistics & analytics
✅ User-friendly UI
✅ Mobile responsive
1. User applies coupon "WELCOME10"
2. CouponApply validates coupon
3. Coupon data stored in state
{
couponCode: "WELCOME10",
discountAmount: 259.90,
...
}
4. User clicks "Place Order"
5. Frontend sends:
{
items: [...],
couponCode: "WELCOME10" ✅
}
6. Backend validates coupon again
7. Creates order in transaction:
- Creates order
- Increments coupon.usedCount ✅
8. Admin panel shows:
"usedCount": 1 ✅