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 { 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, moderatorUser: User, ): Promise { 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 { 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) }