first commit

This commit is contained in:
Bastian Wagner
2026-07-31 21:02:47 +02:00
commit 6bea4f766a
512 changed files with 64459 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty } from 'class-validator';
import { TeamWalletTransactionEnum } from '../team-wallet-transaction.enum';
export class CreateTeamWalletTransactionDto {
@ApiProperty({ example: 0 })
@IsNotEmpty()
teamId: number;
@ApiProperty({ example: 'Extra teuer wegen diskutierens' })
note?: string | null;
@ApiProperty({ example: 'isotimestring' })
date: string;
@ApiProperty({ example: 10 })
@IsNotEmpty()
amount: number;
@ApiProperty({ enum: TeamWalletTransactionEnum })
@IsNotEmpty()
type: TeamWalletTransactionEnum;
}

View File

@@ -0,0 +1,16 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
import { EntityHelper } from 'src/utils/entity-helper';
import { ApiProperty } from '@nestjs/swagger';
import { Allow } from 'class-validator';
@Entity()
export class TeamWalletTransactionType extends EntityHelper {
@ApiProperty({ example: 1 })
@PrimaryColumn()
id: number;
@Allow()
@ApiProperty({ example: 'credit' })
@Column()
name?: string;
}

View File

@@ -0,0 +1,52 @@
import {
BeforeInsert,
Column,
CreateDateColumn,
Entity,
ManyToOne,
PrimaryGeneratedColumn,
} from 'typeorm';
import { EntityHelper } from 'src/utils/entity-helper';
import { TeamWalletTransactionType } from './team-wallet-transaction-type.entity';
import { Team } from 'src/teams/entities/team.entity';
@Entity()
export class TeamWalletTransaction extends EntityHelper {
@PrimaryGeneratedColumn()
id: number;
@ManyToOne(() => Team, {
eager: false,
})
team: Team;
@Column({ default: '' })
note: string;
@Column()
date: string;
@Column({ type: 'decimal', precision: 10, scale: 2, default: 0 })
amount: number;
@ManyToOne(() => TeamWalletTransactionType, {
eager: true,
})
type?: TeamWalletTransactionType | null;
@CreateDateColumn()
createdAt: Date;
@BeforeInsert()
async setBalance() {
if (!this.date) {
this.date = new Date().toISOString();
}
let amount = this.amount;
if (this.type.id > 10 && amount > 0) {
amount = amount * -1;
}
this.team.balance = Number(this.team.balance) + amount;
await this.team.save();
}
}

View File

@@ -0,0 +1,20 @@
import { Test, TestingModule } from '@nestjs/testing';
import { TeamWalletTransactionsController } from './team-wallet-transactions.controller';
describe('TeamWalletTransactionController', () => {
let controller: TeamWalletTransactionsController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [TeamWalletTransactionsController],
}).compile();
controller = module.get<TeamWalletTransactionsController>(
TeamWalletTransactionsController,
);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});

View File

@@ -0,0 +1,4 @@
export enum TeamWalletTransactionEnum {
'credit' = 1,
'expense' = 14,
}

View File

@@ -0,0 +1,20 @@
import { Test, TestingModule } from '@nestjs/testing';
import { TeamWalletTransactionsService } from './team-wallet-transactions.service';
describe('TeamWalletTransactionService', () => {
let service: TeamWalletTransactionsService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [TeamWalletTransactionsService],
}).compile();
service = module.get<TeamWalletTransactionsService>(
TeamWalletTransactionsService,
);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -0,0 +1,43 @@
import {
Body,
Controller,
HttpCode,
HttpStatus,
Post,
Req,
UseGuards,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiTags, ApiBearerAuth } from '@nestjs/swagger';
import { Roles } from 'src/roles/roles.decorator';
import { RoleEnum } from 'src/roles/roles.enum';
import { RolesGuard } from 'src/roles/roles.guard';
import { CreateTeamWalletTransactionDto } from './dto/create-team-wallet-transaction.dto';
import { TeamWalletTransactionsService } from './team-wallet-transactions.service';
@ApiTags('Transactions')
@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'), RolesGuard)
@Controller({
path: 'team-wallet-transactions',
version: '1',
})
export class TeamWalletTransactionsController {
constructor(
private teamWalletTransactionsService: TeamWalletTransactionsService,
) {}
@Roles([RoleEnum.admin, RoleEnum.user])
@Post()
@HttpCode(HttpStatus.CREATED)
create(
@Req() req,
@Body() createTransactionDto: CreateTeamWalletTransactionDto,
) {
const userId = req.user?.id;
return this.teamWalletTransactionsService.create(
createTransactionDto,
userId,
);
}
}

