Merge pull request #2914 from gradido/feat-previous-balance

feat(backend): previous balance in transaction
This commit is contained in:
Moriz Wahl 2023-04-05 12:31:45 +02:00 committed by GitHub
commit fcb51f353f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 139 additions and 62 deletions

View File

@ -47,6 +47,10 @@ export class Transaction {
this.linkId = transaction.contribution this.linkId = transaction.contribution
? transaction.contribution.contributionLinkId ? transaction.contribution.contributionLinkId
: transaction.transactionLinkId || null : transaction.transactionLinkId || null
this.previousBalance =
(transaction.previousTransaction &&
transaction.previousTransaction.balance.toDecimalPlaces(2, Decimal.ROUND_DOWN)) ||
new Decimal(0)
} }
@Field(() => Int) @Field(() => Int)
@ -70,6 +74,9 @@ export class Transaction {
@Field(() => Date) @Field(() => Date)
balanceDate: Date balanceDate: Date
@Field(() => Decimal)
previousBalance: Decimal
@Field(() => Decay) @Field(() => Decay)
decay: Decay decay: Decay

View File

@ -275,6 +275,7 @@ export class TransactionResolver {
firstDate || now, firstDate || now,
lastDate || now, lastDate || now,
self, self,
(userTransactions.length && userTransactions[0].balance) || new Decimal(0),
), ),
) )
logger.debug(`transactions=${transactions}`) logger.debug(`transactions=${transactions}`)
@ -291,6 +292,15 @@ export class TransactionResolver {
}) })
logger.debug(`TransactionTypeId.CREATION: transactions=${transactions}`) logger.debug(`TransactionTypeId.CREATION: transactions=${transactions}`)
transactions.forEach((transaction: Transaction) => {
if (transaction.typeId !== TransactionTypeId.DECAY) {
const { balance, previousBalance, amount } = transaction
transaction.decay.decay = new Decimal(
Number(balance) - Number(amount) - Number(previousBalance),
).toDecimalPlaces(2, Decimal.ROUND_HALF_UP)
}
})
// Construct Result // Construct Result
return new TransactionList(await balanceResolver.balance(context), transactions) return new TransactionList(await balanceResolver.balance(context), transactions)
} }

View File

