expense-log-mcp
Version:
A MCP server that provides tools for logging expenses.
72 lines (71 loc) • 2.82 kB
JavaScript
import { z } from "zod";
import prisma from "../db.js";
import { successResponse, errorResponse, getErrorMessage } from "./utils.js";
const getGroupedExpensesParameters = z.object({
ledgerId: z.string(),
categoryIds: z.array(z.string()).optional(),
payer: z.string().optional(),
startDate: z.string().optional(),
endDate: z.string().optional(),
});
export const getGroupedExpenses = {
name: "getGroupedExpenses",
description: `Retrieves and groups expenses by payer and category, showing total amounts,
with optional filters for category IDs, payer, and date range (ISO 8601 format).`,
parameters: getGroupedExpensesParameters,
execute: async ({ ledgerId, categoryIds, payer, startDate, endDate }) => {
try {
const where = buildWhereFilter(ledgerId, categoryIds, payer, startDate, endDate);
const expenses = await prisma.expense.findMany({ where });
const categories = await prisma.expenseCategory.findMany();
const categoryMap = new Map();
categories.forEach(category => {
categoryMap.set(category.id, category.name);
});
const groupedExpenses = groupExpenses(expenses, categoryMap);
return successResponse("Grouped expenses retrieved successfully.", groupedExpenses);
}
catch (e) {
return errorResponse("DATABSAE_ERROR", getErrorMessage(e));
}
}
};
function buildWhereFilter(ledgerId, categoryIds, payer, startDate, endDate) {
const where = {};
where.ledgerId = ledgerId;
if (categoryIds && categoryIds.length > 0) {
where.categoryId = { in: categoryIds };
}
if (payer) {
where.payer = payer;
}
if (!startDate && !endDate) {
const now = new Date();
startDate = new Date(now.getFullYear(), now.getMonth(), 1).toISOString();
endDate = new Date(now.getFullYear(), now.getMonth() + 1, 0).toISOString();
}
where.createdAt = {};
if (startDate) {
where.createdAt.gte = new Date(startDate);
}
if (endDate) {
where.createdAt.lte = new Date(endDate);
}
return where;
}
function groupExpenses(expenses, categoryMap) {
return expenses.reduce((acc, expense) => {
const payer = expense.payer;
const categoryId = expense.categoryId;
const categoryName = categoryMap.get(categoryId) || 'Unknown Category';
if (!acc[payer]) {
acc[payer] = { expenseCategories: {}, totalAmount: 0 };
}
if (!acc[payer].expenseCategories[categoryName]) {
acc[payer].expenseCategories[categoryName] = 0;
}
acc[payer].expenseCategories[categoryName] += expense.amount;
acc[payer].totalAmount += expense.amount;
return acc;
}, {});
}