- Modified TypeScript configuration to disable strict mode and allow importing TypeScript extensions. - Updated Prisma schema to enhance the User model with a new debtAccounts field and refined asset/liability types. - Adjusted environment variable parsing for PORT to use coercion for better type handling. - Refactored various controllers and repositories to utilize type imports for better clarity and maintainability. - Enhanced service layers with new methods for retrieving assets by type and calculating invoice statistics. - Introduced new types for invoice statuses and asset types to ensure consistency across the application.
165 lines
4.6 KiB
TypeScript
165 lines
4.6 KiB
TypeScript
import type {IncomeSource, Expense, Transaction, Prisma} from '@prisma/client';
|
|
import {DatabaseConnection} from '../config/database';
|
|
|
|
const prisma = DatabaseConnection.getInstance();
|
|
|
|
/**
|
|
* Repository for IncomeSource data access
|
|
*/
|
|
export class IncomeSourceRepository {
|
|
async findById(id: string): Promise<IncomeSource | null> {
|
|
return prisma.incomeSource.findUnique({where: {id}});
|
|
}
|
|
|
|
async findByIdAndUser(id: string, userId: string): Promise<IncomeSource | null> {
|
|
return prisma.incomeSource.findFirst({where: {id, userId}});
|
|
}
|
|
|
|
async findAllByUser(userId: string): Promise<IncomeSource[]> {
|
|
return prisma.incomeSource.findMany({
|
|
where: {userId},
|
|
orderBy: {createdAt: 'desc'},
|
|
});
|
|
}
|
|
|
|
async create(data: Prisma.IncomeSourceCreateInput): Promise<IncomeSource> {
|
|
return prisma.incomeSource.create({data});
|
|
}
|
|
|
|
async update(id: string, data: Prisma.IncomeSourceUpdateInput): Promise<IncomeSource> {
|
|
return prisma.incomeSource.update({where: {id}, data});
|
|
}
|
|
|
|
async delete(id: string): Promise<void> {
|
|
await prisma.incomeSource.delete({where: {id}});
|
|
}
|
|
|
|
async getTotalMonthlyIncome(userId: string): Promise<number> {
|
|
const result = await prisma.incomeSource.aggregate({
|
|
where: {userId},
|
|
_sum: {amount: true},
|
|
});
|
|
return result._sum.amount || 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Repository for Expense data access
|
|
*/
|
|
export class ExpenseRepository {
|
|
async findById(id: string): Promise<Expense | null> {
|
|
return prisma.expense.findUnique({where: {id}});
|
|
}
|
|
|
|
async findByIdAndUser(id: string, userId: string): Promise<Expense | null> {
|
|
return prisma.expense.findFirst({where: {id, userId}});
|
|
}
|
|
|
|
async findAllByUser(userId: string): Promise<Expense[]> {
|
|
return prisma.expense.findMany({
|
|
where: {userId},
|
|
orderBy: {createdAt: 'desc'},
|
|
});
|
|
}
|
|
|
|
async create(data: Prisma.ExpenseCreateInput): Promise<Expense> {
|
|
return prisma.expense.create({data});
|
|
}
|
|
|
|
async update(id: string, data: Prisma.ExpenseUpdateInput): Promise<Expense> {
|
|
return prisma.expense.update({where: {id}, data});
|
|
}
|
|
|
|
async delete(id: string): Promise<void> {
|
|
await prisma.expense.delete({where: {id}});
|
|
}
|
|
|
|
async getTotalMonthlyExpenses(userId: string): Promise<number> {
|
|
const result = await prisma.expense.aggregate({
|
|
where: {userId},
|
|
_sum: {amount: true},
|
|
});
|
|
return result._sum.amount || 0;
|
|
}
|
|
|
|
async getByCategory(userId: string): Promise<Record<string, Expense[]>> {
|
|
const expenses = await this.findAllByUser(userId);
|
|
return expenses.reduce((acc, expense) => {
|
|
if (!acc[expense.category]) acc[expense.category] = [];
|
|
acc[expense.category].push(expense);
|
|
return acc;
|
|
}, {} as Record<string, Expense[]>);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Repository for Transaction data access
|
|
*/
|
|
export class TransactionRepository {
|
|
async findById(id: string): Promise<Transaction | null> {
|
|
return prisma.transaction.findUnique({where: {id}});
|
|
}
|
|
|
|
async findByIdAndUser(id: string, userId: string): Promise<Transaction | null> {
|
|
return prisma.transaction.findFirst({where: {id, userId}});
|
|
}
|
|
|
|
async findAllByUser(userId: string): Promise<Transaction[]> {
|
|
return prisma.transaction.findMany({
|
|
where: {userId},
|
|
orderBy: {date: 'desc'},
|
|
});
|
|
}
|
|
|
|
async create(data: Prisma.TransactionCreateInput): Promise<Transaction> {
|
|
return prisma.transaction.create({data});
|
|
}
|
|
|
|
async update(id: string, data: Prisma.TransactionUpdateInput): Promise<Transaction> {
|
|
return prisma.transaction.update({where: {id}, data});
|
|
}
|
|
|
|
async delete(id: string): Promise<void> {
|
|
await prisma.transaction.delete({where: {id}});
|
|
}
|
|
|
|
async getByDateRange(userId: string, startDate: Date, endDate: Date): Promise<Transaction[]> {
|
|
return prisma.transaction.findMany({
|
|
where: {
|
|
userId,
|
|
date: {gte: startDate, lte: endDate},
|
|
},
|
|
orderBy: {date: 'desc'},
|
|
});
|
|
}
|
|
|
|
async getByType(userId: string, type: string): Promise<Transaction[]> {
|
|
return prisma.transaction.findMany({
|
|
where: {userId, type},
|
|
orderBy: {date: 'desc'},
|
|
});
|
|
}
|
|
|
|
async getCashflowSummary(userId: string, startDate: Date, endDate: Date): Promise<{
|
|
totalIncome: number;
|
|
totalExpenses: number;
|
|
netCashflow: number;
|
|
}> {
|
|
const transactions = await this.getByDateRange(userId, startDate, endDate);
|
|
|
|
const totalIncome = transactions
|
|
.filter(t => t.type === 'income')
|
|
.reduce((sum, t) => sum + t.amount, 0);
|
|
|
|
const totalExpenses = transactions
|
|
.filter(t => t.type === 'expense')
|
|
.reduce((sum, t) => sum + t.amount, 0);
|
|
|
|
return {
|
|
totalIncome,
|
|
totalExpenses,
|
|
netCashflow: totalIncome - totalExpenses,
|
|
};
|
|
}
|
|
}
|