mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
implement decay from start decay block
;
This commit is contained in:
parent
0f29989c64
commit
5ed7b3e416
@ -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>";
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user