mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge pull request #607 from gradido/309-Transaction-details-design
feat: Transaction Details
This commit is contained in:
commit
3dcd88953f
@ -25,7 +25,7 @@ class AppRequestsController extends AppController
|
||||
$this->loadComponent('GradidoNumber');
|
||||
//$this->loadComponent('JsonRpcRequestClient');
|
||||
//$this->Auth->allow(['add', 'edit']);
|
||||
$this->Auth->allow(['index', 'sendCoins', 'createCoins', 'getBalance', 'listTransactions']);
|
||||
$this->Auth->allow(['index', 'sendCoins', 'createCoins', 'getBalance', 'listTransactions', 'getDecayStartBlock']);
|
||||
}
|
||||
|
||||
|
||||
@ -335,11 +335,21 @@ class AppRequestsController extends AppController
|
||||
|
||||
$limit = $count;
|
||||
$offset = 0;
|
||||
$skip_first_transaction = false;
|
||||
if($page == 1) {
|
||||
$limit--;
|
||||
} else {
|
||||
$offset = (( $page - 1 ) * $count) - 1;
|
||||
}
|
||||
if($offset && $orderDirection == 'ASC') {
|
||||
// move cursor one step backwards to able to load one transaction previous last which will be shown for decay calculation
|
||||
$offset--;
|
||||
$limit++;
|
||||
$skip_first_transaction = true;
|
||||
} else if($orderDirection == 'DESC') {
|
||||
$limit++;
|
||||
$skip_first_transaction = true;
|
||||
}
|
||||
|
||||
$stateUserTransactionsQuery = $stateUserTransactionsTable
|
||||
->find()
|
||||
@ -362,7 +372,7 @@ class AppRequestsController extends AppController
|
||||
$transactions_from_db = array_reverse($transactions_from_db);
|
||||
}
|
||||
|
||||
$transactions = $transactionsTable->listTransactionsHumanReadable($transactions_from_db, $user, $decay);
|
||||
$transactions = $transactionsTable->listTransactionsHumanReadable($transactions_from_db, $user, $decay, $skip_first_transaction);
|
||||
|
||||
if($orderDirection == 'DESC') {
|
||||
$transactions = array_reverse($transactions);
|
||||
@ -393,6 +403,16 @@ class AppRequestsController extends AppController
|
||||
$this->set('body', $body);
|
||||
}
|
||||
|
||||
public function getDecayStartBlock()
|
||||
{
|
||||
$transactionsTable = TableRegistry::getTableLocator()->get('Transactions');
|
||||
$decayStartBlock = $transactionsTable->find()->where(['transaction_type_id' => 9]);
|
||||
if(!$decayStartBlock->count()) {
|
||||
return $this->returnJson(['state' => 'error', 'msg' => 'not found']);
|
||||
}
|
||||
return $this->returnJson(['state' => 'success', 'decay_start' => $decayStartBlock->first()->received]);
|
||||
}
|
||||
|
||||
private function acquireAccessToken($session_id)
|
||||
{
|
||||
|
||||
|
||||
@ -133,11 +133,12 @@ class TransactionsTable extends Table
|
||||
}
|
||||
|
||||
|
||||
public function listTransactionsHumanReadable($stateUserTransactions, array $user, $decay = true)
|
||||
public function listTransactionsHumanReadable($stateUserTransactions, array $user, $decay = true, $skip_first_transaction = false)
|
||||
{
|
||||
|
||||
$stateUsersTable = TableRegistry::getTableLocator()->get('StateUsers');
|
||||
$stateBalancesTable = TableRegistry::getTableLocator()->get('StateBalances');
|
||||
$transactionsTable = TableRegistry::getTableLocator()->get('Transactions');
|
||||
|
||||
$transaction_ids = [];
|
||||
$involved_user_ids = [];
|
||||
@ -162,11 +163,15 @@ class TransactionsTable extends Table
|
||||
|
||||
$state_balance = $stateBalancesTable->newEntity();
|
||||
$final_transactions = [];
|
||||
$decay_start_transaction = $transactionsTable->find()->where(['transaction_type_id' => 9]);
|
||||
$decay_start_transaction_id = 0;
|
||||
if($decay_start_transaction->count()) {
|
||||
$decay_start_transaction_id = $decay_start_transaction->first()->id;
|
||||
}
|
||||
$decay_start_time = $stateBalancesTable->getDecayStartDateCached()->getTimestamp();
|
||||
|
||||
foreach($stateUserTransactions as $i => $su_transaction)
|
||||
{
|
||||
|
||||
|
||||
// sender or receiver when user has sended money
|
||||
// group name if creation
|
||||
// type: gesendet / empfangen / geschöpft
|
||||
@ -187,7 +192,8 @@ class TransactionsTable extends Table
|
||||
}
|
||||
if($prev)
|
||||
{
|
||||
if($prev->balance > 0) {
|
||||
if($prev->balance > 0)
|
||||
{
|
||||
$current = $su_transaction;
|
||||
$calculated_decay = $stateBalancesTable->calculateDecay($prev->balance, $prev->balance_date, $current->balance_date, true);
|
||||
$balance = floatval($prev->balance - $calculated_decay['balance']);
|
||||
@ -199,7 +205,19 @@ class TransactionsTable extends Table
|
||||
'decay_duration' => $calculated_decay['interval']->format('%a days, %H hours, %I minutes, %S seconds'),
|
||||
'decay_start' => $calculated_decay['start_date'],
|
||||
'decay_end' => $calculated_decay['end_date']
|
||||
];
|
||||
];
|
||||
if($prev->transaction_id < $decay_start_transaction_id &&
|
||||
$current->transaction_id > $decay_start_transaction_id) {
|
||||
$final_transaction['decay']['decay_start_block'] = $decay_start_time;
|
||||
}
|
||||
// hint: use transaction id
|
||||
/*if($calculated_decay['start_date'] < $decay_start_time && $calculated_decay['end_date'] > $decay_start_time) {
|
||||
$final_transaction['decay']['decay_start_block'] = $decay_start_time;
|
||||
} else {
|
||||
echo "start block: " . $decay_start_time . "<br>";
|
||||
echo "start date: " . $calculated_decay['start_date'] . "<br>";
|
||||
echo "end date: " . $calculated_decay['end_date']. "<hr>";
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -249,8 +267,9 @@ class TransactionsTable extends Table
|
||||
$final_transaction['name'] = $otherUser->first_name . ' ' . $otherUser->last_name;
|
||||
$final_transaction['email'] = $otherUser->email;
|
||||
}
|
||||
|
||||
$final_transactions[] = $final_transaction;
|
||||
if($i > 0 || !$skip_first_transaction) {
|
||||
$final_transactions[] = $final_transaction;
|
||||
}
|
||||
|
||||
if($i == $stateUserTransactionsCount-1 && $decay) {
|
||||
$now = new FrozenTime();
|
||||
|
||||
@ -205,11 +205,12 @@ class AppRequestControllerTest extends TestCase
|
||||
"transaction_id": 7,
|
||||
"date": "2021-04-14T09:02:28+00:00",
|
||||
"memo": "test time 3",
|
||||
"decay": {
|
||||
"decay": {
|
||||
"balance": 6,
|
||||
"decay_duration": "0 days, 00 hours, 00 minutes, 28 seconds",
|
||||
"decay_start": 1618390920,
|
||||
"decay_end": 1618390948
|
||||
"decay_end": 1618390948,
|
||||
"decay_start_block": 1618390920
|
||||
},
|
||||
"balance": 100000,
|
||||
"type": "receive",
|
||||
@ -237,7 +238,7 @@ class AppRequestControllerTest extends TestCase
|
||||
"transaction_id": 9,
|
||||
"date": "2021-04-14T09:31:28+00:00",
|
||||
"memo": "test login crash",
|
||||
"decay": {
|
||||
"decay": {
|
||||
"balance": 33,
|
||||
"decay_duration": "0 days, 00 hours, 02 minutes, 42 seconds",
|
||||
"decay_start": 1618392526,
|
||||
@ -251,20 +252,20 @@ class AppRequestControllerTest extends TestCase
|
||||
},
|
||||
{
|
||||
"type": "decay",
|
||||
"balance": 1222493,
|
||||
"balance": 1345726,
|
||||
"decay_duration": "on 14.04.21",
|
||||
"decay_start": 1618392688,
|
||||
"decay_end": 1624956464,
|
||||
"decay_end": 1625673853,
|
||||
"memo": ""
|
||||
}
|
||||
],
|
||||
"transactionExecutingCount": 0,
|
||||
"count": 7,
|
||||
"gdtSum": 180000,
|
||||
"timeUsed": 0.6441609859466553,
|
||||
"decay_date": "2021-06-29T08:47:44+00:00",
|
||||
"timeUsed": 0.44154810905456545,
|
||||
"decay_date": "2021-07-07T16:04:13+00:00",
|
||||
"balance": 9099652,
|
||||
"decay": 7877159
|
||||
"decay": 7753926
|
||||
}';
|
||||
$this->getAndParse('/api/list-transactions/', json_decode($expectedResult, true));
|
||||
}
|
||||
|
||||
97
frontend/src/components/DecayInformation.vue
Normal file
97
frontend/src/components/DecayInformation.vue
Normal file
@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div>
|
||||
<span v-if="decaytyp === 'short'">
|
||||
<small>{{ decay ? ' ' + decay.balance + ' ' + decayStartBlockTextShort : '' }}</small>
|
||||
</span>
|
||||
|
||||
<div v-if="decaytyp === 'new'">
|
||||
<b-list-group style="border: 0px">
|
||||
<b-list-group-item style="border: 0px; background-color: #f1f1f1">
|
||||
<div class="d-flex">
|
||||
<div style="width: 40%" class="text-right pr-3 mr-2">
|
||||
{{ $t('decay.calculation_decay') }}
|
||||
<b-icon icon="droplet-half" height="12" class="mb-2" />
|
||||
</div>
|
||||
<div style="width: 60%"></div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex">
|
||||
<div style="width: 40%" class="text-right pr-3 mr-2">
|
||||
{{ $t('decay.last_transaction') }}
|
||||
</div>
|
||||
<div style="width: 60%">
|
||||
<div v-if="decay.decay_start_block > 0">
|
||||
<div class="display-4">{{ $t('decay.Starting_block_decay') }}</div>
|
||||
<div>
|
||||
{{ $t('decay.decay_introduced') }} :
|
||||
{{ $d($moment.unix(decay.decay_start), 'long') }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ $d($moment.unix(decay.decay_start), 'long') }} Uhr</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex">
|
||||
<div style="width: 40%" class="text-right pr-3 mr-2">
|
||||
{{ $t('decay.past_time') }}
|
||||
</div>
|
||||
<div style="width: 60%">
|
||||
<div v-if="decay.decay_start_block > 0">{{ $t('decay.since_introduction') }}</div>
|
||||
<i>{{ getDuration(decay.decay_end, decay.decay_start) }}</i>
|
||||
<span v-if="this.duration != {}">
|
||||
<b v-if="duration.years > 0">{{ duration.years }} {{ $t('decay.year') }},</b>
|
||||
<b v-if="duration.months > 0">{{ duration.months }} {{ $t('decay.months') }},</b>
|
||||
<b v-if="duration.days > 0">{{ duration.days }} {{ $t('decay.days') }},</b>
|
||||
<b v-if="duration.hours > 0">{{ duration.hours }} {{ $t('decay.hours') }},</b>
|
||||
<b v-if="duration.minutes > 0">{{ duration.minutes }} {{ $t('decay.minutes') }},</b>
|
||||
<b v-if="duration.seconds > 0">{{ duration.seconds }} {{ $t('decay.seconds') }}</b>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</b-list-group-item>
|
||||
</b-list-group>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'DecayInformation',
|
||||
props: {
|
||||
decay: {
|
||||
balance: '',
|
||||
decay_duration: '',
|
||||
decay_start: 0,
|
||||
decay_end: 0,
|
||||
decay_start_block: 0,
|
||||
},
|
||||
decaytyp: { type: String, default: '' },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
a: 0,
|
||||
b: 0,
|
||||
duration: {},
|
||||
diff: {},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
decayStartBlockTextShort() {
|
||||
return this.decay.decay_start_block
|
||||
? ' - Startblock Decay am: ' + this.$d(this.$moment.unix(this.decay.decay_start_block))
|
||||
: ''
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getDuration(start, end) {
|
||||
this.a = new Date(start)
|
||||
this.b = new Date(end)
|
||||
this.a = this.$moment.unix(this.a)
|
||||
this.b = this.$moment.unix(this.b)
|
||||
this.diff = this.$moment.duration(this.a.diff(this.b))
|
||||
this.duration = this.diff._data
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -18,7 +18,25 @@
|
||||
"de": "Deutsch",
|
||||
"en": "English"
|
||||
},
|
||||
"decay": "Vergänglichkeit",
|
||||
"decay": {
|
||||
"decay": "Vergänglichkeit",
|
||||
"decay_since_last_transaction":"Vergänglichkeit seit der letzten Transaktion",
|
||||
"calculation_decay":"Berechnung der Vergänglichkeit",
|
||||
"Starting_block_decay":"Startblock Vergänglichkeit",
|
||||
"decay_introduced":"Die Vergänglichkeit wurde Eingeführt am",
|
||||
"last_transaction":"Letzte Transaktion",
|
||||
"past_time":"Vergangene Zeit",
|
||||
"since_introduction":"seit Einführung der Vergänglichkeit",
|
||||
"year":"Jahre",
|
||||
"months":"Monate",
|
||||
"days":"Tage",
|
||||
"hours":"Stunden",
|
||||
"minutes":"Minuten",
|
||||
"seconds":"Sekunden",
|
||||
"received":"empfangen",
|
||||
"sent":"gesendet",
|
||||
"created":"geschöpft"
|
||||
},
|
||||
"form": {
|
||||
"cancel": "Abbrechen",
|
||||
"reset": "Zurücksetzen",
|
||||
|
||||
@ -18,7 +18,25 @@
|
||||
"de": "Deutsch",
|
||||
"en": "English"
|
||||
},
|
||||
"decay": "Decay",
|
||||
"decay": {
|
||||
"decay": "Decay",
|
||||
"decay_since_last_transaction":"Decay since the last transaction",
|
||||
"calculation_decay": "Calculation of Decay",
|
||||
"Starting_block_decay": "Starting Block Decay",
|
||||
"decay_introduced": "Decay was Introduced on",
|
||||
"last_transaction": "Last transaction:",
|
||||
"past_time": "Past time",
|
||||
"since_introduction": "Since the introduction of Decay",
|
||||
"year": "Years",
|
||||
"months": "Months",
|
||||
"days": "Days",
|
||||
"hours": "Hours",
|
||||
"minutes": "Minutes",
|
||||
"seconds": "Seconds",
|
||||
"received":"received",
|
||||
"sent":"sent",
|
||||
"created":"created"
|
||||
},
|
||||
"form": {
|
||||
"cancel":"Cancel",
|
||||
"reset": "Reset",
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
<gdd-transaction-list
|
||||
v-if="showContext"
|
||||
:transactions="transactions"
|
||||
:page-size="5"
|
||||
:pageSize="5"
|
||||
:timestamp="timestamp"
|
||||
:transaction-count="transactionCount"
|
||||
@update-transactions="updateTransactions"
|
||||
|
||||
@ -203,7 +203,7 @@ describe('GddTransactionList', () => {
|
||||
})
|
||||
|
||||
it('shows the name of the receiver', () => {
|
||||
expect(transaction.findAll('div').at(3).text()).toBe('decay')
|
||||
expect(transaction.findAll('div').at(3).text()).toBe('decay.decay_since_last_transaction')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -2,69 +2,79 @@
|
||||
<div class="gdd-transaction-list">
|
||||
<b-list-group>
|
||||
<b-list-group-item
|
||||
v-for="item in transactions"
|
||||
:key="item.id"
|
||||
style="background-color: #ebebeba3 !important"
|
||||
v-for="{ decay, transaction_id, type, date, balance, name, memo } in transactions"
|
||||
:key="transaction_id"
|
||||
:style="type === 'decay' ? 'background-color:#f1e0ae3d' : ''"
|
||||
>
|
||||
<div class="d-flex gdd-transaction-list-item" v-b-toggle="'a' + item.date + ''">
|
||||
<!-- ROW Start -->
|
||||
<div class="d-flex gdd-transaction-list-item" v-b-toggle="'a' + date + ''">
|
||||
<!-- ICON -->
|
||||
<div style="width: 8%">
|
||||
<b-icon :icon="getProperties(item).icon" :class="getProperties(item).class" />
|
||||
<b-icon :icon="getProperties(type).icon" :class="getProperties(type).class" />
|
||||
</div>
|
||||
<!-- Text Links -->
|
||||
<div class="font1_2em pr-2 text-right" style="width: 32%">
|
||||
<span>{{ getProperties(item).operator }}</span>
|
||||
{{ $n(item.balance, 'decimal') }}
|
||||
<span>{{ getProperties(type).operator }}</span>
|
||||
<small v-if="type === 'decay'">{{ $n(balance, 'decimal') }}</small>
|
||||
|
||||
<span v-else>{{ $n(balance, 'decimal') }}</span>
|
||||
|
||||
<div v-if="decay">
|
||||
<br />
|
||||
<b-icon v-if="type != 'decay'" icon="droplet-half" height="15" class="mb-3" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Text Rechts -->
|
||||
<div class="font1_2em text-left pl-2" style="width: 55%">
|
||||
{{ item.name ? item.name : $t('decay') }}
|
||||
<div v-if="item.date" class="text-sm">{{ $d($moment(item.date), 'long') }}</div>
|
||||
{{ name ? name : '' }}
|
||||
<span v-if="type === 'decay'">
|
||||
<small>{{ $t('decay.decay_since_last_transaction') }}</small>
|
||||
</span>
|
||||
<div v-if="date" class="text-sm">{{ $d($moment(date), 'long') }}</div>
|
||||
<decay-information v-if="decay" decaytyp="short" :decay="decay" />
|
||||
</div>
|
||||
<div class="text-right" style="width: 5%">
|
||||
<!-- Collaps Toggle Button -->
|
||||
<div v-if="type != 'decay'" class="text-right" style="width: 5%">
|
||||
<b-button class="btn-sm">
|
||||
<b>i</b>
|
||||
</b-button>
|
||||
</div>
|
||||
</div>
|
||||
<b-collapse :id="'a' + item.date + ''" class="mt-2">
|
||||
<b-card>
|
||||
<b-list-group>
|
||||
<b-list-group-item v-if="item.type === 'send'">
|
||||
<b-badge class="mr-4" variant="primary" pill>{{ $t('form.receiver') }}</b-badge>
|
||||
{{ item.name }}
|
||||
</b-list-group-item>
|
||||
<b-list-group-item v-else>
|
||||
<b-badge class="mr-4" variant="primary" pill>{{ $t('form.sender') }}</b-badge>
|
||||
{{ item.name }}
|
||||
</b-list-group-item>
|
||||
|
||||
<b-list-group-item>
|
||||
<b-badge class="mr-4" variant="primary" pill>type</b-badge>
|
||||
{{ item.type }}
|
||||
</b-list-group-item>
|
||||
<b-list-group-item>
|
||||
<b-badge class="mr-5" variant="primary" pill>id</b-badge>
|
||||
{{ item.transaction_id }}
|
||||
</b-list-group-item>
|
||||
<b-list-group-item>
|
||||
<b-badge class="mr-4" variant="primary" pill>{{ $t('form.date') }}</b-badge>
|
||||
{{ item.date }}
|
||||
</b-list-group-item>
|
||||
<b-list-group-item>
|
||||
<b-badge class="mr-4" variant="primary" pill>gdd</b-badge>
|
||||
{{ item.balance }}
|
||||
</b-list-group-item>
|
||||
<b-list-group-item>
|
||||
<b-badge class="mr-4" variant="primary" pill>{{ $t('form.memo') }}</b-badge>
|
||||
{{ item.memo }}
|
||||
</b-list-group-item>
|
||||
</b-list-group>
|
||||
<b-button v-b-toggle="'collapse-1-inner' + item.date" variant="secondary">
|
||||
{{ $t('transaction.more') }}
|
||||
</b-button>
|
||||
<b-collapse :id="'collapse-1-inner' + item.date" class="mt-2">
|
||||
<b-card>{{ item }}</b-card>
|
||||
</b-collapse>
|
||||
</b-card>
|
||||
<!-- ROW End -->
|
||||
<!-- Collaps Start -->
|
||||
<b-collapse v-if="type != 'decay'" :id="'a' + date + ''">
|
||||
<b-list-group v-if="type === 'receive' || type === 'send'">
|
||||
<b-list-group-item style="border: 0px; background-color: #f1f1f1">
|
||||
<div class="d-flex">
|
||||
<div style="width: 40%" class="text-right pr-3 mr-2">
|
||||
{{ type === 'receive' ? 'von:' : 'an:' }}
|
||||
</div>
|
||||
<div style="width: 60%">
|
||||
{{ name }}
|
||||
<b-avatar class="mr-3"></b-avatar>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div style="width: 40%" class="text-right pr-3 mr-2">
|
||||
{{ type === 'receive' ? 'Nachricht:' : 'Nachricht:' }}
|
||||
</div>
|
||||
<div style="width: 60%">
|
||||
{{ memo }}
|
||||
</div>
|
||||
</div>
|
||||
</b-list-group-item>
|
||||
</b-list-group>
|
||||
<b-list-group v-if="type === 'creation'">
|
||||
<b-list-group-item style="border: 0px">
|
||||
<div class="d-flex">
|
||||
<div style="width: 40%" class="text-right pr-3 mr-2">Schöpfung</div>
|
||||
<div style="width: 60%">Aus der Community</div>
|
||||
</div>
|
||||
</b-list-group-item>
|
||||
</b-list-group>
|
||||
<decay-information v-if="decay" decaytyp="new" :decay="decay" />
|
||||
</b-collapse>
|
||||
<!-- Collaps End -->
|
||||
</b-list-group-item>
|
||||
<pagination-buttons
|
||||
v-if="showPagination && transactionCount > pageSize"
|
||||
@ -84,6 +94,7 @@
|
||||
|
||||
<script>
|
||||
import PaginationButtons from '../../../components/PaginationButtons'
|
||||
import DecayInformation from '../../../components/DecayInformation'
|
||||
|
||||
const iconsByType = {
|
||||
send: { icon: 'arrow-left-circle', classes: 'text-danger', operator: '-' },
|
||||
@ -96,10 +107,12 @@ export default {
|
||||
name: 'gdd-transaction-list',
|
||||
components: {
|
||||
PaginationButtons,
|
||||
DecayInformation,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentPage: 1,
|
||||
startDecay: 0,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
@ -133,8 +146,8 @@ export default {
|
||||
items: this.pageSize,
|
||||
})
|
||||
},
|
||||
getProperties(item) {
|
||||
const type = iconsByType[item.type]
|
||||
getProperties(givenType) {
|
||||
const type = iconsByType[givenType]
|
||||
if (type)
|
||||
return {
|
||||
icon: type.icon,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user