Initial commit: teaching institution management API.
Express/MongoDB backend with JWT auth, RBAC, S3 uploads, notifications, and scheduled jobs.
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
// /components/payments/paymentService.js
|
||||
'use strict';
|
||||
|
||||
const Payment = require('./paymentModel');
|
||||
const AppError = require('../../utils/AppError');
|
||||
const eventEmitter = require('../../events/eventEmitter');
|
||||
const EVENT_NAMES = require('../../constants/eventNames');
|
||||
const { calculateMeta } = require('../../utils/pagination');
|
||||
|
||||
const getAllPayments = async (query) => {
|
||||
const page = parseInt(query.page) || 1;
|
||||
const limit = Math.min(parseInt(query.limit) || 20, 200);
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
const filter = {};
|
||||
if (query.userId) filter.user = query.userId;
|
||||
if (query.status) filter.status = query.status;
|
||||
|
||||
const [items, total] = await Promise.all([
|
||||
Payment.find(filter)
|
||||
.populate({ path: 'user', select: 'name surname' })
|
||||
.populate({ path: 'classes', select: 'name' })
|
||||
.populate({ path: 'course', select: 'title' })
|
||||
.skip(skip).limit(limit).sort({ createdAt: -1 }).lean(),
|
||||
Payment.countDocuments(filter)
|
||||
]);
|
||||
|
||||
return { data: items, meta: calculateMeta(total, page, limit) };
|
||||
};
|
||||
|
||||
const getPaymentById = async (id) => {
|
||||
const payment = await Payment.findById(id)
|
||||
.populate({ path: 'user', select: 'name surname phoneNumber' })
|
||||
.populate({ path: 'classes', select: 'name tuitionFee' })
|
||||
.populate({ path: 'course', select: 'title price' })
|
||||
.lean();
|
||||
if (!payment) throw new AppError('PAYMENT_NOT_FOUND');
|
||||
return payment;
|
||||
};
|
||||
|
||||
const createPayment = async (body, actorId = null) => {
|
||||
const payment = await Payment.create({
|
||||
...body,
|
||||
paidAmount: body.paidAmount || 0
|
||||
});
|
||||
|
||||
if (actorId) {
|
||||
eventEmitter.emit(EVENT_NAMES.PAYMENT_CREATED, {
|
||||
paymentId: payment._id,
|
||||
userId: payment.user,
|
||||
actorId
|
||||
});
|
||||
}
|
||||
|
||||
return getPaymentById(payment._id);
|
||||
};
|
||||
|
||||
const updatePayment = async (id, body, actorId = null) => {
|
||||
const payment = await Payment.findById(id);
|
||||
if (!payment) throw new AppError('PAYMENT_NOT_FOUND');
|
||||
|
||||
const previousStatus = payment.status;
|
||||
Object.assign(payment, body);
|
||||
await payment.save();
|
||||
|
||||
if (body.status && body.status !== previousStatus) {
|
||||
eventEmitter.emit(EVENT_NAMES.PAYMENT_STATUS_CHANGED, {
|
||||
paymentId: payment._id,
|
||||
userId: payment.user,
|
||||
oldStatus: previousStatus,
|
||||
newStatus: payment.status,
|
||||
actorId
|
||||
});
|
||||
}
|
||||
|
||||
return getPaymentById(payment._id);
|
||||
};
|
||||
|
||||
const deletePayment = async (id) => {
|
||||
const payment = await Payment.findByIdAndDelete(id);
|
||||
if (!payment) throw new AppError('PAYMENT_NOT_FOUND');
|
||||
return null;
|
||||
};
|
||||
|
||||
const searchPayments = async (query) => getAllPayments(query);
|
||||
|
||||
const addTransaction = async (paymentId, trxData, actorId = null) => {
|
||||
const payment = await Payment.findById(paymentId);
|
||||
if (!payment) throw new AppError('PAYMENT_NOT_FOUND');
|
||||
|
||||
payment.transactions.push({
|
||||
...trxData,
|
||||
recordedBy: actorId || trxData.recordedBy,
|
||||
date: trxData.date || new Date()
|
||||
});
|
||||
payment.paidAmount = payment.transactions.reduce((sum, t) => sum + (t.amount || 0), 0);
|
||||
await payment.save();
|
||||
return getPaymentById(paymentId);
|
||||
};
|
||||
|
||||
const getMyPayments = async (userId, query = {}) => {
|
||||
return getAllPayments({ ...query, userId });
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getAllPayments,
|
||||
getPaymentById,
|
||||
createPayment,
|
||||
updatePayment,
|
||||
deletePayment,
|
||||
searchPayments,
|
||||
addTransaction,
|
||||
getMyPayments,
|
||||
// Aliases for older call sites
|
||||
getAll: getAllPayments,
|
||||
getOne: getPaymentById,
|
||||
create: createPayment,
|
||||
recordTransaction: addTransaction,
|
||||
remove: deletePayment
|
||||
};
|
||||
Reference in New Issue
Block a user