From 5ed7b3e416bb5ddaa6914f24f9bf6a2b15651636 Mon Sep 17 00:00:00 2001 From: Dario Rekowski on RockPI Date: Mon, 10 May 2021 14:12:03 +0000 Subject: [PATCH] implement decay from start decay block ; --- .../src/Model/Table/StateBalancesTable.php | 63 ++++++++++++++----- .../src/Model/Table/TransactionsTable.php | 17 ++++- .../Model/Transactions/TransactionBase.php | 19 +++--- .../Transactions/TransactionCreation.php | 11 +++- 4 files changed, 84 insertions(+), 26 deletions(-) diff --git a/community_server/src/Model/Table/StateBalancesTable.php b/community_server/src/Model/Table/StateBalancesTable.php index 7564c30f2..4e91c2948 100644 --- a/community_server/src/Model/Table/StateBalancesTable.php +++ b/community_server/src/Model/Table/StateBalancesTable.php @@ -1,14 +1,12 @@ 'INNER' ]); } + + public static function getDecayStartDateCached() + { + if(self::$startDecayDate == null) { + $transactionsTable = TableRegistry::getTableLocator()->get('Transactions'); + self::$startDecayDate = $transactionsTable->getDecayStartDate(); + } + return self::$startDecayDate; + } /** * Default validation rules. @@ -83,20 +91,33 @@ class StateBalancesTable extends Table return $rules; } - - public function sortTransactions($a, $b) + public static function calculateDecay($startBalance, FrozenTime $startDate, FrozenTime $endDate) { - if ($a['date'] == $b['date']) { - return 0; + $decayStartDate = self::getDecayStartDateCached(); + // if no start decay block exist, we just return input + // if start date for decay is after enddate, we also just return input + if($decayStartDate === null || $decayStartDate >= $endDate) { + return $startBalance; } - return ($a['date'] > $b['date']) ? -1 : 1; + $state_balance = $this->newEntity(); + $state_balance->amount = $startBalance; + // if decay start date is before start date we calculate decay for full duration + if($decayStartDate < $startDate) { + $state_balance->record_date = $startDate; + } + // if decay start in between start date and end date we caculcate decay from decay start time to end date + else { + $state_balance->record_date = $decayStartDate; + } + return $state_balance->partDecay($endDate); + } - public function updateBalances($stateUserId) { $stateUserTransactionsTable = TableRegistry::getTableLocator()->get('StateUserTransactions'); $transactionsTable = TableRegistry::getTableLocator()->get('Transactions'); + $now = new FrozenTime; // info: cakephp use lazy loading, query will be executed later only if needed $state_balances = $this->find('all')->where(['state_user_id' => $stateUserId]); $state_user_transactions = $stateUserTransactionsTable @@ -128,18 +149,26 @@ class StateBalancesTable extends Table if($state_user_transactions->count() == 0){ $clear_state_balance = true; } else { + + $first_state_balance = $state_balances->first(); + $first_state_balance_decayed = self::calculateDecay( + $first_state_balance->amount, + $first_state_balance->record_date, + $now); + $last_state_user_transaction = $state_user_transactions->last(); - $last_transaction = $this->newEntity(); - $last_transaction->amount = $last_state_user_transaction->balance; - $last_transaction->record_date = $last_state_user_transaction->balance_date; + $last_state_user_transaction_decayed = self::calculateDecay( + $last_state_user_transaction->balance, + $last_state_user_transaction->balance_date, + $now); // if entrys are nearly the same, we don't need doing anything - if(abs($last_transaction->decay - $state_balances->first()->decay) > 100) { + if(abs($last_state_user_transaction_decayed - $first_state_balance_decayed) > 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 && $last_state_user_transaction->balance <= 0) { @@ -223,7 +252,11 @@ class StateBalancesTable extends Table if($i == 0) { $balance_cursor->amount = $amount; } else { - $balance_cursor->amount = $balance_cursor->partDecay($amount_date) + $amount; + + //$balance_cursor->amount = $balance_cursor->partDecay($amount_date) + $amount; + $balance_cursor->amount = + $this->calculateDecay($balance_cursor->amount, $balance_cursor->recordDate, $amount_date) + + $amount; } //echo "new balance: " . $balance_cursor->amount . "
"; diff --git a/community_server/src/Model/Table/TransactionsTable.php b/community_server/src/Model/Table/TransactionsTable.php index fdd437076..71d301722 100644 --- a/community_server/src/Model/Table/TransactionsTable.php +++ b/community_server/src/Model/Table/TransactionsTable.php @@ -211,7 +211,8 @@ class TransactionsTable extends Table 'name' => 'Gradido Akademie', 'type' => 'creation', 'transaction_id' => $transaction->id, - 'date' => $creation->target_date, + 'date' => $transaction->received,// $creation->target_date, + 'target_date' => $creation->target_date, 'balance' => $creation->amount, 'memo' => $transaction->memo ]; @@ -320,4 +321,18 @@ class TransactionsTable extends Table } return ['state' => 'error', 'msg' => 'error by saving transaction', 'details' => $transaction->getErrors()]; } + + /*! + * @return: false if no decay start block found + * @return: DateTime Object with start date if one start block found + * @return: ['state':'error'] if more than one found + */ + public function getDecayStartDate() + { + $transaction = $this->find()->where(['transaction_type_id' => 9])->select(['received'])->order(['received' => 'ASC']); + if($transaction->count() == 0) { + return null; + } + return $transaction->first()->received; + } } diff --git a/community_server/src/Model/Transactions/TransactionBase.php b/community_server/src/Model/Transactions/TransactionBase.php index 7d1a1c18b..1f80cc687 100644 --- a/community_server/src/Model/Transactions/TransactionBase.php +++ b/community_server/src/Model/Transactions/TransactionBase.php @@ -72,8 +72,11 @@ class TransactionBase { //debug($stateBalanceQuery); if($stateBalanceQuery->count() > 0) { + $stateBalanceEntry = $stateBalanceQuery->first(); - $stateBalanceEntry->amount = $stateBalanceEntry->partDecay($recordDate) + $addAmountCent; + $stateBalanceEntry->amount = + $stateBalancesTable->calculateDecay($stateBalanceEntry->amount, $stateBalanceEntry->record_date, $recordDate) + + $addAmountCent; } else { $stateBalanceEntry = $stateBalancesTable->newEntity(); $stateBalanceEntry->state_user_id = $stateUserId; @@ -92,11 +95,12 @@ class TransactionBase { protected function addStateUserTransaction($stateUserId, $transactionId, $transactionTypeId, $balance, $balance_date) { $stateUserTransactionTable = self::getTable('state_user_transactions'); + $stateUserTransactions = $stateUserTransactionTable ->find('all') ->where(['state_user_id' => $stateUserId]) ->order(['transaction_id DESC']); - + $new_balance = $balance; if($stateUserTransactions->count() > 0) { $stateBalanceTable = self::getTable('state_balances'); $state_user_transaction = $stateUserTransactions->first(); @@ -104,16 +108,17 @@ class TransactionBase { $this->addError('TransactionBase::addStateUserTransaction', 'state_user_transaction is zero, no first entry exist?'); return false; } - $balance_entity = $stateBalanceTable->newEntity(); - $balance_entity->amount = $state_user_transaction->balance; - $balance_entity->record_date = $state_user_transaction->balance_date; - $balance = $balance_entity->decay + $balance; + $new_balance += $stateBalanceTable->calculateDecay( + $state_user_transaction->balance, + $state_user_transaction->balance_date, + $balance_date + ); } $entity = $stateUserTransactionTable->newEntity(); $entity->state_user_id = $stateUserId; $entity->transaction_id = $transactionId; $entity->transaction_type_id = $transactionTypeId; - $entity->balance = $balance; + $entity->balance = $new_balance; $entity->balance_date = $balance_date; if(!$stateUserTransactionTable->save($entity)) { diff --git a/community_server/src/Model/Transactions/TransactionCreation.php b/community_server/src/Model/Transactions/TransactionCreation.php index 6aeddd955..63b886a3f 100644 --- a/community_server/src/Model/Transactions/TransactionCreation.php +++ b/community_server/src/Model/Transactions/TransactionCreation.php @@ -138,8 +138,9 @@ class TransactionCreation extends TransactionBase { return true; } - public function save($transaction_id, $firstPublic) + public function save($transaction_id, $firstPublic, $received) { + $stateBalancesTable = self::getTable('stateBalances'); $transactionCreationEntity = $this->transactionCreationsTable->newEntity(); $transactionCreationEntity->transaction_id = $transaction_id; @@ -151,23 +152,27 @@ class TransactionCreation extends TransactionBase { $this->addError('TransactionCreation::save', 'couldn\'t get state user id'); return false; } + $transactionCreationEntity->state_user_id = $receiverUserId; $transactionCreationEntity->amount = $this->getAmount(); $transactionCreationEntity->target_date = $this->protoTransactionCreation->getTargetDate()->getSeconds(); $target_date = new FrozenTime($transactionCreationEntity->target_date); + + $decayed_balance = $stateBalancesTable->calculateDecay($this->getAmount(), $target_date, $received); + if(!$this->transactionCreationsTable->save($transactionCreationEntity)) { $this->addError('TransactionCreation::save', 'error saving transactionCreation with errors: ' . json_encode($transactionCreationEntity->getErrors())); return false; } // update state balance - $final_balance = $this->updateStateBalance($receiverUserId, $this->getAmount(), $target_date); + $final_balance = $this->updateStateBalance($receiverUserId, $decayed_balance, $received); if(false === $final_balance) { return false; } // decay is a virtual field which is calculated from amount and now() - record_date - if(!$this->addStateUserTransaction($receiverUserId, $transaction_id, 1, $this->getAmount(), $target_date)) { + if(!$this->addStateUserTransaction($receiverUserId, $transaction_id, 1, $decayed_balance, $received)) { return false; }