2025-11-29 11:04:35 +01:00

119 lines
4.1 KiB
TypeScript

import { Contribution, Transaction, User } from '../../entity'
import { Decimal } from 'decimal.js-light'
import { CreationInterface } from '../creation/CreationInterface'
import { ContributionType, ContributionStatus, TransactionTypeId } from '../../enum'
import { findUserByIdentifier } from '../../queries'
import { createTransaction } from './transaction'
import { AppDatabase } from '../../AppDatabase'
export function nMonthsBefore(date: Date, months = 1): string {
return new Date(date.getFullYear(), date.getMonth() - months, 1).toISOString()
}
export async function creationFactory(
creation: CreationInterface,
user?: User | null,
moderatorUser?: User | null,
): Promise<Contribution> {
if (!user) {
user = await findUserByIdentifier(creation.email)
}
if (!user) {
throw new Error(`User ${creation.email} not found`)
}
let contribution = await createContribution(creation, user)
if (creation.confirmed) {
if (!moderatorUser) {
moderatorUser = await findUserByIdentifier('peter@lustig.de')
}
if (!moderatorUser) {
throw new Error('Moderator user not found')
}
await confirmTransaction(contribution, moderatorUser)
}
return contribution
}
export async function creationFactoryBulk(
creations: CreationInterface[],
userCreationIndexedByEmail: Map<string, User>,
moderatorUser: User,
): Promise<Contribution[]> {
const lastTransaction = await Transaction.findOne({ order: { id: 'DESC' }, select: ['id'], where: {} })
let transactionId = lastTransaction ? lastTransaction.id + 1 : 1
const dbContributions: Contribution[] = []
const dbTransactions: Transaction[] = []
for (const creation of creations) {
const user = userCreationIndexedByEmail.get(creation.email)
if (!user) {
throw new Error(`User ${creation.email} not found`)
}
let contribution = await createContribution(creation, user, false)
if (creation.confirmed) {
const { contribution: _, transaction } = await confirmTransaction(contribution, moderatorUser, transactionId, false)
dbTransactions.push(transaction)
transactionId++
}
dbContributions.push(contribution)
}
const dataSource = AppDatabase.getInstance().getDataSource()
await dataSource.transaction(async (transaction) => {
await dataSource.getRepository(Contribution).insert(dbContributions)
await dataSource.getRepository(Transaction).insert(dbTransactions)
})
return dbContributions
}
export async function createContribution(creation: CreationInterface, user: User, store: boolean = true): Promise<Contribution> {
const contribution = new Contribution()
contribution.user = user
contribution.userId = user.id
contribution.amount = new Decimal(creation.amount)
contribution.createdAt = new Date()
contribution.contributionDate = getContributionDate(creation)
contribution.memo = creation.memo
contribution.contributionType = ContributionType.USER
contribution.contributionStatus = ContributionStatus.PENDING
return store ? contribution.save() : contribution
}
export async function confirmTransaction(
contribution: Contribution,
moderatorUser: User,
transactionId?: number,
store: boolean = true
): Promise<{ contribution: Contribution, transaction: Transaction }> {
const now = new Date()
const transaction = await createTransaction(
contribution.amount,
contribution.memo,
contribution.user,
moderatorUser,
TransactionTypeId.CREATION,
now,
contribution.contributionDate,
transactionId,
store,
)
contribution.confirmedAt = now
contribution.confirmedBy = moderatorUser.id
contribution.transactionId = transaction.id
contribution.transaction = transaction
contribution.contributionStatus = ContributionStatus.CONFIRMED
if (store) {
await contribution.save()
await transaction.save()
}
return { contribution, transaction }
}
function getContributionDate(creation: CreationInterface): Date {
if (creation.moveCreationDate) {
return new Date(nMonthsBefore(new Date(creation.contributionDate), creation.moveCreationDate))
}
return new Date(creation.contributionDate)
}