implement decay from start decay block

;
This commit is contained in:
Dario Rekowski on RockPI 2021-05-10 14:12:03 +00:00
parent 0f29989c64
commit 5ed7b3e416
4 changed files with 84 additions and 26 deletions

View File

@ -1,14 +1,12 @@
<?php
namespace App\Model\Table;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Table;
use Cake\Validation\Validator;
use Cake\ORM\TableRegistry;
use Cake\I18n\Date;
use Cake\I18n\Time;
use Cake\I18n\FrozenTime;
/**
* StateBalances Model
@ -28,6 +26,7 @@ use Cake\I18n\Time;
*/
class StateBalancesTable extends Table
{
private static $startDecayDate = null;
/**
* Initialize method
*
@ -49,6 +48,15 @@ class StateBalancesTable extends Table
'joinType' => '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 . "<br>";

View File

@ -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;
}
}

View File

@ -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)) {

View File

@ -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;
}