Merge branch 'virtual-link-transaction' into transaction-link-list-query

This commit is contained in:
Moriz Wahl 2022-03-11 12:24:02 +01:00
commit 80201c6fb1
6 changed files with 133 additions and 67 deletions

View File

@ -6,6 +6,7 @@ export enum TransactionTypeId {
RECEIVE = 3, RECEIVE = 3,
// This is a virtual property, never occurring on the database // This is a virtual property, never occurring on the database
DECAY = 4, DECAY = 4,
TRANSACTION_LINK,
} }
registerEnumType(TransactionTypeId, { registerEnumType(TransactionTypeId, {

View File

@ -30,7 +30,7 @@ import { calculateBalance, isHexPublicKey } from '@/util/validate'
import { RIGHTS } from '@/auth/RIGHTS' import { RIGHTS } from '@/auth/RIGHTS'
import { User } from '@model/User' import { User } from '@model/User'
import { communityUser } from '@/util/communityUser' import { communityUser } from '@/util/communityUser'
import { virtualDecayTransaction } from '@/util/virtualDecayTransaction' import { virtualLinkTransaction, virtualDecayTransaction } from '@/util/virtualTransactions'
import Decimal from 'decimal.js-light' import Decimal from 'decimal.js-light'
import { calculateDecay } from '@/util/decay' import { calculateDecay } from '@/util/decay'
@ -112,11 +112,29 @@ export class TransactionResolver {
const self = new User(user) const self = new User(user)
const transactions: Transaction[] = [] const transactions: Transaction[] = []
const transactionLinkRepository = getCustomRepository(TransactionLinkRepository)
const { sumHoldAvailableAmount, sumAmount, lastDate, firstDate } =
await transactionLinkRepository.summary(user.id, now)
// decay transaction // decay transaction
if (!onlyCreations && currentPage === 1 && order === Order.DESC) { if (!onlyCreations && currentPage === 1 && order === Order.DESC) {
transactions.push( transactions.push(
virtualDecayTransaction(lastTransaction.balance, lastTransaction.balanceDate, now, self), virtualDecayTransaction(lastTransaction.balance, lastTransaction.balanceDate, now, self),
) )
// virtual transaction for pending transaction-links sum
if (sumHoldAvailableAmount.greaterThan(0)) {
transactions.push(
virtualLinkTransaction(
lastTransaction.balance.minus(sumHoldAvailableAmount.toString()),
sumAmount,
sumHoldAvailableAmount,
sumHoldAvailableAmount.minus(sumAmount.toString()),
firstDate || now,
lastDate || now,
self,
),
)
}
} }
// transactions // transactions
@ -128,13 +146,10 @@ export class TransactionResolver {
transactions.push(new Transaction(userTransaction, self, linkedUser)) transactions.push(new Transaction(userTransaction, self, linkedUser))
}) })
const transactionLinkRepository = getCustomRepository(TransactionLinkRepository)
const toHoldAvailable = await transactionLinkRepository.sumAmountToHoldAvailable(user.id, now)
// Construct Result // Construct Result
return new TransactionList( return new TransactionList(
calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, now).balance.minus( calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, now).balance.minus(
toHoldAvailable.toString(), sumHoldAvailableAmount.toString(),
), ),
transactions, transactions,
userTransactionsCount, userTransactionsCount,

View File

@ -4,13 +4,33 @@ import Decimal from 'decimal.js-light'
@EntityRepository(dbTransactionLink) @EntityRepository(dbTransactionLink)
export class TransactionLinkRepository extends Repository<dbTransactionLink> { export class TransactionLinkRepository extends Repository<dbTransactionLink> {
async sumAmountToHoldAvailable(userId: number, date: Date): Promise<Decimal> { async summary(
const { sum } = await this.createQueryBuilder('transactionLinks') userId: number,
.select('SUM(transactionLinks.holdAvailableAmount)', 'sum') date: Date,
.where('transactionLinks.userId = :userId', { userId }) ): Promise<{
.andWhere('transactionLinks.redeemedAt is NULL') sumHoldAvailableAmount: Decimal
.andWhere('transactionLinks.validUntil > :date', { date }) sumAmount: Decimal
.getRawOne() lastDate: Date | null
return sum ? new Decimal(sum) : new Decimal(0) firstDate: Date | null
}> {
const { sumHoldAvailableAmount, sumAmount, lastDate, firstDate } =
await this.createQueryBuilder('transactionLinks')
.select('SUM(transactionLinks.holdAvailableAmount)', 'sumHoldAvailableAmount')
.addSelect('SUM(transactionLinks.amount)', 'sumAmount')
.addSelect('MAX(transactionLinks.validUntil)', 'lastDate')
.addSelect('MIN(transactionLinks.createdAt)', 'firstDate')
.where('transactionLinks.userId = :userId', { userId })
.andWhere('transactionLinks.redeemedAt is NULL')
.andWhere('transactionLinks.validUntil > :date', { date })
.orderBy('transactionLinks.createdAt', 'DESC')
.getRawOne()
return {
sumHoldAvailableAmount: sumHoldAvailableAmount
? new Decimal(sumHoldAvailableAmount)
: new Decimal(0),
sumAmount: sumAmount ? new Decimal(sumAmount) : new Decimal(0),
lastDate: lastDate || null,
firstDate: firstDate || null,
}
} }
} }

View File

@ -30,9 +30,9 @@ async function calculateBalance(
// TODO why we have to use toString() here? // TODO why we have to use toString() here?
const balance = decay.balance.add(amount.toString()) const balance = decay.balance.add(amount.toString())
const transactionLinkRepository = getCustomRepository(TransactionLinkRepository) const transactionLinkRepository = getCustomRepository(TransactionLinkRepository)
const toHoldAvailable = await transactionLinkRepository.sumAmountToHoldAvailable(userId, time) const { sumHoldAvailableAmount } = await transactionLinkRepository.summary(userId, time)
if (balance.minus(toHoldAvailable.toString()).lessThan(0)) { if (balance.minus(sumHoldAvailableAmount.toString()).lessThan(0)) {
return null return null
} }
return { balance, lastTransactionId: lastTransaction.id, decay } return { balance, lastTransactionId: lastTransaction.id, decay }

View File

@ -1,52 +0,0 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import Decimal from 'decimal.js-light'
import { SaveOptions, RemoveOptions } from '@dbTools/typeorm'
import { Transaction as dbTransaction } from '@entity/Transaction'
import { calculateDecay } from './decay'
import { TransactionTypeId } from '@enum/TransactionTypeId'
import { Transaction } from '@model/Transaction'
import { User } from '@model/User'
const virtualDecayTransaction = (
balance: Decimal,
balanceDate: Date,
time: Date = new Date(),
user: User,
): Transaction => {
const decay = calculateDecay(balance, balanceDate, time)
// const balance = decay.balance.minus(lastTransaction.balance)
const decayDbTransaction: dbTransaction = {
id: -1,
userId: -1,
previous: -1,
typeId: TransactionTypeId.DECAY,
amount: decay.decay ? decay.decay : new Decimal(0), // new Decimal(0), // this kinda is wrong, but helps with the frontend query
balance: decay.balance,
balanceDate: time,
decay: decay.decay ? decay.decay : new Decimal(0),
decayStart: decay.start,
memo: '',
creationDate: null,
hasId: function (): boolean {
throw new Error('Function not implemented.')
},
save: function (options?: SaveOptions): Promise<dbTransaction> {
throw new Error('Function not implemented.')
},
remove: function (options?: RemoveOptions): Promise<dbTransaction> {
throw new Error('Function not implemented.')
},
softRemove: function (options?: SaveOptions): Promise<dbTransaction> {
throw new Error('Function not implemented.')
},
recover: function (options?: SaveOptions): Promise<dbTransaction> {
throw new Error('Function not implemented.')
},
reload: function (): Promise<void> {
throw new Error('Function not implemented.')
},
}
return new Transaction(decayDbTransaction, user)
}
export { virtualDecayTransaction }

View File

@ -0,0 +1,82 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Transaction } from '@model/Transaction'
import { SaveOptions, RemoveOptions } from '@dbTools/typeorm'
import { Transaction as dbTransaction } from '@entity/Transaction'
import { TransactionTypeId } from '@enum/TransactionTypeId'
import { calculateDecay } from './decay'
import { User } from '@model/User'
import Decimal from 'decimal.js-light'
const defaultModelFunctions = {
hasId: function (): boolean {
throw new Error('Function not implemented.')
},
save: function (options?: SaveOptions): Promise<dbTransaction> {
throw new Error('Function not implemented.')
},
remove: function (options?: RemoveOptions): Promise<dbTransaction> {
throw new Error('Function not implemented.')
},
softRemove: function (options?: SaveOptions): Promise<dbTransaction> {
throw new Error('Function not implemented.')
},
recover: function (options?: SaveOptions): Promise<dbTransaction> {
throw new Error('Function not implemented.')
},
reload: function (): Promise<void> {
throw new Error('Function not implemented.')
},
}
const virtualLinkTransaction = (
balance: Decimal,
amount: Decimal,
holdAvailableAmount: Decimal,
decay: Decimal,
createdAt: Date,
validUntil: Date,
user: User,
): Transaction => {
const linkDbTransaction: dbTransaction = {
id: -2,
userId: -1,
previous: -1,
typeId: TransactionTypeId.TRANSACTION_LINK,
amount: amount,
balance: balance,
balanceDate: validUntil,
decayStart: createdAt,
decay: decay,
memo: '',
creationDate: null,
...defaultModelFunctions,
}
return new Transaction(linkDbTransaction, user)
}
const virtualDecayTransaction = (
balance: Decimal,
balanceDate: Date,
time: Date = new Date(),
user: User,
): Transaction => {
const decay = calculateDecay(balance, balanceDate, time)
// const balance = decay.balance.minus(lastTransaction.balance)
const decayDbTransaction: dbTransaction = {
id: -1,
userId: -1,
previous: -1,
typeId: TransactionTypeId.DECAY,
amount: decay.decay ? decay.decay : new Decimal(0), // new Decimal(0), // this kinda is wrong, but helps with the frontend query
balance: decay.balance,
balanceDate: time,
decay: decay.decay ? decay.decay : new Decimal(0),
decayStart: decay.start,
memo: '',
creationDate: null,
...defaultModelFunctions,
}
return new Transaction(decayDbTransaction, user)
}
export { virtualLinkTransaction, virtualDecayTransaction }