diff --git a/server/src/main_modules/reports/models.js b/server/src/main_modules/reports/models.js index 6ba7917..58dad69 100644 --- a/server/src/main_modules/reports/models.js +++ b/server/src/main_modules/reports/models.js @@ -5,12 +5,12 @@ const reportDB = mongoose.createConnection('mongodb://localhost/reportDB') const {r_string,r_bool,r_num,r_date} = require.main.require('./utils/types/mongo-required') const reportSchema = new mongoose.Schema({ - month: r_date, + monthYear: r_date, income: [transactionSchema], spendings: [transactionSchema], savings: r_num, goalsInProgress: [goalSchema], - recommendations: r_string + recommendations: String }) const userReportSchema = new mongoose.Schema({ @@ -19,6 +19,7 @@ const userReportSchema = new mongoose.Schema({ reports: {type: [reportSchema],default: []} }) +const Report = reportDB.model('Report', reportSchema); const UserReport = reportDB.model('UserReport', userReportSchema); -module.exports = {UserReport}; \ No newline at end of file +module.exports = {UserReport,Report}; \ No newline at end of file diff --git a/server/src/main_modules/reports/report-routes.js b/server/src/main_modules/reports/report-routes.js index 49c9070..b261955 100644 --- a/server/src/main_modules/reports/report-routes.js +++ b/server/src/main_modules/reports/report-routes.js @@ -1,37 +1,170 @@ const { authenticate } = require("../accounts/account-auth"); -const { UserReport } = require("./models"); +const { UserGoal } = require("../goals/models"); +const { UserTransaction } = require("../transactions/models"); +const { formatTransactions } = require("../transactions/transaction-store"); +const { UserReport, Report } = require("./models"); module.exports = function(app) { - app.route('/reports/:userId') - .get((req,res,next) => { - UserReport.findOne({userId: req.params.userId}, (err,userReport) => { - if (err || !userReport) return next(err); - return res.send(userReport); - }) - }) - .delete((req,res,next) => { - UserReport.findOneAndUpdate({userId: req.params.userId}, {reports: []}, {returnDocument: 'after'},(err,userReport) => { - if (err || !userReport) return next(err); - res.send(userReport); - }) + const getOngoingGoals = (goals, startOfNextMonth) => { + let ongoingGoals = goals.filter(goal => goal.deadline.getTime() > startOfNextMonth.getTime()); + return ongoingGoals; + } + const getMonthTransactions = (transactions, startOfNextMonth) => { + let monthTransactions = transactions.filter(transaction => transaction.date.getTime() < startOfNextMonth.getTime()); + return monthTransactions; + } + const getIncome = (transactions) => { + return transactions.filter(transaction => transaction.isIncome); + } + const getSpendings = (transactions) => { + return transactions.filter(transaction => !transaction.isIncome); + } + const getSavings = (income, spendings) => { + let totalIncome = 0; + income.forEach(inc => totalIncome += inc.amount); + + let totalSpendings = 0; + spendings.forEach(sp => totalSpendings += sp.amount); + + return totalIncome - totalSpendings; + } + + const getStartOfNextMonth = (date) => { + let nextMonth = new Date(date); + nextMonth.setHours(0, 0, 0, 0); + nextMonth.setMonth(nextMonth.getMonth()+1,1); + return nextMonth; + } + + const getReport = async (userId, monthYear) => { + const userReport = await UserReport.findOne({userId: userId}); + const foundReport = userReport.reports.find(report => { + const monthMatch = report.monthYear.getMonth() === monthYear.getMonth(); + const yearMatch = report.monthYear.getYear() === monthYear.getYear(); + return monthMatch && yearMatch; }) + return foundReport; + } - app.route('/reports/:userId/:reportId') - .get((req,res) => { - UserReport.findOne({userId: req.params.userId}, (err,userReport) => { - if (err || !userReport) return next(err); - const report = userReport.reports.filter(r => r.id === req.params.reportId)[0] - return res.send(report); - }) + app.route('/reports/users/:userId') + .get(async (req,res,next) => { + try { + const userReport = await UserReport.findOne({userId: req.params.userId}) + res.status(200).json(userReport) + } catch (err) { + console.log(err) + res.status(400).json(err); + } }) - .put((req,res) => { - UserReport.findOne({userId: req.params.userId}, (err,userReport) => { - if (err || !userReport) return next(err); - const report = userReport.reports.filter(r => r.id === req.params.reportId)[0] - return res.send(report); + .post(async (req,res) => { + const monthYear = new Date(req.query.monthYear); + try { + if (await getReport(req.params.userId,monthYear)) { + return res.status(400).end('report already exists'); + } + const startOfNextMonth = getStartOfNextMonth(monthYear); + const userGoal = await UserGoal.findOne({userId: req.params.userId}); + const ongoingGoals = getOngoingGoals(userGoal.goals, startOfNextMonth); + + const userTransaction = await UserTransaction.findOne({userId: req.params.userId}); + const lastMonthTransactions = getMonthTransactions(userTransaction.transactions,startOfNextMonth); + const income = formatTransactions(getIncome(lastMonthTransactions)); + const spendings = formatTransactions(getSpendings(lastMonthTransactions)); + const savings = getSavings(income,spendings); + + const newReport = new Report({ + monthYear:monthYear, income, spendings, savings, + goalsInProgress: ongoingGoals }) + + const userReport = await UserReport.findOneAndUpdate( + {userId: req.params.userId}, + {$push: {reports: newReport}}, + {returnDocument: 'after'} + ) + res.status(200).json(newReport) + } catch (err) { + console.log(err); + res.status(400).json(err); + } + }) + .put(async (req,res,next) => { //updates the userReport's accountantId + try { + const userReport = await UserReport.findOneAndUpdate( + {userId: req.params.userId}, + {accountantId: req.query.accountantId}, + {returnDocument: 'after'} + ) + res.status(200).json(userReport); + } catch (err) { + console.log(err) + res.status(400).json(err); + } }) - .delete((req,res) => { - res.send(req.params); + .delete(async (req,res,next) => { + try { + const userReport = await UserReport.findOneAndUpdate( + {userId: req.params.userId}, + {reports: []}, + {returnDocument: 'after'} + ); + res.status(200).json(userReport); + } catch (err) { + console.log(err) + res.status(400).json(err) + } + }) + + app.route('/reports/users/:userId/:reportId') + .get(async (req,res) => { + try { + const userReport = await UserReport.findOne({userId: req.params.userId}); + const report = userReport.reports.find(r => r.id === req.params.reportId); + res.status(200).json(report); + } catch(err) { + console.log(err) + res.status(400).json(err) + } }) + .put(async (req,res) => { //add/update recommendations + const {recommendations} = req.query; + try { + const userReport = await UserReport.findOneAndUpdate( + {$and:[{userId: req.params.userId}, { + reports: { $elemMatch: { _id: req.params.reportId }} + }]}, + {$set: {"reports.$.recommendations": recommendations}}, + {returnDocument: 'after'}, + ) + const report = userReport.reports.find(r => r.id === req.params.reportId) + res.status(200).json(report); + } catch (err) { + console.log(err) + res.status(400).json(err) + } + + }) + .delete(async (req,res) => { + try { + const userReport = await UserReport.findOneAndUpdate( + {userId: req.params.userId}, + {$pull: {reports: {_id: req.params.reportId}}}, + {returnDocument: 'after'}, + ) + res.status(200).end('report deleted'); + } catch (err) { + console.log(err) + res.status(400).json(err) + } + }) + + app.get('/reports/accountants/:accountantId', async (req,res) => { //fetch all userReports accessible by the acocuntant + try { + const userReports = await UserReport.find({accountantId: req.params.accountantId}); + res.status(200).json(userReports); + } catch (err) { + console.log(err) + res.status(400).json(err); + } + }) } \ No newline at end of file diff --git a/server/src/main_modules/transactions/transaction-store.js b/server/src/main_modules/transactions/transaction-store.js index 4122149..55b4f0a 100644 --- a/server/src/main_modules/transactions/transaction-store.js +++ b/server/src/main_modules/transactions/transaction-store.js @@ -4,21 +4,16 @@ const {UserTransaction} = require('./models'); const { getDefinedFields } = require.main.require('./utils/get-defined-fields'); const moment = require('moment'); -function parseTransactionData(fields) { - const {title,category,date,amount,isIncome,receipt} = fields; - const df = getDefinedFields({title,category,date,amount,isIncome,receipt}); - - const fieldsToUpdate = { - ...(df.title && {"transactions.$.title": df.title}), - ...(df.category && {"transactions.$.category": df.category}), - ...(df.date && {"transactions.$.date": df.date}), - ...(df.amount && {"transactions.$.amount": df.amount}), - ...(df.isIncome && {"transactions.$.isIncome": df.isIncome}), - ...(df.receipt && {"transactions.$.receipt": df.receipt}), +const formatTransactions = (transactions) => { + let formattedTransactions = []; + for (const t of transactions) { + // console.log(t); + formattedTransactions.push(formatTransaction(t)); } - return fieldsToUpdate; -} -function formatTransaction(transaction) { + return formattedTransactions; +}; + +const formatTransaction = (transaction) => { return { title: transaction.title, category: transaction.category, @@ -28,27 +23,37 @@ function formatTransaction(transaction) { _id: transaction._id, receipt: transaction.receipt } -} -function formatTransactions(userTransaction) { - let transactions = []; - for (const t of userTransaction.transactions) { - console.log(t); - transactions.push(formatTransaction(t)); +}; + +const parseTransactionData = (fields) => { + const {title,category,date,amount,isIncome,receipt} = fields; + const df = getDefinedFields({title,category,date,amount,isIncome,receipt}); + + const fieldsToUpdate = { + ...(df.title && {"transactions.$.title": df.title}), + ...(df.category && {"transactions.$.category": df.category}), + ...(df.date && {"transactions.$.date": df.date}), + ...(df.amount && {"transactions.$.amount": Math.abs(df.amount)}), + ...(df.isIncome && {"transactions.$.isIncome": df.isIncome}), + ...(df.receipt && {"transactions.$.receipt": df.receipt}), } - return transactions; -} + return fieldsToUpdate; +}; -function createUserTransaction(userId,transactions,callback) { - const newUserTransaction = new UserTransaction({userId,transactions: transactions}); - newUserTransaction.save((err,createdUserTransaction) => { - callback(err,createdUserTransaction) - }) -} module.exports = { + formatTransaction, + formatTransactions, + createUserTransaction: (userId,transactions,callback) => { + const newUserTransaction = new UserTransaction({userId,transactions: transactions}); + newUserTransaction.save((err,createdUserTransaction) => { + callback(err,createdUserTransaction) + }) + }, + //functions used by routes findTransactions: (accountId,callback) => { UserTransaction.findOne({userId: accountId},(err,usertransaction) => { if (!usertransaction) return callback(new Error('account not found'),null); - callback(err,formatTransactions(usertransaction)) + callback(err,formatTransactions(usertransaction.transactions)) }) }, findTransaction: (accountId,transactionId,callback) => {