diff --git a/skeema/gradido_community/state_user_transactions.sql b/skeema/gradido_community/state_user_transactions.sql
index 272552845..5e01cac4a 100644
--- a/skeema/gradido_community/state_user_transactions.sql
+++ b/skeema/gradido_community/state_user_transactions.sql
@@ -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;
diff --git a/src/Controller/JsonRequestHandlerController.php b/src/Controller/JsonRequestHandlerController.php
index 7162d4d86..ba68f2b5a 100644
--- a/src/Controller/JsonRequestHandlerController.php
+++ b/src/Controller/JsonRequestHandlerController.php
@@ -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');
diff --git a/src/Controller/StateBalancesController.php b/src/Controller/StateBalancesController.php
index 435a9329f..3daa37fa9 100644
--- a/src/Controller/StateBalancesController.php
+++ b/src/Controller/StateBalancesController.php
@@ -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 . "
";
- $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 "
";
+ echo "prev balance: $prev->balance
diff: $diff_amount
";
+ echo "current balance: $current->balance
";
+ *
+ */
+ //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()) . "
";
-
- 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'));
diff --git a/src/Model/Entity/StateBalance.php b/src/Model/Entity/StateBalance.php
index 35af8477b..0381864b6 100644
--- a/src/Model/Entity/StateBalance.php
+++ b/src/Model/Entity/StateBalance.php
@@ -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));
}
}
diff --git a/src/Model/Transactions/Record.php b/src/Model/Transactions/Record.php
index a0da48836..862399af5 100644
--- a/src/Model/Transactions/Record.php
+++ b/src/Model/Transactions/Record.php
@@ -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);
diff --git a/src/Template/StateBalances/overview.ctp b/src/Template/StateBalances/overview.ctp
index 94564e3e5..1f2f4c811 100644
--- a/src/Template/StateBalances/overview.ctp
+++ b/src/Template/StateBalances/overview.ctp
@@ -9,6 +9,7 @@ $this->assign('title', __('Kontoübersicht'));
$header = '
Überweisungen
+Berechnet (debugging): = $this->element('printGradido', ['number' => $calculated_balance]) ?>