View File

@@ -0,0 +1,24 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { LoggingModule } from 'src/database/logging/logging.module';
import { Team } from 'src/teams/entities/team.entity';
import { User } from 'src/users/entities/user.entity';
import { TeamWalletTransactionType } from './entities/team-wallet-transaction-type.entity';
import { TeamWalletTransaction } from './entities/team-wallet-transaction.entity';
import { TeamWalletTransactionsController } from './team-wallet-transactions.controller';
import { TeamWalletTransactionsService } from './team-wallet-transactions.service';
@Module({
imports: [
TypeOrmModule.forFeature([
User,
TeamWalletTransaction,
TeamWalletTransactionType,
Team,
]),
LoggingModule,
],
controllers: [TeamWalletTransactionsController],
providers: [TeamWalletTransactionsService],
})
export class TeamWalletTransactionsModule {}

View File

@@ -0,0 +1,83 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { LoggingService } from 'src/database/logging/logging.service';
import { Team } from 'src/teams/entities/team.entity';
import { User } from 'src/users/entities/user.entity';
import { Repository } from 'typeorm';
import { CreateTeamWalletTransactionDto } from './dto/create-team-wallet-transaction.dto';
import { TeamWalletTransactionType } from './entities/team-wallet-transaction-type.entity';
import { TeamWalletTransaction } from './entities/team-wallet-transaction.entity';
import { TeamWalletTransactionEnum } from './team-wallet-transaction.enum';
@Injectable()
export class TeamWalletTransactionsService {
constructor(
@InjectRepository(User)
private usersRepository: Repository<User>,
@InjectRepository(TeamWalletTransaction)
private teamWalletTransactionRepository: Repository<TeamWalletTransaction>,
@InjectRepository(TeamWalletTransactionType)
private teamWalletTransactionTypeRepository: Repository<TeamWalletTransactionType>,
@InjectRepository(Team)
private teamRepository: Repository<Team>,
private logger: LoggingService,
) {}
async create(data: CreateTeamWalletTransactionDto, userId: string) {
const creatingUser = await this.usersRepository.findOne({
where: {
id: Number(userId),
},
relations: ['players', 'players.team', 'players.team.settings'],
});
const teamPlayer = creatingUser.players.find(
(p) =>
p.team.id == data.teamId &&
p.teamRole.id >=
Number(
p.team.settings.find((s) => s.key == 'transaction_create_min_role')[
'value'
],
),
);
if (creatingUser.role.id != 1 && !teamPlayer) {
return;
}
let team: Team;
if (teamPlayer && teamPlayer.team) {
team = teamPlayer.team;
} else {
team = await this.teamRepository.findOneByOrFail({
id: data.teamId,
});
}
const transactionType =
await this.teamWalletTransactionTypeRepository.findOne({
where: {
id: TeamWalletTransactionEnum[TeamWalletTransactionEnum[data.type]],
},
});
// darf es anlegen
const transaction = await this.teamWalletTransactionRepository.save(
this.teamWalletTransactionRepository.create({
amount: data.amount,
team: team,
date: data.date,
type: transactionType,
}),
);
await this.logger.info({
event: 'team_transaction_create',
details: `Teambuchung ${transaction.id} angelegt`,
userId: Number(userId),
});
return transaction;
}
}