-
Notifications
You must be signed in to change notification settings - Fork 117
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #954 from IkkiOcean/backend-schema-10
Add Payment Schema, Controllers, and Admin-Restricted Management Routes for Backend
- Loading branch information
Showing
5 changed files
with
298 additions
and
0 deletions.
There are no files selected for viewing
44 changes: 44 additions & 0 deletions
44
backend/controllers/shop/sub-controllers/adminController.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
const Payment = require("../models/payment"); | ||
const Invoice = require("../models/invoice"); | ||
|
||
// Admin view all payments | ||
const adminViewPayments = async (req, res) => { | ||
try { | ||
const payments = await Payment.find() | ||
.populate("orderId") | ||
.populate("userId"); | ||
res.status(200).json(payments); | ||
} catch (error) { | ||
res.status(500).json({ message: error.message }); | ||
} | ||
}; | ||
|
||
// Admin view all invoices | ||
const adminViewInvoices = async (req, res) => { | ||
try { | ||
const invoices = await Invoice.find() | ||
.populate("orderId") | ||
.populate("userId"); | ||
res.status(200).json(invoices); | ||
} catch (error) { | ||
res.status(500).json({ message: error.message }); | ||
} | ||
}; | ||
|
||
// Admin filter/sort payments | ||
const adminFilterPayments = async (req, res) => { | ||
const { status, startDate, endDate } = req.query; | ||
const filters = {}; | ||
if (status) filters.paymentStatus = status; | ||
if (startDate && endDate) | ||
filters.paymentDate = { $gte: startDate, $lte: endDate }; | ||
|
||
try { | ||
const payments = await Payment.find(filters); | ||
res.status(200).json(payments); | ||
} catch (error) { | ||
res.status(500).json({ message: error.message }); | ||
} | ||
}; | ||
|
||
module.exports = { adminViewPayments, adminViewInvoices, adminFilterPayments }; |
161 changes: 161 additions & 0 deletions
161
backend/controllers/shop/sub-controllers/paymentController.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
const Payment = require("../models/payment"); | ||
|
||
// Retrieve all payments | ||
const getAllPayments = async (req, res) => { | ||
try { | ||
const payments = await Payment.find(); | ||
res.status(200).json(payments); | ||
} catch (error) { | ||
res.status(500).json({ message: error.message }); | ||
} | ||
}; | ||
|
||
// Retrieve payment by ID | ||
const getPaymentById = async (req, res) => { | ||
try { | ||
const payment = await Payment.findById(req.params.id); | ||
if (!payment) return res.status(404).json({ message: "Payment not found" }); | ||
res.status(200).json(payment); | ||
} catch (error) { | ||
res.status(500).json({ message: error.message }); | ||
} | ||
}; | ||
|
||
// Create a new payment | ||
const createPayment = async (req, res) => { | ||
const { orderId, userId, amount, paymentMethod, transactionId } = req.body; | ||
|
||
const newPayment = new Payment({ | ||
paymentId: `PAY${Date.now()}`, | ||
orderId, | ||
userId, | ||
amount, | ||
paymentMethod, | ||
transactionId, | ||
}); | ||
|
||
try { | ||
const payment = await newPayment.save(); | ||
res.status(201).json(payment); | ||
} catch (error) { | ||
res.status(400).json({ message: error.message }); | ||
} | ||
}; | ||
|
||
// Update payment status | ||
const updatePaymentStatus = async (req, res) => { | ||
const { paymentStatus } = req.body; | ||
try { | ||
const payment = await Payment.findByIdAndUpdate( | ||
req.params.id, | ||
{ paymentStatus }, | ||
{ new: true } | ||
); | ||
if (!payment) return res.status(404).json({ message: "Payment not found" }); | ||
res.status(200).json(payment); | ||
} catch (error) { | ||
res.status(500).json({ message: error.message }); | ||
} | ||
}; | ||
const Payment = require("../models/payment"); | ||
|
||
// Update Payment Method | ||
const updatePaymentMethod = async (req, res) => { | ||
const { paymentMethod } = req.body; | ||
try { | ||
if (!["Credit Card", "PayPal", "Bank Transfer"].includes(paymentMethod)) { | ||
return res.status(400).json({ message: "Invalid payment method" }); | ||
} | ||
const payment = await Payment.findByIdAndUpdate( | ||
req.params.id, | ||
{ paymentMethod }, | ||
{ new: true } | ||
); | ||
if (!payment) return res.status(404).json({ message: "Payment not found" }); | ||
res.status(200).json(payment); | ||
} catch (error) { | ||
res.status(500).json({ message: error.message }); | ||
} | ||
}; | ||
|
||
// Retrieve Payments by Date Range | ||
const getPaymentsByDateRange = async (req, res) => { | ||
const { startDate, endDate } = req.query; | ||
try { | ||
const payments = await Payment.find({ | ||
paymentDate: { | ||
$gte: new Date(startDate), | ||
$lte: new Date(endDate), | ||
}, | ||
}); | ||
if (!payments.length) | ||
return res | ||
.status(404) | ||
.json({ message: "No payments found in this date range" }); | ||
res.status(200).json(payments); | ||
} catch (error) { | ||
res.status(500).json({ message: error.message }); | ||
} | ||
}; | ||
|
||
// Retrieve Payments by Amount Range | ||
const getPaymentsByAmountRange = async (req, res) => { | ||
const { minAmount, maxAmount } = req.query; | ||
try { | ||
const payments = await Payment.find({ | ||
amount: { $gte: minAmount, $lte: maxAmount }, | ||
}); | ||
if (!payments.length) | ||
return res | ||
.status(404) | ||
.json({ message: "No payments found in this amount range" }); | ||
res.status(200).json(payments); | ||
} catch (error) { | ||
res.status(500).json({ message: error.message }); | ||
} | ||
}; | ||
|
||
// Retrieve Payment by Transaction ID | ||
const getPaymentByTransactionId = async (req, res) => { | ||
try { | ||
const payment = await Payment.findOne({ | ||
transactionId: req.params.transactionId, | ||
}); | ||
if (!payment) | ||
return res | ||
.status(404) | ||
.json({ message: "Payment not found with this transaction ID" }); | ||
res.status(200).json(payment); | ||
} catch (error) { | ||
res.status(500).json({ message: error.message }); | ||
} | ||
}; | ||
|
||
// Count Payments by Status | ||
const countPaymentsByStatus = async (req, res) => { | ||
try { | ||
const counts = await Payment.aggregate([ | ||
{ | ||
$group: { | ||
_id: "$paymentStatus", | ||
count: { $sum: 1 }, | ||
}, | ||
}, | ||
]); | ||
res.status(200).json(counts); | ||
} catch (error) { | ||
res.status(500).json({ message: error.message }); | ||
} | ||
}; | ||
|
||
module.exports = { | ||
getAllPayments, | ||
getPaymentById, | ||
createPayment, | ||
updatePaymentStatus, | ||
updatePaymentMethod, | ||
getPaymentsByDateRange, | ||
getPaymentsByAmountRange, | ||
getPaymentByTransactionId, | ||
countPaymentsByStatus, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
const validatePaymentData = (req, res, next) => { | ||
const { orderId, userId, amount, paymentMethod, transactionId } = req.body; | ||
|
||
if (!orderId || !userId || !amount || !paymentMethod || !transactionId) { | ||
return res | ||
.status(400) | ||
.json({ message: "All fields are required for payment" }); | ||
} | ||
|
||
next(); | ||
}; | ||
|
||
const validateInvoiceData = (req, res, next) => { | ||
const { orderId, userId, amount, dueDate, paymentId } = req.body; | ||
|
||
if (!orderId || !userId || !amount || !dueDate || !paymentId) { | ||
return res | ||
.status(400) | ||
.json({ message: "All fields are required for invoice" }); | ||
} | ||
|
||
next(); | ||
}; | ||
|
||
module.exports = { validatePaymentData, validateInvoiceData }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
const mongoose = require("mongoose"); | ||
|
||
const paymentSchema = new mongoose.Schema( | ||
{ | ||
paymentId: { type: String, required: true, unique: true }, | ||
orderId: { | ||
type: mongoose.Schema.Types.ObjectId, | ||
ref: "Order", | ||
required: true, | ||
}, | ||
userId: { | ||
type: mongoose.Schema.Types.ObjectId, | ||
ref: "User", | ||
required: true, | ||
}, | ||
amount: { type: Number, required: true }, | ||
paymentMethod: { | ||
type: String, | ||
enum: ["Credit Card", "PayPal", "Bank Transfer"], | ||
required: true, | ||
}, | ||
paymentStatus: { | ||
type: String, | ||
default: "Pending", | ||
enum: ["Pending", "Completed", "Failed"], | ||
}, | ||
paymentDate: { type: Date, default: Date.now }, | ||
transactionId: { type: String, required: true }, | ||
}, | ||
{ timestamps: true } | ||
); | ||
|
||
const Payment = mongoose.model("Payment", paymentSchema); | ||
module.exports = Payment; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
const express = require("express"); | ||
const router = express.Router(); | ||
const { | ||
getAllPayments, | ||
getPaymentById, | ||
getPaymentsByUserId, | ||
getPaymentsByStatus, | ||
createPayment, | ||
updatePaymentStatus, | ||
deletePayment, | ||
updatePaymentMethod, | ||
getPaymentsByDateRange, | ||
getPaymentsByAmountRange, | ||
getPaymentByTransactionId, | ||
countPaymentsByStatus, | ||
} = require("../controllers/paymentController"); | ||
|
||
// Payment routes | ||
router.get("/", getAllPayments); // Retrieve all payments | ||
router.get("/:id", getPaymentById); // Retrieve payment by ID | ||
router.get("/user/:userId", getPaymentsByUserId); // Retrieve payments by User ID | ||
router.get("/status/:status", getPaymentsByStatus); // Retrieve payments by Status | ||
router.post("/", createPayment); // Create a new payment | ||
router.patch("/:id/status", updatePaymentStatus); // Update payment status | ||
router.patch("/:id/method", updatePaymentMethod); // Update payment method | ||
router.delete("/:id", deletePayment); // Delete payment | ||
|
||
// Additional routes for edge cases | ||
router.get("/date-range", getPaymentsByDateRange); // Retrieve payments by date range | ||
router.get("/amount-range", getPaymentsByAmountRange); // Retrieve payments by amount range | ||
router.get("/transaction/:transactionId", getPaymentByTransactionId); // Retrieve payment by transaction ID | ||
router.get("/count/status", countPaymentsByStatus); // Count payments by status | ||
|
||
module.exports = router; |