diff --git a/backend/src/graphql/inputs/TransactionInput.ts b/backend/src/graphql/inputs/TransactionInput.ts index a62d86a65..1f79d193e 100644 --- a/backend/src/graphql/inputs/TransactionInput.ts +++ b/backend/src/graphql/inputs/TransactionInput.ts @@ -9,7 +9,7 @@ export class TransactionListInput { items: number @Field(() => String) - order: string + order: "ASC" | "DESC" } @ArgsType() diff --git a/backend/src/graphql/models/Transaction.ts b/backend/src/graphql/models/Transaction.ts index 87535c4a2..a2f2d19c1 100644 --- a/backend/src/graphql/models/Transaction.ts +++ b/backend/src/graphql/models/Transaction.ts @@ -30,6 +30,9 @@ export class Transaction { @Field(() => Number) balance: number + @Field(() => Number) + totalBalance: number + @Field({ nullable: true }) decayStart?: number diff --git a/backend/src/graphql/resolvers/TransactionResolver.ts b/backend/src/graphql/resolvers/TransactionResolver.ts index 52af4bd53..ed8dcea81 100644 --- a/backend/src/graphql/resolvers/TransactionResolver.ts +++ b/backend/src/graphql/resolvers/TransactionResolver.ts @@ -6,6 +6,11 @@ import CONFIG from '../../config' import { TransactionList } from '../models/Transaction' import { TransactionListInput, TransactionSendArgs } from '../inputs/TransactionInput' import { apiGet, apiPost } from '../../apis/HttpRequest' +import { User } from '../../typeorm/entity/User' +import { Balance } from '../../typeorm/entity/Balance' +import listTransactions from './listTransactions' +import { roundFloorFrom4 } from '../../util/round' +import calculateDecay from '../../util/decay' @Resolver() export class TransactionResolver { @@ -15,11 +20,30 @@ export class TransactionResolver { @Args() { firstPage = 1, items = 25, order = 'DESC' }: TransactionListInput, @Ctx() context: any, ): Promise { - const result = await apiGet( - `${CONFIG.COMMUNITY_API_URL}listTransactions/${firstPage}/${items}/${order}/${context.sessionId}`, - ) + // get public key for current logged in user + const result = await apiGet(CONFIG.LOGIN_API_URL + 'login?session_id=' + context.sessionId) if (!result.success) throw new Error(result.data) - return new TransactionList(result.data) + + // load user + const userEntity = await User.findByPubkeyHex(result.data.user.public_hex) + + const transactions = await listTransactions(firstPage, items, order, userEntity) + + // get gdt sum + const resultGDTSum = await apiPost( + `${CONFIG.GDT_API_URL}/GdtEntries/sumPerEmailApi`, {email: userEntity.email} + ) + if (!resultGDTSum.success) throw new Error(resultGDTSum.data) + transactions.gdtSum = resultGDTSum.data.sum + + // get balance + const balanceEntity = await Balance.findByUser(userEntity.id) + const now = new Date() + transactions.balance = roundFloorFrom4(balanceEntity.amount) + transactions.decay = roundFloorFrom4(calculateDecay(balanceEntity.amount, balanceEntity.recordDate, now)) + transactions.decayDate = now.toString() + + return transactions } @Authorized() diff --git a/backend/src/graphql/resolvers/listTransactions.ts b/backend/src/graphql/resolvers/listTransactions.ts new file mode 100644 index 000000000..a7889a954 --- /dev/null +++ b/backend/src/graphql/resolvers/listTransactions.ts @@ -0,0 +1,61 @@ + +import { User } from '../../typeorm/entity/User' +import { TransactionList, Transaction } from '../models/Transaction' +import { UserTransaction } from '../../typeorm/entity/UserTransaction' + +function calculateAndAddDecayTransactions( + userTransactions:UserTransaction[], + user: User, + decay:boolean, + skipFirstTransaction:boolean +): Transaction[] +{ + let transactions: Transaction[] = [] + + return transactions +} + + +export default async function listTransactions( + firstPage:number, + items:number, + order:"ASC" | "DESC", + user:User) : Promise +{ + + let limit = items + let offset = 0 + let skipFirstTransaction = false + if(firstPage > 1) { + offset = (( firstPage - 1 ) * items) - 1; + limit++; + } + + if(offset && order == 'ASC') { + offset--; + } + let [userTransactions, userTransactionsCount] = await UserTransaction.findByUserPaged(user.id, limit, offset, order) + skipFirstTransaction = userTransactionsCount > offset + limit + const decay = !(firstPage > 1) + let transactions: Transaction[] = [] + if(userTransactions.length) { + if(order === 'DESC') { + userTransactions = userTransactions.reverse() + } + let transactions = calculateAndAddDecayTransactions(userTransactions, user, decay, skipFirstTransaction) + if(order === 'DESC') { + transactions = transactions.reverse() + } + } + + const transactionList = new TransactionList({ + gdtSum: 0, + count: userTransactionsCount, + balance: 0, + decay: 0, + decay_date: '', + transactions: transactions + }) + + return transactionList +} \ No newline at end of file diff --git a/backend/src/typeorm/entity/User.ts b/backend/src/typeorm/entity/User.ts index f7b8ed7c1..bdf53bc4f 100644 --- a/backend/src/typeorm/entity/User.ts +++ b/backend/src/typeorm/entity/User.ts @@ -1,4 +1,5 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm' +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm' +import { UserTransaction } from './UserTransaction' // import { Group } from "./Group" diff --git a/backend/src/typeorm/entity/UserTransaction.ts b/backend/src/typeorm/entity/UserTransaction.ts new file mode 100644 index 000000000..6232c220d --- /dev/null +++ b/backend/src/typeorm/entity/UserTransaction.ts @@ -0,0 +1,35 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, Timestamp, ManyToOne } from 'typeorm' +import { User } from './User' + + +@Entity('state_user_transactions') +export class UserTransaction extends BaseEntity { + @PrimaryGeneratedColumn() + id: number + + @Column({ name: 'state_user_id' }) + userId: number + + @Column({ name: 'transaction_id' }) + transactionId: number + + @Column({ name: 'transaction_type_id' }) + transactionTypeId: number + + @Column({ name: 'balance', type: 'bigint' }) + balance: number + + @Column({ name: 'balance_date', type: 'timestamp' }) + balanceDate: Timestamp + + static findByUserPaged(userId: number, limit: number, offset: number, order: "ASC" | "DESC") + :Promise<[UserTransaction[], number]> + { + return this.createQueryBuilder('userTransaction') + .where('userTransaction.userId = :userId', { userId }) + .orderBy('userTransaction.balanceDate', order) + .limit(limit) + .offset(offset) + .getManyAndCount() + } +}