102 lines
3.4 KiB
TypeScript
102 lines
3.4 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
import { Cron, CronExpression } from '@nestjs/schedule';
|
|
import { InjectRepository } from '@nestjs/typeorm';
|
|
import { LoggingService } from 'src/database/logging/logging.service';
|
|
import { Player } from 'src/players/entities/player.entity';
|
|
import { Transaction } from 'src/transactions/entitites/transaction.entity';
|
|
import { DataSource, LessThanOrEqual, Repository } from 'typeorm';
|
|
import { RecurringTransactionIntervalEnum } from './recurring-transaction-interval.enum';
|
|
import { RecurringTransaction } from './entities/recurring-transaction.entity';
|
|
|
|
const INTERVAL_MONTHS: Record<RecurringTransactionIntervalEnum, number> = {
|
|
[RecurringTransactionIntervalEnum.monthly]: 1,
|
|
[RecurringTransactionIntervalEnum.quarterly]: 3,
|
|
[RecurringTransactionIntervalEnum.yearly]: 12,
|
|
};
|
|
|
|
@Injectable()
|
|
export class RecurringTransactionsScheduler {
|
|
constructor(
|
|
@InjectRepository(RecurringTransaction)
|
|
private readonly repository: Repository<RecurringTransaction>,
|
|
private readonly dataSource: DataSource,
|
|
private readonly logger: LoggingService,
|
|
) {}
|
|
|
|
@Cron(CronExpression.EVERY_DAY_AT_8AM)
|
|
async runDueRecurringTransactions(): Promise<void> {
|
|
const start = Date.now();
|
|
|
|
await this.logger.info(
|
|
{
|
|
event: 'scheduled_recurring_transaction_check_start',
|
|
details: `Starting sheduled recurring Transaction check`,
|
|
userId: -1,
|
|
},
|
|
);
|
|
|
|
const today = new Date().toISOString();
|
|
const due = await this.repository.find({
|
|
where: { active: true, nextRunDate: LessThanOrEqual(today) },
|
|
relations: ['team', 'type'],
|
|
});
|
|
|
|
for (const definition of due) {
|
|
await this.runOne(definition);
|
|
}
|
|
|
|
await this.logger.info(
|
|
{
|
|
event: 'scheduled_recurring_transaction_check_finished',
|
|
details: `Finished sheduled recurring Transaction check, durationMS=${Date.now() - start}`,
|
|
userId: -1,
|
|
},
|
|
);
|
|
}
|
|
|
|
private async runOne(definition: RecurringTransaction): Promise<void> {
|
|
await this.dataSource.transaction(async (manager) => {
|
|
const players = await manager
|
|
.getRepository(Player)
|
|
.find({ where: { team: { id: definition.team.id }, active: true } });
|
|
|
|
const transactionRepository = manager.getRepository(Transaction);
|
|
for (const player of players) {
|
|
const transaction = transactionRepository.create({
|
|
amount: definition.amount,
|
|
date: new Date().toISOString(),
|
|
note: definition.description,
|
|
player,
|
|
type: definition.type,
|
|
});
|
|
await transactionRepository.save(transaction);
|
|
}
|
|
|
|
const definitionRepository = manager.getRepository(RecurringTransaction);
|
|
definition.nextRunDate = this.advance(
|
|
definition.nextRunDate,
|
|
definition.interval,
|
|
);
|
|
await definitionRepository.save(definition);
|
|
|
|
await this.logger.info(
|
|
{
|
|
event: 'recurring_transaction_run',
|
|
details: `recurringTransactionId=${definition.id} teamId=${definition.team.id} gebuchteSpieler=${players.length}`,
|
|
userId: -1,
|
|
},
|
|
manager,
|
|
);
|
|
});
|
|
}
|
|
|
|
private advance(
|
|
nextRunDate: string,
|
|
interval: RecurringTransactionIntervalEnum,
|
|
): string {
|
|
const date = new Date(nextRunDate);
|
|
date.setUTCMonth(date.getUTCMonth() + INTERVAL_MONTHS[interval]);
|
|
return date.toISOString();
|
|
}
|
|
}
|