This commit is contained in:
2023-12-14 11:15:56 +01:00
parent 55f5869385
commit f6f9819058
21 changed files with 3516 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
// Account model definition
import { Sequelize, DataTypes, Model, Optional, Attributes, CreateOptions, ModelStatic } from 'sequelize';
import { HookReturn } from 'sequelize/types/hooks';
import { Transaction } from './Transaction'; // Import the Transaction model
interface AccountAttributes {
AccountID: number;
Name: string;
// Other account fields...
}
interface AccountCreationAttributes extends Optional<AccountAttributes, 'AccountID'> { }
class Account extends Model<AccountAttributes, AccountCreationAttributes> implements AccountAttributes {
public AccountID!: number;
public Name!: string;
static initialize(sequelize: Sequelize): void {
Account.init(
{
AccountID: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
Name: {
type: DataTypes.STRING,
allowNull: false,
},
// Other account fields...
},
{
sequelize,
modelName: 'Account',
hooks: {
afterCreate: (attributes: Account, options: CreateOptions<AccountAttributes>) => {
console.log(attributes)
},
beforeCreate(attributes: Account, options: CreateOptions<AccountAttributes>) {
console.log(attributes)
},
}
}
);
}
static associate(models: { Transaction: typeof Transaction }): void {
Account.hasMany(models.Transaction, { foreignKey: 'AccountID' }); // An account can have multiple transactions
}
}
export { Account };

View File

@@ -0,0 +1,54 @@
import { Sequelize, DataTypes, Model, Optional } from 'sequelize';
import { User } from './User';
import { Transaction } from './Transaction';
// Category attributes interface
interface CategoryAttributes {
CategoryID: number;
Name: string;
Description: string | null;
// Other fields...
}
// Category creation attributes (optional fields)
interface CategoryCreationAttributes extends Optional<CategoryAttributes, 'CategoryID'> {}
// Define the Category model
class Category extends Model<CategoryAttributes, CategoryCreationAttributes> implements CategoryAttributes {
public CategoryID!: number;
public Name!: string;
public Description!: string | null;
// Other fields...
static initialize(sequelize: Sequelize): void {
Category.init(
{
CategoryID: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
Name: {
type: DataTypes.STRING,
allowNull: false,
},
Description: {
type: DataTypes.STRING,
allowNull: true,
},
// Other fields...
},
{
sequelize,
modelName: 'Category',
// Other model options...
}
);
}
static associate(models: { User: typeof User; Transaction: typeof Transaction }): void {
Category.belongsToMany(models.Transaction,{through:"TransactionCategory"}); // A category can have multiple transactions
}
}
export {Category };

View File

@@ -0,0 +1,114 @@
// MonthlyReport model definition
import { Sequelize, DataTypes, Model, Optional, Op, fn, col } from 'sequelize';
import moment from 'moment';
import { Transaction } from './Transaction'; // Assuming you have a Transaction model
import { Account } from './Account';
interface MonthlyReportAttributes {
MonthlyReportID: number;
Month: number;
Year: number;
TotalAmount: number;
// Other report fields...
AccountID: number;
}
interface MonthlyReportCreationAttributes extends Optional<MonthlyReportAttributes, 'MonthlyReportID'> { }
class MonthlyReport extends Model<MonthlyReportAttributes, MonthlyReportCreationAttributes> implements MonthlyReportAttributes {
public MonthlyReportID!: number;
public Month!: number;
public Year!: number;
public TotalAmount!: number;
public AccountID!: number;
static initialize(sequelize: Sequelize): void {
MonthlyReport.init(
{
MonthlyReportID: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
Month: {
type: DataTypes.INTEGER,
allowNull: false,
},
Year: {
type: DataTypes.INTEGER,
allowNull: false,
},
TotalAmount: {
type: DataTypes.FLOAT,
allowNull: false,
},
AccountID: {
type: DataTypes.INTEGER,
allowNull: false,
}
// Other report fields...
},
{
sequelize,
modelName: 'MonthlyReport',
}
);
}
static associate(models: { Transaction: typeof Transaction, Account: typeof Account }): void {
MonthlyReport.hasMany(models.Transaction, { foreignKey: 'MonthlyReportID' }); // A report can have multiple transactions
MonthlyReport.belongsTo(models.Account)
}
static async generateMonthlyReport(month: number, year: number, AccountID: number|null = null): Promise<void> {
try {
moment.locale("de")
let m = moment();
m.set({year:year,month:month-1,day:15});
let startDate = moment(m).startOf('month');
let endDate = moment(m).endOf('month');
// Fetch transaction data and calculate total amount
let transactions = null;
if(AccountID==null){
transactions = await Transaction.findAll({
where: {
Date: {
[Op.between]: [startDate, endDate],
}
},
});
}else{
transactions = await Transaction.findAll({
where: {
Date: {
[Op.between]: [startDate, endDate],
},
AccountID: AccountID
},
});
}
console.log(transactions)
const totalAmount = transactions.reduce((total, transaction) => total + transaction.Amount, 0);
console.log(totalAmount)
// Create a MonthlyReport entry with the generated data
await MonthlyReport.create({
Month: month,
Year: year,
TotalAmount: totalAmount,
AccountID: 0
});
console.log(`Monthly report generated for ${month}/${year}`);
} catch (err) {
console.error('Error generating monthly report:', err);
} finally {
}
}
}
export { MonthlyReport };

