From de0a91e9d892edfb5454aa722d653f613c87f3b0 Mon Sep 17 00:00:00 2001 From: Ikki Date: Sun, 10 Nov 2024 10:05:30 +0530 Subject: [PATCH] gift-card-controllers-and-functions --- .../sub-controllers/giftCardController.js | 311 ++++++++++++++++++ .../middleware/sub-ware/giftCardMiddleware.js | 28 ++ backend/model/shop/sub-model/GiftCard.js | 37 +++ backend/routes/sub-routes/giftCardRoutes.js | 38 +++ backend/services/sub-service/giftCardUtils.js | 54 +++ 5 files changed, 468 insertions(+) create mode 100644 backend/controllers/shop/sub-controllers/giftCardController.js create mode 100644 backend/middleware/sub-ware/giftCardMiddleware.js create mode 100644 backend/model/shop/sub-model/GiftCard.js create mode 100644 backend/routes/sub-routes/giftCardRoutes.js create mode 100644 backend/services/sub-service/giftCardUtils.js diff --git a/backend/controllers/shop/sub-controllers/giftCardController.js b/backend/controllers/shop/sub-controllers/giftCardController.js new file mode 100644 index 00000000..da430178 --- /dev/null +++ b/backend/controllers/shop/sub-controllers/giftCardController.js @@ -0,0 +1,311 @@ +// controllers/giftCardController.js +const GiftCard = require("../../../model/shop/sub-model/GiftCard"); + +// Create a new gift card +exports.createGiftCard = async (req, res) => { + try { + const { value, userId, expiryDate } = req.body; + + if (value <= 0) { + return res + .status(400) + .json({ message: "Gift card value must be greater than 0" }); + } + + const cardNumber = generateCardNumber(); + + const newGiftCard = new GiftCard({ + cardNumber, + value, + userId, + expiryDate, + }); + + await newGiftCard.save(); + res + .status(201) + .json({ + message: "Gift card created successfully", + giftCard: newGiftCard, + }); + } catch (err) { + res + .status(500) + .json({ message: "Error creating gift card", error: err.message }); + } +}; + +// Redeem a gift card +exports.redeemGiftCard = async (req, res) => { + try { + const { cardNumber } = req.body; + + const giftCard = await GiftCard.findOne({ cardNumber }); + + if (!giftCard) { + return res.status(404).json({ message: "Gift card not found" }); + } + + if (giftCard.status === "redeemed") { + return res.status(400).json({ message: "Gift card already redeemed" }); + } + + if (giftCard.status === "expired") { + return res.status(400).json({ message: "Gift card is expired" }); + } + + if (giftCard.expiryDate < new Date()) { + giftCard.status = "expired"; + await giftCard.save(); + return res.status(400).json({ message: "Gift card has expired" }); + } + + if (giftCard.value <= 0) { + return res.status(400).json({ message: "Gift card value is invalid" }); + } + + giftCard.status = "redeemed"; + await giftCard.save(); + + res + .status(200) + .json({ message: "Gift card redeemed successfully", giftCard }); + } catch (err) { + res + .status(500) + .json({ message: "Error redeeming gift card", error: err.message }); + } +}; + +// Fetch gift card details +exports.getGiftCardDetails = async (req, res) => { + try { + const { cardNumber } = req.params; + const giftCard = await GiftCard.findOne({ cardNumber }); + + if (!giftCard) { + return res.status(404).json({ message: "Gift card not found" }); + } + + res.status(200).json({ giftCard }); + } catch (err) { + res + .status(500) + .json({ + message: "Error fetching gift card details", + error: err.message, + }); + } +}; + +// Fetch all active gift cards for a user +exports.getUserGiftCards = async (req, res) => { + try { + const { userId } = req.params; + + const giftCards = await GiftCard.find({ userId, status: "active" }); + + if (giftCards.length === 0) { + return res + .status(404) + .json({ message: "No active gift cards found for this user" }); + } + + res.status(200).json({ giftCards }); + } catch (err) { + res + .status(500) + .json({ message: "Error fetching user gift cards", error: err.message }); + } +}; + +// Extend gift card expiration +exports.extendGiftCardExpiry = async (req, res) => { + try { + const { cardNumber, newExpiryDate } = req.body; + + const giftCard = await GiftCard.findOne({ cardNumber }); + + if (!giftCard) { + return res.status(404).json({ message: "Gift card not found" }); + } + + if (giftCard.status === "redeemed") { + return res + .status(400) + .json({ message: "Cannot extend expiry of redeemed card" }); + } + + if (giftCard.status === "expired") { + return res + .status(400) + .json({ message: "Cannot extend expiry of expired card" }); + } + + giftCard.expiryDate = new Date(newExpiryDate); + await giftCard.save(); + + res + .status(200) + .json({ message: "Gift card expiry extended successfully", giftCard }); + } catch (err) { + res + .status(500) + .json({ + message: "Error extending gift card expiry", + error: err.message, + }); + } +}; + +// Deactivate a gift card +exports.deactivateGiftCard = async (req, res) => { + try { + const { cardNumber } = req.body; + + const giftCard = await GiftCard.findOne({ cardNumber }); + + if (!giftCard) { + return res.status(404).json({ message: "Gift card not found" }); + } + + if (giftCard.status === "redeemed") { + return res + .status(400) + .json({ message: "Cannot deactivate redeemed card" }); + } + + giftCard.status = "expired"; + await giftCard.save(); + + res + .status(200) + .json({ message: "Gift card deactivated successfully", giftCard }); + } catch (err) { + res + .status(500) + .json({ message: "Error deactivating gift card", error: err.message }); + } +}; + +// Delete a gift card (force delete) +exports.deleteGiftCard = async (req, res) => { + try { + const { cardNumber } = req.body; + + const giftCard = await GiftCard.findOne({ cardNumber }); + + if (!giftCard) { + return res.status(404).json({ message: "Gift card not found" }); + } + + await giftCard.remove(); + res.status(200).json({ message: "Gift card deleted successfully" }); + } catch (err) { + res + .status(500) + .json({ message: "Error deleting gift card", error: err.message }); + } +}; + +// Reactivate an expired gift card +exports.reactivateGiftCard = async (req, res) => { + try { + const { cardNumber } = req.body; + + const giftCard = await GiftCard.findOne({ cardNumber }); + + if (!giftCard) { + return res.status(404).json({ message: "Gift card not found" }); + } + + if (giftCard.status === "redeemed") { + return res + .status(400) + .json({ message: "Cannot reactivate redeemed card" }); + } + + if (giftCard.status === "active") { + return res.status(400).json({ message: "Gift card is already active" }); + } + + giftCard.status = "active"; + giftCard.expiryDate = new Date(); // Reset the expiry date to a new default + await giftCard.save(); + + res + .status(200) + .json({ message: "Gift card reactivated successfully", giftCard }); + } catch (err) { + res + .status(500) + .json({ message: "Error reactivating gift card", error: err.message }); + } +}; + +// Update the value of a gift card +exports.updateGiftCardValue = async (req, res) => { + try { + const { cardNumber, newValue } = req.body; + + if (newValue <= 0) { + return res + .status(400) + .json({ message: "New value must be greater than 0" }); + } + + const giftCard = await GiftCard.findOne({ cardNumber }); + + if (!giftCard) { + return res.status(404).json({ message: "Gift card not found" }); + } + + giftCard.value = newValue; + await giftCard.save(); + + res + .status(200) + .json({ message: "Gift card value updated successfully", giftCard }); + } catch (err) { + res + .status(500) + .json({ message: "Error updating gift card value", error: err.message }); + } +}; + +// Search for gift cards by value range +exports.searchGiftCardsByValue = async (req, res) => { + try { + const { minValue, maxValue } = req.query; + + if (minValue <= 0 || maxValue <= 0) { + return res + .status(400) + .json({ message: "Value range must be greater than 0" }); + } + + const giftCards = await GiftCard.find({ + value: { $gte: minValue, $lte: maxValue }, + }); + + if (giftCards.length === 0) { + return res + .status(404) + .json({ message: "No gift cards found within this value range" }); + } + + res.status(200).json({ giftCards }); + } catch (err) { + res + .status(500) + .json({ + message: "Error searching gift cards by value", + error: err.message, + }); + } +}; + +// Helper function to generate a unique card number +const generateCardNumber = () => { + return `GC-${Math.random().toString(36).substr(2, 9).toUpperCase()}`; +}; diff --git a/backend/middleware/sub-ware/giftCardMiddleware.js b/backend/middleware/sub-ware/giftCardMiddleware.js new file mode 100644 index 00000000..3c7782fa --- /dev/null +++ b/backend/middleware/sub-ware/giftCardMiddleware.js @@ -0,0 +1,28 @@ +const GiftCard = require("../../model/shop/sub-model/GiftCard"); + +// Validate if gift card is active and not expired +exports.validateGiftCard = async (req, res, next) => { + const { cardNumber } = req.body; + + const giftCard = await GiftCard.findOne({ cardNumber }); + + if (!giftCard) { + return res.status(404).json({ message: "Gift card not found" }); + } + + if (giftCard.status === "redeemed") { + return res.status(400).json({ message: "Gift card already redeemed" }); + } + + if (giftCard.status === "expired") { + return res.status(400).json({ message: "Gift card has expired" }); + } + + if (giftCard.expiryDate < new Date()) { + giftCard.status = "expired"; + await giftCard.save(); + return res.status(400).json({ message: "Gift card has expired" }); + } + + next(); +}; diff --git a/backend/model/shop/sub-model/GiftCard.js b/backend/model/shop/sub-model/GiftCard.js new file mode 100644 index 00000000..e0c713bb --- /dev/null +++ b/backend/model/shop/sub-model/GiftCard.js @@ -0,0 +1,37 @@ + +const mongoose = require('mongoose'); + +const giftCardSchema = new mongoose.Schema({ + cardNumber: { + type: String, + required: true, + unique: true, + }, + value: { + type: Number, + required: true, + min: 0.01, + }, + status: { + type: String, + enum: ['active', 'redeemed', 'expired'], + default: 'active', + }, + userId: { + type: mongoose.Schema.Types.ObjectId, + ref: 'User', + required: true, + }, + expiryDate: { + type: Date, + required: true, + }, + createdAt: { + type: Date, + default: Date.now, + }, +}); + +const GiftCard = mongoose.model('GiftCard', giftCardSchema); + +module.exports = GiftCard; diff --git a/backend/routes/sub-routes/giftCardRoutes.js b/backend/routes/sub-routes/giftCardRoutes.js new file mode 100644 index 00000000..817e403f --- /dev/null +++ b/backend/routes/sub-routes/giftCardRoutes.js @@ -0,0 +1,38 @@ + +const express = require('express'); +const router = express.Router(); + +// Import the GiftCard Controller +const GiftCardController = require('../../controllers/shop/sub-controllers/giftCardController'); + +// Middleware to validate gift cards (to check status, expiry, etc.) +const validateGiftCard = require('../../middleware/sub-ware/giftCardMiddleware'); + +// Route to create a new gift card +router.post('/api/gift-cards', GiftCardController.createGiftCard); + +// Route to get details of a specific gift card by card number +router.get('/api/gift-cards/:cardNumber', GiftCardController.getGiftCardDetails); + +// Route to redeem a gift card by card number +router.post('/api/gift-cards/redeem', validateGiftCard, GiftCardController.redeemGiftCard); + +// Route to fetch all gift cards for a user (e.g., list of user's gift cards) +router.get('/api/gift-cards/user/:userId', GiftCardController.getUserGiftCards); + +// Route to search gift cards within a specific value range +router.get('/api/gift-cards/search', GiftCardController.searchGiftCardsByValue); + +// Route to delete a gift card (forceful deletion) +router.delete('/api/gift-cards/:cardNumber', GiftCardController.deleteGiftCard); + +// Route to deactivate (expire) a gift card before redemption +router.patch('/api/gift-cards/deactivate/:cardNumber', GiftCardController.deactivateGiftCard); + +// Route to fetch all gift cards (Admin-only route) +router.get('/api/gift-cards', GiftCardController.getAllGiftCards); + +// Route to get statistics on redeemed gift cards +router.get('/api/gift-cards/stats', GiftCardController.getGiftCardStats); + +module.exports = router; diff --git a/backend/services/sub-service/giftCardUtils.js b/backend/services/sub-service/giftCardUtils.js new file mode 100644 index 00000000..3e79cbc2 --- /dev/null +++ b/backend/services/sub-service/giftCardUtils.js @@ -0,0 +1,54 @@ +// Check if a gift card has expired based on its expiry date +exports.isExpired = (expiryDate) => { + const currentDate = new Date(); + return new Date(expiryDate) < currentDate; +}; + +// Format a gift card's value into a currency string (e.g., $100.00) +exports.formatGiftCardValue = (value) => { + return `$${value.toFixed(2)}`; +}; + +// Validate if the gift card value is positive +exports.isValidGiftCardValue = (value) => { + return value > 0; +}; + +// Helper function to generate a random expiration date (within 1 year) +exports.generateRandomExpiryDate = () => { + const currentDate = new Date(); + const randomMonths = Math.floor(Math.random() * 12) + 1; // Expiry in 1 to 12 months + currentDate.setMonth(currentDate.getMonth() + randomMonths); + return currentDate; +}; + +// Helper function to validate card number format (GC-XXXXXXX) +exports.isValidCardNumber = (cardNumber) => { + const regex = /^GC-[A-Z0-9]{9}$/; + return regex.test(cardNumber); +}; + +// Generate a random status for the card (active, redeemed, expired) +exports.generateRandomStatus = () => { + const statuses = ["active", "redeemed", "expired"]; + return statuses[Math.floor(Math.random() * statuses.length)]; +}; + +// Helper function to generate random user ID (for user association) +exports.generateUserId = () => { + return `USR-${Math.random().toString(36).substr(2, 7).toUpperCase()}`; +}; + +// Check if the gift card can be redeemed (it must be active and not expired) +exports.canRedeem = (giftCard) => { + if (giftCard.status !== "active") { + return false; + } + + return !this.isExpired(giftCard.expiryDate); +}; + +// Utility to get the current date in ISO string format +exports.getCurrentDate = () => { + return new Date().toISOString(); +};