setTable('state_balances'); $this->setDisplayField('id'); $this->setPrimaryKey('id'); $this->addBehavior('Timestamp'); $this->belongsTo('StateUsers', [ 'foreignKey' => 'state_user_id', 'joinType' => 'INNER' ]); } /** * Default validation rules. * * @param \Cake\Validation\Validator $validator Validator instance. * @return \Cake\Validation\Validator */ public function validationDefault(Validator $validator) { $validator ->integer('id') ->allowEmptyString('id', null, 'create'); $validator ->requirePresence('amount', 'create') ->notEmptyString('amount'); return $validator; } /** * Returns a rules checker object that will be used for validating * application integrity. * * @param \Cake\ORM\RulesChecker $rules The rules object to be modified. * @return \Cake\ORM\RulesChecker */ public function buildRules(RulesChecker $rules) { $rules->add($rules->existsIn(['state_user_id'], 'StateUsers')); return $rules; } public function sortTransactions($a, $b) { if ($a['date'] == $b['date']) { return 0; } return ($a['date'] > $b['date']) ? -1 : 1; } public function updateBalances($stateUserId) { $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->find('all')->where(['state_user_id' => $stateUserId]); $state_user_transactions = $stateUserTransactionsTable ->find() ->where(['state_user_id' => $stateUserId]) ->order(['balance_date ASC']) //->contain(false); ; if(!$state_user_transactions || !$state_user_transactions->count()) { 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; $recalculate_state_user_transactions_balance = true; } if($state_balances->count() > 1) { $clear_state_balance = true; $create_state_balance = true; $recalculate_state_user_transactions_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->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 && $last_state_user_transaction->balance <= 0) { $recalculate_state_user_transactions_balance = true; if(!$create_state_balance) { $update_state_balance = true; } } else if(!$last_state_user_transaction) { $creationsTable = TableRegistry::getTableLocator()->get('TransactionCreations'); $creationTransactions = $creationsTable ->find('all') ->where(['state_user_id' => $stateUserId]) ->contain(false); $transferTable = TableRegistry::getTableLocator()->get('TransactionSendCoins'); $transferTransactions = $transferTable ->find('all') ->where(['OR' => ['state_user_id' => $stateUserId, 'receiver_user_id' => $stateUserId]]) ->contain(false); if($creationTransactions->count() > 0 || $transferTransactions->count() > 0) { return ['success' => false, 'error' => 'state_user_transactions is empty but it exist transactions for user']; } } } // second: do what is needed if($clear_state_balance) { $this->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(['Transactions.id IN' => array_keys($transaction_ids)]) ->contain(['TransactionCreations', 'TransactionSendCoins']); $transactions_indiced = []; foreach($transactions as $transaction) { $transactions_indiced[$transaction->id] = $transaction; } $balance_cursor = $this->newEntity(); $i = 0; foreach($state_user_transactions_array as $state_user_transaction) { $transaction = $transactions_indiced[$state_user_transaction->transaction_id]; if($transaction->transaction_type_id > 2) { continue; } //echo "transaction id: ".$transaction->id . "
"; $amount_date = null; $amount = 0; if($transaction->transaction_type_id == 1) { // creation $temp = $transaction->transaction_creation; /*$balance_temp = $this->newEntity(); $balance_temp->amount = $temp->amount; $balance_temp->record_date = $temp->target_date; */ $amount = intval($temp->amount);//$balance_temp->partDecay($transaction->received); $amount_date = $temp->target_date; //$amount_date = } else if($transaction->transaction_type_id == 2) { // transfer $temp = $transaction->transaction_send_coin; $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; } //echo "new balance: " . $balance_cursor->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->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->save($state_balance)) { return ['success' => false, 'error' => 'error saving state balance', 'details' => $state_balance->getErrors()]; } } return true; } }