Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backend reports #56

Merged
merged 6 commits into from
Jul 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions server/src/main_modules/reports/models.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand All @@ -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};
module.exports = {UserReport,Report};
187 changes: 160 additions & 27 deletions server/src/main_modules/reports/report-routes.js
Original file line number Diff line number Diff line change
@@ -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);
}
})
}
63 changes: 34 additions & 29 deletions server/src/main_modules/transactions/transaction-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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) => {
Expand Down