Skip to content

Commit

Permalink
started working on building expense diary feature api
Browse files Browse the repository at this point in the history
  • Loading branch information
abhiraj-ku committed Nov 23, 2024
1 parent ca6f023 commit 61717cb
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"printWidth": 100,
"printWidth": 110,
"tabWidth": 2,
"useTabs": false,
"semi": true,
Expand Down
2 changes: 1 addition & 1 deletion src/controllers/groupController.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ module.exports.joinGroup = async (req, res) => {
if (err) {
reject(err);
} else {
res(data);
resolve(data);
}
});
});
Expand Down
112 changes: 112 additions & 0 deletions src/controllers/journalController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
const { JournalTopic, Expense } = require('../models/journalModel');
const User = require('../models/userModel');
const Group = require('../models/groupModel');

// Get all expenses controller(API)
module.exports.getAllExpense = async (req, res) => {
const { topicId, showSettled } = req.query;
try {
const query = {};
if (topicId && topicId !== 'all') query.topicId = topicId;
if (showSettled !== true) query.status = 'pending';

const expense = await Expense.find(query)
.populate('paidBy', 'name email')
.populate('splitBetween', 'name email')
.sort({ date: -1 });

res.status(200).json(expense);
} catch (error) {
res.status(500).json({ error: 'Failed to fetch expenses' });
}
};

module.exports.newExpense = async (req, res) => {
const { description, amount, paidBy, paidFor, topicId, groupId } = req.body;
if (!amount || !paidBy || !paidFor || !groupId) {
return res.status(400).json({ error: 'All required fields must be provided' });
}

if (isNaN(amount) || parseFloat(amount) <= 0) {
return res.status(400).json({ error: 'Amount must be a positive number' });
}

if (!mongoose.Types.ObjectId.isValid(paidBy) || !mongoose.Types.ObjectId.isValid(groupId)) {
return res.status(400).json({ error: 'Invalid paidBy or groupId format' });
}

if (!mongoose.Types.ObjectId.isValid(paidFor)) {
return res.status(400).json({ error: 'Invalid paidFor format' });
}

if (topicId && !mongoose.Types.ObjectId.isValid(topicId)) {
return res.status(400).json({ error: 'Invalid topicId format' });
}

try {
const group = await Group.findById(groupId);
if (!group) {
return res.status(404).json({ error: 'Group not found' });
}

if (!group.members.includes(req.user._id.toString())) {
return res.status(403).json({ error: 'You are not authorized to add an expense to this group' });
}

const expense = await Expense.create({
groupId,
description,
amount: parseInt(amount),
paidBy,
createdBy: req.user._id,
splitBetween: [paidFor],
splitType: 'custom',
customAmounts: { [paidFor]: parseFloat(amount) },
date: new Date9(),
topicId,
status: 'pending',
});

await expense.save();

//populate the expense
const populatedExpense = await Expense.findById(expense._id)
.populate('paidBy', 'name email')
.populate('splitBetween', 'name email')
.populate('topicId', 'name description')
.populate('groupId', 'name');

res.status(201).json(populatedExpense);
} catch (error) {
console.error('Error creating expense:', error.message);
res.status(500).json({ error: 'Failed to create expense' });
}
};

//update expense

module.exports.updateExpense = async (req, res) => {
const { id } = req.params;
const { description, amount, paidBy, paidFor, topicId } = req.body;

// Step 1: Validate Inputs
if (!description || !amount || !paidBy || !paidFor) {
return res.status(400).json({ error: 'All required fields must be provided' });
}

if (isNaN(amount) || parseFloat(amount) <= 0) {
return res.status(400).json({ error: 'Amount must be a positive number' });
}

if (
!mongoose.Types.ObjectId.isValid(id) ||
!mongoose.Types.ObjectId.isValid(paidBy) ||
!mongoose.Types.ObjectId.isValid(paidFor)
) {
return res.status(400).json({ error: 'Invalid ID format for expense, paidBy, or paidFor' });
}

if (topicId && !mongoose.Types.ObjectId.isValid(topicId)) {
return res.status(400).json({ error: 'Invalid topicId format' });
}
};
76 changes: 76 additions & 0 deletions src/models/journalModel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
const { Schema } = require('mongoose');

const journalSchema = new Schema({
name: {
type: String,
required: true,
},
decription: String,
createdAt: {
type: Date,
default: Date.now(),
},
id: {
type: Schema.Types.ObjectId,
ref: 'User',
},
});

const expenseSchema = new Schema({
groupId: {
type: Schema.Types.ObjectId,
ref: 'Group',
},
description: String,
amount: {
type: Number,
required: true,
},
paidBy: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true,
},
createdBy: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true,
},
splitBetween: [
{
type: Schema.Types.ObjectId,
ref: 'User',
},
],
splitType: {
type: String,
enum: ['equal', 'custom'],
default: 'equal',
},
customAmounts: {
type: Map,
of: Number,
},
topicId: {
type: String,
ref: 'journalSchema',
},
date: {
type: Date,
default: Date.now(),
},
status: {
type: String,
enum: ['pending', 'settled'],
default: 'pending',
},
settledAt: Date,
lastModified: Date,
});

const JournalTopic = mongoose.model('JournalTopic', journalSchema);
const Expense = mongoose.model('Expense', expenseSchema);
module.exports = {
JournalTopic,
Expense,
};
10 changes: 10 additions & 0 deletions src/routes/journalRoutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const express = require('express');

const { getAllExpense } = require('../controllers/journalController');

const router = express.Router();

router.get('/expenses/:groupId', getAllExpense);
router.post('/expenses/newE', getAllExpense);

module.exports = router;

0 comments on commit 61717cb

Please sign in to comment.