mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
update decay code, use different approach as before, more easy coding
This commit is contained in:
parent
130397e2bb
commit
25b0ae28ed
@ -4,6 +4,6 @@ CREATE TABLE `state_user_transactions` (
|
||||
`transaction_id` int UNSIGNED NOT NULL,
|
||||
`transaction_type_id` int UNSIGNED NOT NULL,
|
||||
`balance` bigint(20) DEFAULT 0,
|
||||
`balance_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`balance_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
@ -108,7 +108,7 @@ class JsonRequestHandlerController extends AppController {
|
||||
if($last_transaction_query->count() < $last_transaction_id) {
|
||||
$last_transaction_id = $last_transaction_query->count();
|
||||
}
|
||||
$last_transaction_id = 0;
|
||||
//$last_transaction_id = 0;
|
||||
|
||||
|
||||
$group_alias = Configure::read('GroupAlias');
|
||||
|
||||
@ -41,33 +41,145 @@ class StateBalancesController extends AppController
|
||||
|
||||
$this->set(compact('stateBalances'));
|
||||
}
|
||||
|
||||
private function updateBalances($state_user_id)
|
||||
|
||||
private function updateBalance($stateUserId)
|
||||
{
|
||||
$state_balances = $this->StateBalances->find('all')->where(['state_user_id' => $state_user_id]);
|
||||
if($state_balances->count() == 1) {
|
||||
$stateUserTransactionsTable = TableRegistry::getTableLocator()->get('StateUserTransactions');
|
||||
$state_user_transactions = $stateUserTransactionsTable
|
||||
$stateUserTransactionsTable = TableRegistry::getTableLocator()->get('StateUserTransactions');
|
||||
$transactionsTable = TableRegistry::getTableLocator()->get('Transactions');
|
||||
// info: cakephp use lazy loading, query will be executed later only if needed
|
||||
$state_balances = $this->StateBalances->find('all')->where(['state_user_id' => $stateUserId]);
|
||||
$state_user_transactions = $stateUserTransactionsTable
|
||||
->find('all')
|
||||
->where(['state_user_id' => $state_user_id])
|
||||
->where(['state_user_id' => $stateUserId])
|
||||
->order(['transaction_id ASC'])
|
||||
->contain(['']);
|
||||
if($state_user_transactions->count() == 0){
|
||||
return;
|
||||
}
|
||||
$last_state_user_transaction = $state_user_transactions->last();
|
||||
$last_transaction = $this->StateBalance->newEntity();
|
||||
$last_transaction->amount = $last_state_user_transaction->balance;
|
||||
$last_transaction->record_date = $last_state_user_transaction->balance_date;
|
||||
// if entrys are nearly the same, we don't need doing anything
|
||||
if(abs($last_transaction->decay - $state_balances->decay) < 100) {
|
||||
return;
|
||||
}
|
||||
foreach($state_user_transactions as $state_user_transaction) {
|
||||
|
||||
}
|
||||
|
||||
->contain(false);
|
||||
|
||||
if(!$state_user_transactions) {
|
||||
//debug($state_user_transactions);
|
||||
return true;
|
||||
}
|
||||
|
||||
// first: decide what todo
|
||||
$create_state_balance = false;
|
||||
$recalculate_state_user_transactions_balance = false;
|
||||
$clear_state_balance = false;
|
||||
$update_state_balance = false;
|
||||
if($state_balances->count() == 0) {
|
||||
$create_state_balance = true;
|
||||
}
|
||||
if($state_balances->count() > 1) {
|
||||
$clear_state_balance = true;
|
||||
$create_state_balance = true;
|
||||
}
|
||||
if($state_balances->count() == 1) {
|
||||
if($state_user_transactions->count() == 0){
|
||||
$clear_state_balance = true;
|
||||
} else {
|
||||
$last_state_user_transaction = $state_user_transactions->last();
|
||||
$last_transaction = $this->StateBalances->newEntity();
|
||||
$last_transaction->amount = $last_state_user_transaction->balance;
|
||||
$last_transaction->record_date = $last_state_user_transaction->balance_date;
|
||||
// if entrys are nearly the same, we don't need doing anything
|
||||
if(abs($last_transaction->decay - $state_balances->first()->decay) > 100) {
|
||||
$recalculate_state_user_transactions_balance = true;
|
||||
$update_state_balance = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!$recalculate_state_user_transactions_balance) {
|
||||
$last_state_user_transaction = $state_user_transactions->last();
|
||||
if($last_state_user_transaction->balance <= 0) {
|
||||
$recalculate_state_user_transactions_balance = true;
|
||||
if(!$create_state_balance) {
|
||||
$update_state_balance = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// second: do what is needed
|
||||
if($clear_state_balance) {
|
||||
$this->StateBalances->deleteAll(['state_user_id' => $stateUserId]);
|
||||
}
|
||||
|
||||
$transaction_ids = [];
|
||||
if($recalculate_state_user_transactions_balance) {
|
||||
$state_user_transactions_array = $state_user_transactions->toArray();
|
||||
foreach($state_user_transactions_array as $i => $state_user_transaction) {
|
||||
$transaction_ids[$state_user_transaction->transaction_id] = $i;
|
||||
}
|
||||
|
||||
$transactions = $transactionsTable
|
||||
->find('all')
|
||||
->where(['id IN' => array_keys($transaction_ids)])
|
||||
->contain(['TransactionCreations', 'TransactionSendCoins']);
|
||||
|
||||
$balance_cursor = $this->StateBalances->newEntity();
|
||||
$i = 0;
|
||||
foreach($transactions as $transaction) {
|
||||
if($transaction->transaction_type_id > 2) {
|
||||
continue;
|
||||
}
|
||||
$amount_date = null;
|
||||
$amount = 0;
|
||||
|
||||
if($transaction->transaction_type_id == 1) {
|
||||
$temp = $transaction->transaction_creations[0];
|
||||
|
||||
$balance_temp = $this->StateBalances->newEntity();
|
||||
$balance_temp->amount = $temp->amount;
|
||||
$balance_temp->record_date = $temp->target_date;
|
||||
|
||||
$amount = $balance_temp->partDecay($transaction->received);
|
||||
$amount_date = $transaction->received;
|
||||
//$amount_date =
|
||||
} else if($transaction->transaction_type_id == 2) {
|
||||
$temp = $transaction->transaction_send_coins[0];
|
||||
$amount = intval($temp->amount);
|
||||
// reverse if sender
|
||||
if($stateUserId == $temp->state_user_id) {
|
||||
$amount *= -1.0;
|
||||
}
|
||||
$amount_date = $transaction->received;
|
||||
}
|
||||
if($i == 0) {
|
||||
$balance_cursor->amount = $amount;
|
||||
} else {
|
||||
$balance_cursor->amount = $balance_cursor->partDecay($amount_date) + $amount;
|
||||
}
|
||||
$balance_cursor->record_date = $amount_date;
|
||||
$state_user_transaction_index = $transaction_ids[$transaction->id];
|
||||
$state_user_transactions_array[$state_user_transaction_index]->balance = $balance_cursor->amount;
|
||||
$state_user_transactions_array[$state_user_transaction_index]->balance_date = $balance_cursor->record_date;
|
||||
$i++;
|
||||
}
|
||||
$results = $stateUserTransactionsTable->saveMany($state_user_transactions_array);
|
||||
$errors = [];
|
||||
foreach($results as $i => $result) {
|
||||
if(!$result) {
|
||||
$errors[$i] = $state_user_transactions_array[$i]->getErrors();
|
||||
}
|
||||
}
|
||||
if(count($errors)) {
|
||||
return ['success' => false, 'error' => 'error saving one ore more state user transactions', 'details' => $errors];
|
||||
}
|
||||
}
|
||||
$state_balance = null;
|
||||
if($update_state_balance) {
|
||||
$state_balance = $state_balances->first();
|
||||
}
|
||||
else if($create_state_balance) {
|
||||
$state_balance = $this->StateBalances->newEntity();
|
||||
$state_balance->state_user_id = $stateUserId;
|
||||
}
|
||||
if($state_balance) {
|
||||
$state_balance->amount = $state_user_transactions->last()->balance;
|
||||
$state_balance->record_date = $state_user_transactions->last()->balance_date;
|
||||
if(!$this->StateBalances->save($state_balance)) {
|
||||
return ['success' => false, 'error' => 'error saving state balance', 'details' => $state_balance->getErrors()];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public function overview()
|
||||
@ -86,6 +198,10 @@ class StateBalancesController extends AppController
|
||||
return $result;
|
||||
}
|
||||
$user = $session->read('StateUser');
|
||||
$update_balance_result = $this->updateBalance($user['id']);
|
||||
if($update_balance_result !== true) {
|
||||
$this->addAdminError('StateBalances', 'overview', $update_balance_result, $user['id']);
|
||||
}
|
||||
// sendRequestGDT
|
||||
// listPerEmailApi
|
||||
|
||||
@ -105,6 +221,7 @@ class StateBalancesController extends AppController
|
||||
//}
|
||||
//
|
||||
//
|
||||
$stateUserTransactionsTable = TableRegistry::getTableLocator()->get('StateUserTransactions');
|
||||
|
||||
$creationsTable = TableRegistry::getTableLocator()->get('TransactionCreations');
|
||||
$creationTransactions = $creationsTable
|
||||
@ -211,55 +328,82 @@ class StateBalancesController extends AppController
|
||||
$current_state_balance = null;
|
||||
$cursor = 0;
|
||||
$transactions_reversed = array_reverse($transactions);
|
||||
$maxI = count($transactions_reversed);
|
||||
foreach($transactions_reversed as $i => $transaction) {
|
||||
$date = $transaction['date'];
|
||||
$month = $date->month;
|
||||
$year = $date->year;
|
||||
if(!$month_start_state_balance) {
|
||||
$month_start_state_balance = $this->StateBalances->chooseForMonthAndUser($month, $year, $user['id']);
|
||||
if(is_array($month_start_state_balance)) {
|
||||
$this->Flash->error(__('Error in state balance: ' . json_encode($month_start_state_balance)));
|
||||
break;
|
||||
}
|
||||
$current_state_balance = $month_start_state_balance;
|
||||
|
||||
if(!isset($transaction['transaction_id'])) {
|
||||
continue;
|
||||
}
|
||||
$prev_amount = $current_state_balance->amount;
|
||||
$decay_duration = $current_state_balance->decayDuration($date);
|
||||
$current_state_balance->amount = $current_state_balance->partDecay($date);
|
||||
$transaction_id = $transaction['transaction_id'];
|
||||
$decay_transaction = NULL;
|
||||
$state_balance = $this->StateBalances->newEntity();
|
||||
|
||||
echo "amount: ". ($current_state_balance->amount / 10000) . ", duration: " . $decay_duration . "<br>";
|
||||
$decay_transaction = [
|
||||
'type' => 'decay',
|
||||
'balance' => -($prev_amount - $current_state_balance->amount),
|
||||
'decay_duration' => $decay_duration . ' ' . __('seconds'),
|
||||
'memo' => ''
|
||||
];
|
||||
if($decay_duration > 0) {
|
||||
if($i > 0 && isset($transactions_reversed[$i-1]['transaction_id'])) {
|
||||
$prev_transaction = $transactions_reversed[$i-1];
|
||||
$stateUserTransactions = $stateUserTransactionsTable
|
||||
->find()
|
||||
->where([
|
||||
'transaction_id IN' => [$transaction_id, $prev_transaction['transaction_id']],
|
||||
'state_user_id' => $user['id']
|
||||
])
|
||||
->order(['transaction_id ASC'])
|
||||
->toArray();
|
||||
|
||||
$prev = $stateUserTransactions[0];
|
||||
if($prev->balance > 0) {
|
||||
// var_dump($stateUserTransactions);
|
||||
$current = $stateUserTransactions[1];
|
||||
$interval = $current->balance_date->diff($prev->balance_date);
|
||||
$state_balance->amount = $prev->balance;
|
||||
$state_balance->record_date = $prev->balance_date;
|
||||
$diff_amount = $state_balance->partDecay($current->balance_date);
|
||||
/* echo "prev date: $prev->balance_date, current date: $current->balance_date, interval: ";
|
||||
var_dump($interval);
|
||||
echo "<br>";
|
||||
echo "prev balance: $prev->balance<br>diff: $diff_amount<br>";
|
||||
echo "current balance: $current->balance<br>";
|
||||
*
|
||||
*/
|
||||
//echo $interval->format('%R%a days');
|
||||
$decay_transaction = [
|
||||
'type' => 'decay',
|
||||
'balance' => -($prev->balance - $diff_amount),
|
||||
'decay_duration' => $interval->format('%a days, %H hours, %I minutes, %S seconds'),
|
||||
'memo' => ''
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if($decay_transaction) {
|
||||
array_splice($transactions_reversed, $i + $cursor, 0, [$decay_transaction]);
|
||||
$cursor++;
|
||||
}
|
||||
if($i == $maxI-1) {
|
||||
$stateUserTransaction = $stateUserTransactionsTable
|
||||
->find()
|
||||
->where(['transaction_id' => $transaction_id, 'state_user_id' => $user['id']])
|
||||
->order(['transaction_id ASC'])->first();
|
||||
//var_dump($stateUserTransaction);
|
||||
$state_balance->amount = $stateUserTransaction->balance;
|
||||
$state_balance->record_date = $stateUserTransaction->balance_date;
|
||||
$transactions_reversed[] = [
|
||||
'type' => 'decay',
|
||||
'balance' => -($stateUserTransaction->balance - $state_balance->decay),
|
||||
'decay_duration' => $stateUserTransaction->balance_date->timeAgoInWords(),
|
||||
'memo' => ''
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
if($current_state_balance->record_date != $date) {
|
||||
if($transaction['type'] == 'send') {
|
||||
$current_state_balance->amount -= $transaction['balance'];
|
||||
} else {
|
||||
$current_state_balance->amount += $transaction['balance'];
|
||||
}
|
||||
}
|
||||
// for debugging
|
||||
$calculated_balance = 0;
|
||||
foreach($transactions_reversed as $tr) {
|
||||
if($tr['type'] == 'send') {
|
||||
$calculated_balance -= intval($tr['balance']);
|
||||
} else {
|
||||
$calculated_balance += intval($tr['balance']);
|
||||
}
|
||||
$current_state_balance->record_date = $date;
|
||||
|
||||
}
|
||||
if($current_state_balance) {
|
||||
echo "amount: ". ($current_state_balance->amount / 10000) . ", duration: " . $current_state_balance->decayDuration(Time::now()) . "<br>";
|
||||
|
||||
array_push($transactions_reversed, [
|
||||
'type' => 'decay',
|
||||
'balance' => -($current_state_balance->amount - $current_state_balance->decay),
|
||||
'decay_duration' => $current_state_balance->record_date->timeAgoInWords(),// $current_state_balance->decayDuration(Time::now()),
|
||||
'memo' => ''
|
||||
]);
|
||||
}
|
||||
$this->set('calculated_balance', $calculated_balance);
|
||||
|
||||
$this->set('transactions', array_reverse($transactions_reversed));
|
||||
$this->set('transactionExecutingCount', $session->read('Transaction.executing'));
|
||||
|
||||
@ -36,6 +36,15 @@ class StateBalance extends Entity
|
||||
|
||||
protected $_virtual = ['decay'];
|
||||
|
||||
private function convertToTimestamp($dateOrTime)
|
||||
{
|
||||
if(method_exists($dateOrTime, 'getTimestamp')) {
|
||||
return $dateOrTime->getTimestamp();
|
||||
} else {
|
||||
return $dateOrTime->i18nFormat(Time::UNIX_TIMESTAMP_FORMAT);
|
||||
}
|
||||
}
|
||||
|
||||
protected function _getDecay()
|
||||
{
|
||||
// decay factor in seconds per year
|
||||
@ -45,7 +54,8 @@ class StateBalance extends Entity
|
||||
// SELECT TIMESTAMPDIFF(SECOND, modified, CURDATE()) AS age_in_seconds from state_balances
|
||||
// decay_for_duration = decay_factor^seconds
|
||||
// decay = gradido_cent * decay_for_duration
|
||||
$decay_duration = intval(Time::now()->getTimestamp() - $this->record_date->getTimestamp());
|
||||
|
||||
$decay_duration = intval(Time::now()->getTimestamp() - $this->convertToTimestamp($this->record_date));
|
||||
if($decay_duration === 0) {
|
||||
return $this->amount;
|
||||
}
|
||||
@ -54,7 +64,7 @@ class StateBalance extends Entity
|
||||
}
|
||||
public function partDecay($target_date)
|
||||
{
|
||||
$decay_duration = intval($target_date->getTimestamp() - $this->record_date->getTimestamp());
|
||||
$decay_duration = intval($this->convertToTimestamp($target_date) - $this->convertToTimestamp($this->record_date));
|
||||
if($decay_duration <= 0) {
|
||||
return $this->amount;
|
||||
}
|
||||
@ -63,7 +73,7 @@ class StateBalance extends Entity
|
||||
|
||||
public function decayDuration($target_date)
|
||||
{
|
||||
return intval($target_date->getTimestamp() - $this->record_date->getTimestamp());
|
||||
return intval($this->convertToTimestamp($target_date) - $this->convertToTimestamp($this->record_date));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -58,10 +58,10 @@ class Signature
|
||||
class GradidoModifieUserBalance
|
||||
{
|
||||
private $state_users = [];
|
||||
private $user_balances = [];
|
||||
|
||||
public function getUserId($userPublicKey)
|
||||
{
|
||||
$userPublicBin = hex2bin($userPublicKey);
|
||||
$stateUsersTable = TableRegistry::getTableLocator()->get('StateUsers');
|
||||
|
||||
$stateUser = $stateUsersTable->find('all')->where(['public_key' => hex2bin($userPublicKey)]);
|
||||
@ -77,9 +77,23 @@ class GradidoModifieUserBalance
|
||||
|
||||
public function updateBalance($newBalance, $recordDate, $userId)
|
||||
{
|
||||
|
||||
$stateBalancesTable = TableRegistry::getTableLocator()->get('StateBalances');
|
||||
return $stateBalancesTable->updateBalanceWithTransaction($newBalance, $recordDate, $userId);
|
||||
$state_balance_query = $stateBalancesTable->find()->where(['state_user_id' => $userId])->order(['record_date ASC']);
|
||||
$state_balance = null;
|
||||
if($state_balance_query->count() > 0) {
|
||||
$state_balance = $state_balance_query->last();
|
||||
} else {
|
||||
$state_balance = $stateBalancesTable->newEntity();
|
||||
$state_balance->state_user_id = $userId;
|
||||
}
|
||||
$state_balance->amount = $newBalance;
|
||||
$state_balance->record_date = $recordDate;
|
||||
$this->user_balances[$userId] = $state_balance;
|
||||
$stateBalancesTable->save($state_balance);
|
||||
return true;
|
||||
//$this->user_balances[$userId] = ['balance' => $newBalance, '']
|
||||
//
|
||||
//return $stateBalancesTable->updateBalanceWithTransaction($newBalance, $recordDate, $userId);
|
||||
|
||||
/*$first_of_month = new Time("$year-$month-01 00:00");
|
||||
$stateBalanceQuery = $stateBalancesTable
|
||||
@ -111,6 +125,10 @@ class GradidoModifieUserBalance
|
||||
{
|
||||
return $this->state_users;
|
||||
}
|
||||
public function getAllStateUserBalances()
|
||||
{
|
||||
return $this->user_balances;
|
||||
}
|
||||
}
|
||||
|
||||
class ManageNodeGroupAdd extends GradidoModifieUserBalance
|
||||
@ -457,11 +475,14 @@ class Record
|
||||
}
|
||||
$state_users = $this->transactionObj->getAllStateUsers();
|
||||
$sut_entities = [];
|
||||
$state_user_balances = $this->transactionObj->getAllStateUserBalances();
|
||||
foreach($state_users as $state_user_id) {
|
||||
$entity = $stateUserTransactionsTable->newEntity();
|
||||
$entity->state_user_id = $state_user_id;
|
||||
$entity->transaction_id = $newTransaction->id;
|
||||
$entity->transaction_type_id = $newTransaction->transaction_type_id;
|
||||
$entity->balance = $state_user_balances[$state_user_id]->amount;
|
||||
$entity->balance_date = $state_user_balances[$state_user_id]->record_date;
|
||||
$sut_entities[] = $entity;
|
||||
}
|
||||
$sut_results = $stateUserTransactionsTable->saveMany($sut_entities);
|
||||
|
||||
@ -9,6 +9,7 @@ $this->assign('title', __('Kontoübersicht'));
|
||||
|
||||
$header = '<h1>' . __('Aktueller Kontostand: ') . '</h1>' .
|
||||
'<h1>' . $this->element('printGradido', ['number' => $balance]) . '</h1>';
|
||||
|
||||
if($gdtSum > 0) {
|
||||
$header .= '<h1>'.$this->Html->link(
|
||||
$this->element('printGDT', ['number' => $gdtSum]),
|
||||
@ -27,6 +28,7 @@ $this->assign('header', $header);
|
||||
<?php endif; ?>
|
||||
<div class="content-list">
|
||||
<p class="content-list-title">Überweisungen</p>
|
||||
<p style="margin-left:25px;color:grey;font-size:smaller;">Berechnet (debugging): <?= $this->element('printGradido', ['number' => $calculated_balance]) ?></p>
|
||||
<div class="content-list-table">
|
||||
<div class="row">
|
||||
<div class="cell header-cell c4"><?= __('Absender') . ' / ' . ('Empfänger') ?></div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user