View File

@@ -0,0 +1,129 @@
import { Sequelize, DataTypes, Model, Optional, Attributes, CreateOptions, ModelStatic } from 'sequelize';
import { User } from './User';
import { Category } from './Category';
import { Account } from './Account';
import { HookReturn } from 'sequelize/types/hooks';
import { MonthlyReport } from './MonthlyReport';
// Transaction attributes interface
interface TransactionAttributes {
TransactionID: number;
Date: Date;
Description: string | null;
UserID: number;
Amount: number;
Type: 'income' | 'expense' | 'transfer';
AccountID: number;
// Other fields...
}
// Transaction creation attributes (optional fields)
interface TransactionCreationAttributes extends Optional<TransactionAttributes, 'TransactionID'> { }
// Define the Transaction model
class Transaction extends Model<TransactionAttributes, TransactionCreationAttributes> implements TransactionAttributes {
public TransactionID!: number;
public Date!: Date;
public Description!: string | null;
public Amount!: number;
public Type!: 'income' | 'expense' | 'transfer';
// Other fields...
public UserID!: number;
public AccountID!: number;
public CategoryID!: number;
static initialize(sequelize: Sequelize): void {
Transaction.init(
{
TransactionID: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
Date: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: new Date()
},
Description: {
type: DataTypes.STRING,
allowNull: true,
},
UserID: {
type: DataTypes.INTEGER,
allowNull: false,
},
AccountID: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 1,
},
Amount: {
type: DataTypes.FLOAT,
allowNull: false,
},
Type: {
type: DataTypes.ENUM('income', 'expense','transfer'),
allowNull: false,
},
// Other fields...
},
{
sequelize,
modelName: 'Transaction',
// Other model options...
hooks: {
afterCreate: (attributes: Transaction, options: CreateOptions<TransactionAttributes>) => {
console.log(attributes)
},
beforeCreate(attributes: Transaction, options: CreateOptions<TransactionAttributes>) {
if (attributes.Type == "expense") {
attributes.Amount = -0 - attributes.Amount;
}
},
}
}
);
}
static associate(models: { User: typeof User; Category: typeof Category; Account: typeof Account; MonthlyReport: typeof MonthlyReport }): void {
Transaction.belongsTo(models.User); // A transaction belongs to a user
Transaction.belongsTo(models.Category, { foreignKey: 'CategoryID' }); // A transaction belongs to a category
Transaction.belongsTo(models.Account, { foreignKey: 'AccountID' }); // A transaction belongs to an account
}
static async getTotalAmountForUser(userId: number): Promise<number> {
const result = await Transaction.sum('Amount', { where: { UserID: userId } });
return result || 0;
}
static async transferAmountFromTo(userID: number, fromAccountID: number = 1, toAccountID: number = 1, Amount: number = 0){
console.log(`User: ${userID}, fromAccount: ${fromAccountID}, toAccount${toAccountID}, Amount: ${Amount}`)
await Transaction.create({
Amount:-Amount,
Date:new Date(),
Type:"transfer",
//@ts-ignore
UserID: userID, // Associate the transaction with the user
//@ts-ignore
CategoryID: 1,
AccountID: fromAccountID
})
await Transaction.create({
Amount:Amount,
Date:new Date(),
Type:"transfer",
//@ts-ignore
UserID: userID, // Associate the transaction with the user
//@ts-ignore
CategoryID: 1,
AccountID: toAccountID
})
}
}
export { Transaction };