@ -2,7 +2,6 @@ import { EntityRepository, Repository } from '@dbTools/typeorm'
import { Transaction } from '@entity/Transaction' import { Transaction } from '@entity/Transaction'
import { Order } from '@enum/Order' import { Order } from '@enum/Order'
import { TransactionTypeId } from '@enum/TransactionTypeId'
@EntityRepository(Transaction) @EntityRepository(Transaction)
export class TransactionRepository extends Repository<Transaction> { export class TransactionRepository extends Repository<Transaction> {
@ -11,22 +10,15 @@ export class TransactionRepository extends Repository<Transaction> {
limit: number, limit: number,
offset: number, offset: number,
order: Order, order: Order,
onlyCreation?: boolean,
): Promise<[Transaction[], number]> { ): Promise<[Transaction[], number]> {
const query = this.createQueryBuilder('userTransaction') const query = this.createQueryBuilder('userTransaction')
.leftJoinAndSelect( .leftJoinAndSelect(
'userTransaction.contribution', 'userTransaction.previousTransaction',
'contribution', 'transaction',
'userTransaction.id = contribution.transactionId', 'userTransaction.previous = transaction.id',
) )
.where('userTransaction.userId = :userId', { userId }) .where('userTransaction.userId = :userId', { userId })
if (onlyCreation) {
query.andWhere('userTransaction.typeId = :typeId', {
typeId: TransactionTypeId.CREATION,
})
}
return query return query
.orderBy('userTransaction.balanceDate', order) .orderBy('userTransaction.balanceDate', order)
.limit(limit) .limit(limit)

View File

@ -38,6 +38,7 @@ const virtualLinkTransaction = (
createdAt: Date, createdAt: Date,
validUntil: Date, validUntil: Date,
user: User, user: User,
previousBalance: Decimal,
): Transaction => { ): Transaction => {
const linkDbTransaction: dbTransaction = { const linkDbTransaction: dbTransaction = {
id: -2, id: -2,

View File

@ -96,4 +96,8 @@ export class Transaction extends BaseEntity {
@OneToOne(() => Contribution, (contribution) => contribution.transaction) @OneToOne(() => Contribution, (contribution) => contribution.transaction)
@JoinColumn({ name: 'id', referencedColumnName: 'transactionId' }) @JoinColumn({ name: 'id', referencedColumnName: 'transactionId' })
contribution?: Contribution | null contribution?: Contribution | null
@OneToOne(() => Transaction)
@JoinColumn({ name: 'previous' })
previousTransaction?: Transaction | null
} }

View File

@ -12,7 +12,7 @@
</b-col> </b-col>
<b-col offset="1" offset-md="0" offset-lg="0"> <b-col offset="1" offset-md="0" offset-lg="0">
<div> <div>
{{ previousBookedBalance | GDD }} {{ previousBalance | GDD }}
{{ decay === '0' ? $t('math.minus') : '' }} {{ decay === '0' ? $t('math.minus') : '' }}
{{ decay | GDD }} {{ $t('math.equal') }} {{ decay | GDD }} {{ $t('math.equal') }}
<b>{{ balance | GDD }}</b> <b>{{ balance | GDD }}</b>
@ -35,7 +35,7 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
previousBookedBalance: { previousBalance: {
type: String, type: String,
required: true, required: true,
}, },

View File

@ -14,7 +14,7 @@
<b-col cols="12" lg="4" md="4"> <b-col cols="12" lg="4" md="4">
<div>{{ $t('decay.last_transaction') }}</div> <div>{{ $t('decay.last_transaction') }}</div>
</b-col> </b-col>
<b-col offset="1" offset-md="0" offset-lg="0"> <b-col offset="1" offset-md="0" offset-lg="0" class="text-right mr-5">
<div> <div>
<span> <span>
{{ $d(new Date(decay.start), 'long') }} {{ $d(new Date(decay.start), 'long') }}
@ -24,30 +24,44 @@
</b-row> </b-row>
<duration-row :decayStart="decay.start" :decayEnd="decay.end" /> <duration-row :decayStart="decay.start" :decayEnd="decay.end" />
<!-- Previous Balance -->
<b-row class="mt-2">
<b-col cols="12" lg="6" md="3">
<div>{{ $t('decay.old_balance') }}</div>
</b-col>
<b-col offset="1" offset-md="0" offset-lg="0" class="text-right mr-5">
{{ previousBalance | GDD }}
</b-col>
</b-row>
<!-- Decay--> <!-- Decay-->
<b-row> <b-row class="mt-0">
<b-col cols="12" lg="4" md="4"> <b-col cols="12" lg="3" md="3">
<div>{{ $t('decay.decay') }}</div> <div>{{ $t('decay.decay') }}</div>
</b-col> </b-col>
<b-col offset="1" offset-md="0" offset-lg="0">{{ decay.decay | GDD }}</b-col> <b-col offset="1" offset-md="0" offset-lg="0" class="text-right mr-5">
{{ decay.decay | GDD }}
</b-col>
</b-row> </b-row>
</b-col> </b-col>
</b-row> </b-row>
<!-- Type--> <!-- Type-->
<b-row> <b-row>
<b-col> <b-col>
<b-row> <b-row class="mb-2">
<!-- eslint-disable-next-line @intlify/vue-i18n/no-dynamic-keys--> <!-- eslint-disable-next-line @intlify/vue-i18n/no-dynamic-keys-->
<b-col cols="12" lg="4" md="4">{{ $t(`decay.types.${typeId.toLowerCase()}`) }}</b-col> <b-col cols="12" lg="3" md="3">{{ $t(`decay.types.${typeId.toLowerCase()}`) }}</b-col>
<b-col offset="1" offset-md="0" offset-lg="0">{{ amount | GDD }}</b-col> <b-col offset="1" offset-md="0" offset-lg="0" class="text-right mr-5">
{{ amount | GDD }}
</b-col>
</b-row> </b-row>
<!-- Total--> <!-- Total-->
<b-row> <b-row class="border-top pt-2">
<b-col cols="12" lg="4" md="4"> <b-col cols="12" lg="3" md="3">
<div>{{ $t('decay.total') }}</div> <div>{{ $t('decay.new_balance') }}</div>
</b-col> </b-col>
<b-col offset="1" offset-md="0" offset-lg="0"> <b-col offset="1" offset-md="0" offset-lg="0" class="text-right mr-5">
<b>{{ (Number(amount) + Number(decay.decay)) | GDD }}</b> <b>{{ balance | GDD }}</b>
</b-col> </b-col>
</b-row> </b-row>
</b-col> </b-col>
@ -63,6 +77,8 @@ export default {
DurationRow, DurationRow,
}, },
props: { props: {
balance: { type: String, default: '0' },
previousBalance: { type: String, default: '0' },
amount: { type: String, default: '0' }, amount: { type: String, default: '0' },
typeId: { type: String, default: '' }, typeId: { type: String, default: '' },
memo: { type: String, default: '' }, memo: { type: String, default: '' },

View File

@ -7,7 +7,15 @@
:decay="decay" :decay="decay"
:typeId="typeId" :typeId="typeId"
/> />
<decay-information-long v-else :amount="amount" :decay="decay" :typeId="typeId" :memo="memo" /> <decay-information-long
v-else
:amount="amount"
:decay="decay"
:typeId="typeId"
:memo="memo"
:balance="balance"
:previousBalance="previousBalance"
/>
</div> </div>
</template> </template>
<script> <script>
@ -39,6 +47,14 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
balance: {
type: String,
required: true,
},
previousBalance: {
type: String,
required: true,
},
}, },
computed: { computed: {
isStartBlock() { isStartBlock() {

View File

@ -93,8 +93,9 @@ describe('GddTransactionList', () => {
{ {
id: -1, id: -1,
typeId: 'DECAY', typeId: 'DECAY',
amount: '-0.16778637075575395772595', amount: '-0.16',
balance: '31.59320453982945549519405', balance: '31.59',
previousBalance: '31.75',
balanceDate: '2022-03-03T08:54:54', balanceDate: '2022-03-03T08:54:54',
memo: '', memo: '',
linkedUser: null, linkedUser: null,
@ -110,6 +111,7 @@ describe('GddTransactionList', () => {
typeId: 'SEND', typeId: 'SEND',
amount: '1', amount: '1',
balance: '31.76099091058520945292', balance: '31.76099091058520945292',
previousBalance: '30.76',
balanceDate: '2022-02-28T13:55:47', balanceDate: '2022-02-28T13:55:47',
memo: memo:
'Um den Kessel schlingt den Reihn, Werft die Eingeweid hinein. Kröte du, die Nacht und Tag Unterm kalten Steine lag,', 'Um den Kessel schlingt den Reihn, Werft die Eingeweid hinein. Kröte du, die Nacht und Tag Unterm kalten Steine lag,',
@ -129,6 +131,7 @@ describe('GddTransactionList', () => {
typeId: 'RECEIVE', typeId: 'RECEIVE',
amount: '10', amount: '10',
balance: '10', balance: '10',
previousBalance: '31.75',
balanceDate: '2022-02-23T10:55:30', balanceDate: '2022-02-23T10:55:30',
memo: memo:
'Monatlanges Gift sog ein, In den Topf zuerst hinein… (William Shakespeare, Die Hexen aus Macbeth)', 'Monatlanges Gift sog ein, In den Topf zuerst hinein… (William Shakespeare, Die Hexen aus Macbeth)',
@ -148,6 +151,7 @@ describe('GddTransactionList', () => {
typeId: 'CREATION', typeId: 'CREATION',
amount: '1000', amount: '1000',
balance: '32.96482231613347376132', balance: '32.96482231613347376132',
previousBalance: '31.75',
balanceDate: '2022-02-25T07:29:26', balanceDate: '2022-02-25T07:29:26',
memo: 'Jammern hilft nichts, sondern ich kann selber meinen Teil dazu beitragen.', memo: 'Jammern hilft nichts, sondern ich kann selber meinen Teil dazu beitragen.',
linkedUser: { linkedUser: {
@ -414,6 +418,7 @@ describe('GddTransactionList', () => {
return { return {
amount: '3.14', amount: '3.14',
balanceDate: '2021-04-29T17:26:40+00:00', balanceDate: '2021-04-29T17:26:40+00:00',
previousBalance: '31.75',
decay: { decay: {
decay: '-477.01', decay: '-477.01',
start: '2021-05-13T17:46:31.000Z', start: '2021-05-13T17:46:31.000Z',

View File

@ -19,10 +19,7 @@
class="pointer bg-white appBoxShadow gradido-border-radius px-4 pt-2 test-list-group-item" class="pointer bg-white appBoxShadow gradido-border-radius px-4 pt-2 test-list-group-item"
> >
<template #DECAY> <template #DECAY>
<transaction-decay <transaction-decay v-bind="transactions[index]" />
v-bind="transactions[index]"
:previousBookedBalance="previousBookedBalance(index)"
/>
</template> </template>
</transaction-list-item> </transaction-list-item>
</div> </div>
@ -34,24 +31,15 @@
class="pointer mb-3 bg-white appBoxShadow gradido-border-radius p-3 test-list-group-item" class="pointer mb-3 bg-white appBoxShadow gradido-border-radius p-3 test-list-group-item"
> >
<template #SEND> <template #SEND>
<transaction-send <transaction-send v-bind="transactions[index]" />
v-bind="transactions[index]"
:previousBookedBalance="previousBookedBalance(index)"
/>
</template> </template>
<template #RECEIVE> <template #RECEIVE>
<transaction-receive <transaction-receive v-bind="transactions[index]" />
v-bind="transactions[index]"
:previousBookedBalance="previousBookedBalance(index)"
/>
</template> </template>
<template #CREATION> <template #CREATION>
<transaction-creation <transaction-creation v-bind="transactions[index]" />
v-bind="transactions[index]"
:previousBookedBalance="previousBookedBalance(index)"
/>
</template> </template>
<template #LINK_SUMMARY> <template #LINK_SUMMARY>
@ -124,10 +112,6 @@ export default {
}) })
window.scrollTo(0, 0) window.scrollTo(0, 0)
}, },
previousBookedBalance(idx) {
if (this.transactions[idx + 1]) return this.transactions[idx + 1].balance
return '0'
},
}, },
computed: { computed: {
isPaginationVisible() { isPaginationVisible() {

View File

@ -4,7 +4,7 @@
<b-col cols="12" lg="4" md="4"> <b-col cols="12" lg="4" md="4">
<div>{{ $t('decay.past_time') }}</div> <div>{{ $t('decay.past_time') }}</div>
</b-col> </b-col>
<b-col offset="1" offset-md="0" offset-lg="0"> <b-col offset="1" offset-md="0" offset-lg="0" class="text-right mr-5">
<span v-if="duration">{{ durationText }}</span> <span v-if="duration">{{ durationText }}</span>
</b-col> </b-col>
</b-row> </b-row>

View File

@ -13,7 +13,8 @@ const mocks = {
const propsData = { const propsData = {
amount: '12.45', amount: '12.45',
balance: '31.76099091058521', balance: '31.76',
previousBalance: '19.31',
balanceDate: '2022-02-28T13:55:47.000Z', balanceDate: '2022-02-28T13:55:47.000Z',
decay: { decay: {
decay: '-0.2038314055482643084', decay: '-0.2038314055482643084',

View File

@ -18,7 +18,14 @@
</b-col> </b-col>
</b-row> </b-row>
<b-collapse class="pb-4 pt-lg-3" v-model="visible"> <b-collapse class="pb-4 pt-lg-3" v-model="visible">
<decay-information :typeId="typeId" :decay="decay" :amount="amount" :memo="memo" /> <decay-information
:typeId="typeId"
:decay="decay"
:amount="amount"
:memo="memo"
:balance="balance"
:previousBalance="previousBalance"
/>
</b-collapse> </b-collapse>
</div> </div>
</template> </template>
@ -61,7 +68,11 @@ export default {
type: Number, type: Number,
required: false, required: false,
}, },
previousBookedBalance: { balance: {
type: String,
required: true,
},
previousBalance: {
type: String, type: String,
required: true, required: true,
}, },

View File

@ -14,7 +14,7 @@
<decay-information-decay <decay-information-decay
:balance="balance" :balance="balance"
:decay="decay.decay" :decay="decay.decay"
:previousBookedBalance="previousBookedBalance" :previousBalance="previousBalance"
/> />
</b-collapse> </b-collapse>
</div> </div>
@ -44,9 +44,10 @@ export default {
type: Object, type: Object,
required: true, required: true,
}, },
previousBookedBalance: { },
type: String, computed: {
required: true, previousBalance() {
return String(Number(this.balance) - Number(this.decay.decay))
}, },
}, },
data() { data() {

View File

@ -13,7 +13,8 @@ const mocks = {
const propsData = { const propsData = {
amount: '12.45', amount: '12.45',
balance: '31.76099091058521', balance: '31.76',
previousBalance: '19.31',
balanceDate: '2022-02-28T13:55:47.000Z', balanceDate: '2022-02-28T13:55:47.000Z',
decay: { decay: {
decay: '-0.2038314055482643084', decay: '-0.2038314055482643084',

View File

@ -42,7 +42,14 @@
</b-col> </b-col>
</b-row> </b-row>
<b-collapse class="pb-4 pt-lg-3" v-model="visible"> <b-collapse class="pb-4 pt-lg-3" v-model="visible">
<decay-information :typeId="typeId" :decay="decay" :amount="amount" :memo="memo" /> <decay-information
:typeId="typeId"
:decay="decay"
:amount="amount"
:memo="memo"
:balance="balance"
:previousBalance="previousBalance"
/>
</b-collapse> </b-collapse>
</div> </div>
</template> </template>
@ -84,7 +91,11 @@ export default {
typeId: { typeId: {
type: String, type: String,
}, },
previousBookedBalance: { balance: {
type: String,
required: true,
},
previousBalance: {
type: String, type: String,
required: true, required: true,
}, },

View File

@ -13,7 +13,8 @@ const mocks = {
const propsData = { const propsData = {
amount: '12.45', amount: '12.45',
balance: '31.76099091058521', balance: '31.76',
previousBalance: '19.31',
balanceDate: '2022-02-28T13:55:47.000Z', balanceDate: '2022-02-28T13:55:47.000Z',
decay: { decay: {
decay: '-0.2038314055482643084', decay: '-0.2038314055482643084',

View File

@ -41,7 +41,14 @@
</b-col> </b-col>
</b-row> </b-row>
<b-collapse class="pb-4 pt-lg-3" v-model="visible"> <b-collapse class="pb-4 pt-lg-3" v-model="visible">
<decay-information :typeId="typeId" :decay="decay" :amount="amount" :memo="memo" /> <decay-information
:typeId="typeId"
:decay="decay"
:amount="amount"
:memo="memo"
:balance="balance"
:previousBalance="previousBalance"
/>
</b-collapse> </b-collapse>
</div> </div>
</template> </template>
@ -84,7 +91,11 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
previousBookedBalance: { balance: {
type: String,
required: true,
},
previousBalance: {
type: String, type: String,
required: true, required: true,
}, },

View File

@ -33,6 +33,7 @@ export const transactionsQuery = gql`
typeId typeId
amount amount
balance balance
previousBalance
balanceDate balanceDate
memo memo
linkedUser { linkedUser {

View File

@ -89,6 +89,8 @@
"decay_introduced": "Die Vergänglichkeit wurde eingeführt am:", "decay_introduced": "Die Vergänglichkeit wurde eingeführt am:",
"decay_since_last_transaction": "Vergänglichkeit seit der letzten Transaktion", "decay_since_last_transaction": "Vergänglichkeit seit der letzten Transaktion",
"last_transaction": "Letzte Transaktion", "last_transaction": "Letzte Transaktion",
"new_balance": "Neuer Kontostand",
"old_balance": "Vorheriger Kontostand",
"past_time": "Vergangene Zeit", "past_time": "Vergangene Zeit",
"Starting_block_decay": "Startblock Vergänglichkeit", "Starting_block_decay": "Startblock Vergänglichkeit",
"total": "Gesamt", "total": "Gesamt",

View File

@ -89,6 +89,8 @@
"decay_introduced": "Decay was introduced on:", "decay_introduced": "Decay was introduced on:",
"decay_since_last_transaction": "Decay since the last transaction", "decay_since_last_transaction": "Decay since the last transaction",
"last_transaction": "Last transaction:", "last_transaction": "Last transaction:",
"new_balance": "New balance",
"old_balance": "Previous balance",
"past_time": "Time passed", "past_time": "Time passed",
"Starting_block_decay": "Starting Block Decay", "Starting_block_decay": "Starting Block Decay",
"total": "Total", "total": "Total",