View File

@@ -0,0 +1,62 @@
import { Sequelize, DataTypes, Model, Optional } from 'sequelize';
import { Category } from './Category';
import { Transaction } from './Transaction';
// User attributes interface
interface UserAttributes {
UserID: number;
Name: string;
Email: string;
Password: string;
// Other fields...
}
// User creation attributes (optional fields)
interface UserCreationAttributes extends Optional<UserAttributes, 'UserID'> { }
// Define the User model
class User extends Model<UserAttributes, UserCreationAttributes> implements UserAttributes {
public UserID!: number;
public Name!: string;
public Email!: string;
public Password!: string;
// Other fields...
static initialize(sequelize: Sequelize): void {
User.init(
{
UserID: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
Name: {
type: DataTypes.STRING,
allowNull: false,
},
Email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
Password: {
type: DataTypes.STRING,
allowNull: false,
},
// Other fields...
},
{
sequelize,
modelName: 'User',
// Other model options...
}
);
}
static associate(models: { Category: typeof Category; Transaction: typeof Transaction }): void {
User.hasMany(models.Transaction, { foreignKey: 'UserID' });
}
}
export { User };

View File

@@ -0,0 +1,4 @@
export { Category } from "./Category";
export { Transaction } from "./Transaction";
export { User } from "./User";
export { Account } from "./Account";

109
src/controller/router.ts Normal file
View File

@@ -0,0 +1,109 @@
// server.ts
import express, { Request, Response } from 'express';
import { User, Category, Transaction, Account } from './models'; // Adjust the path to your models
import pug from "pug"
import path from 'path';
export class Router {
app: any;
constructor(Path = "", PORT = 3000) {
let app = express();
// Set the view engine to Pug
app.set('view engine', 'pug');
app.set('views', './views'); // Set the views directory
console.log(Path)
app.use('/assets', express.static(Path));
app.get('/', async (req: Request, res: Response) => {
try {
const users = await User.findAll();
const categories = await Category.findAll();
const transactions = await Transaction.findAll();
res.render('index', {
title: 'Home',
userCount: users.length,
categoryCount: categories.length,
transactionCount: transactions.length,
});
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
});
app.get('/users', async (req: Request, res: Response) => {
try {
const users = await User.findAll();
res.render('users', { title: 'Users', users });
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
});
app.get('/categories', async (req: Request, res: Response) => {
try {
const categories = await Category.findAll();
res.render('categories', { title: 'Categories', categories });
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
});
app.get('/transactions', async (req: Request, res: Response) => {
try {
const transactions = await Transaction.findAll({
include: Account
});
console.log(transactions)
res.render('transactions/transactions', { title: 'Transactions', transactions });
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
});
app.get('/transactions/acc/:acc', async (req: Request, res: Response) => {
try {
const transactions = await Transaction.findAll({
include: Account,
where: {
AccountID: req.params.acc
}
});
console.log(transactions)
res.render('transactions/transactions', { title: 'Transactions', transactions });
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
});
app.get('/transactions/cat/:cat', async (req: Request, res: Response) => {
try {
const transactions = await Transaction.findAll({
include: [Account, Category],
where: {
//@ts-ignore
CategoryID: req.params.cat
}
});
console.log(transactions)
res.render('transactions/transactions', { title: 'Transactions', transactions });
} catch (err) {
console.error(err);
res.status(500).send('Internal Server Error');
}
});
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
this.app = app;
}
}

View File

@@ -0,0 +1,5 @@
export class Storage{
static Path=""
static __filename: string;
static __dirname: string;
}