diff --git a/skeema/gradido_community/state_user_transactions.sql b/skeema/gradido_community/state_user_transactions.sql new file mode 100644 index 000000000..272552845 --- /dev/null +++ b/skeema/gradido_community/state_user_transactions.sql @@ -0,0 +1,9 @@ +CREATE TABLE `state_user_transactions` ( + `id` int UNSIGNED NOT NULL AUTO_INCREMENT, + `state_user_id` int UNSIGNED NOT NULL, + `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, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; diff --git a/src/Controller/StateUserTransactionsController.php b/src/Controller/StateUserTransactionsController.php new file mode 100644 index 000000000..8c252218c --- /dev/null +++ b/src/Controller/StateUserTransactionsController.php @@ -0,0 +1,290 @@ +Auth->allow(['add', 'edit']); + $this->Auth->allow(['ajaxListTransactions']); + //$this->loadComponent('JsonRequestClient'); + } + /** + * Index method + * + * @return \Cake\Http\Response|null + */ + public function index() + { + $this->paginate = [ + 'contain' => ['StateUsers', 'Transactions', 'TransactionTypes'], + ]; + $stateUserTransactions = $this->paginate($this->StateUserTransactions); + + $this->set(compact('stateUserTransactions')); + } + + public function sortTransactions($a, $b) + { + if ($a['date'] == $b['date']) { + return 0; + } + return ($a['date'] > $b['date']) ? -1 : 1; + } + + + public function ajaxListTransactions($page = 1, $count = 20) + { + $startTime = microtime(true); + $session = $this->getRequest()->getSession(); + $user = $session->read('StateUser'); + if(!$user) { + return $this->returnJson(['state' => 'error', 'msg' => 'user not found', 'details' => 'exist a valid session cookie?']); + } + + $paged_state_user_transactions = $this->StateUserTransactions + ->find('all') + ->where(['state_user_id' => $user['id'], 'transaction_type_id IN' => [1,2]]) + ->limit($count) + ->page($page) + ->order(['transaction_id']) + ; + $all_user_transactions_count = $this->StateUserTransactions + ->find('all') + ->where(['state_user_id' => $user['id'], 'transaction_type_id IN' => [1,2]]) + ->count() + ; + $creationTransaction_ids = []; + $transferTransaction_ids = []; + $allTransaction_ids = []; + foreach($paged_state_user_transactions as $state_user_transaction) { + $allTransaction_ids[] = $state_user_transaction->transaction_id; + switch($state_user_transaction->transaction_type_id) { + case 1: $creationTransaction_ids[] = $state_user_transaction->transaction_id; break; + case 2: $transferTransaction_ids[] = $state_user_transaction->transaction_id; break; + } + } + $transactionsTable = TableRegistry::getTableLocator()->get('Transactions'); + $transactionCreationsTable = TableRegistry::getTableLocator()->get('TransactionCreations'); + $transactionSendCoinsTable = TableRegistry::getTableLocator()->get('TransactionSendCoins'); + $stateUsersTable = TableRegistry::getTableLocator()->get('StateUsers'); + if(count($allTransaction_ids) > 0) { + $transactionEntries = $transactionsTable->find('all')->where(['id IN' => $allTransaction_ids])->order(['id'])->toArray(); + } + if(count($creationTransaction_ids) > 0) { + $transactionCreations = $transactionCreationsTable->find('all')->where(['transaction_id IN' => $creationTransaction_ids]); + } + if(count($transferTransaction_ids)) { + $transactionTransfers = $transactionSendCoinsTable->find('all')->where(['transaction_id IN' => $transferTransaction_ids]); + } + //var_dump($transactions->all()); + + $transactions = []; + // creations + if(isset($transactionCreations)) { + foreach ($transactionCreations as $creation) { + //var_dump($creation); + $transaction_entries_index = array_search($creation->transaction_id, $allTransaction_ids); + if(FALSE === $transaction_entries_index) { + return $this->returnJson(['state' => 'error', 'msg' => 'code error', 'details' => 'creation, transaction_entries_index is FALSE, shouldn\'t occure']); + } + $transaction = $transactionEntries[$transaction_entries_index]; + array_push($transactions, [ + 'name' => 'Gradido Akademie', + 'type' => 'creation', + 'transaction_id' => $creation->transaction_id, + 'date' => $transaction->received, + 'balance' => $creation->amount, + 'memo' => $transaction->memo + ]); + } + } + + // involved users + if(isset($transactionTransfers)) { + $involvedUserIds = []; + + foreach ($transactionTransfers as $transfer) { + //var_dump($sendCoins); + if ($transfer->state_user_id != $user['id']) { + array_push($involvedUserIds, intval($transfer->state_user_id)); + } elseif ($transfer->receiver_user_id != $user['id']) { + array_push($involvedUserIds, intval($transfer->receiver_user_id)); + } + } + + // exchange key with values and drop duplicates + $involvedUser_temp = array_flip($involvedUserIds); + // exchange back + $involvedUserIds = array_flip($involvedUser_temp); + + $involvedUser = $stateUsersTable->find('all', [ + 'contain' => false, + 'where' => ['id IN' => $involvedUserIds], + 'fields' => ['id', 'first_name', 'last_name', 'email'] + ]); + //var_dump($involvedUser->toArray()); + $involvedUserIndices = []; + foreach ($involvedUser as $involvedUser) { + $involvedUserIndices[$involvedUser->id] = $involvedUser; + } + + // transfers - send coins + foreach($transactionTransfers as $transfer) + { + $transaction_entries_index = array_search($transfer->transaction_id, $allTransaction_ids); + if(FALSE === $transaction_entries_index) { + + return $this->returnJson([ + 'state' => 'error', + 'msg' => 'code error', + 'details' => 'transfer, transaction_entries_index is FALSE, shouldn\'t occure', + 'data' => ['haystack' => $allTransaction_ids, 'needle' => $transfer->transaction_id] + ]); + } + $transaction = $transactionEntries[$transaction_entries_index]; + $type = ''; + $otherUser = null; + $other_user_public = ''; + + if ($transfer->state_user_id == $user['id']) { + $type = 'send'; + + if(isset($involvedUserIndices[$transfer->receiver_user_id])) { + $otherUser = $involvedUserIndices[$transfer->receiver_user_id]; + } + $other_user_public = bin2hex(stream_get_contents($transfer->receiver_public_key)); + } else if ($transfer->receiver_user_id == $user['id']) { + $type = 'receive'; + if(isset($involvedUserIndices[$transfer->state_user_id])) { + $otherUser = $involvedUserIndices[$transfer->state_user_id]; + } + if($transfer->sender_public_key) { + $other_user_public = bin2hex(stream_get_contents($transfer->sender_public_key)); + } + } + if(null == $otherUser) { + $otherUser = $stateUsersTable->newEntity(); + } + array_push($transactions, [ + 'name' => $otherUser->first_name . ' ' . $otherUser->last_name, + 'email' => $otherUser->email, + 'type' => $type, + 'transaction_id' => $transfer->transaction_id, + 'date' => $transaction->received, + 'balance' => $transfer->amount, + 'memo' => $transaction->memo, + 'pubkey' => $other_user_public + ]); + //*/ + + } + } + uasort($transactions, array($this, 'sortTransactions')); + + return $this->returnJson([ + 'state' => 'success', + 'transactions' => $transactions, + 'transactionExecutingCount' => $session->read('Transaction.executing'), + 'count' => $all_user_transactions_count, + 'timeUsed' => microtime(true) - $startTime + ]); + } + + /** + * View method + * + * @param string|null $id State User Transaction id. + * @return \Cake\Http\Response|null + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function view($id = null) + { + $stateUserTransaction = $this->StateUserTransactions->get($id, [ + 'contain' => ['StateUsers', 'Transactions', 'TransactionTypes'], + ]); + + $this->set('stateUserTransaction', $stateUserTransaction); + } + + /** + * Add method + * + * @return \Cake\Http\Response|null Redirects on successful add, renders view otherwise. + */ + public function add() + { + $stateUserTransaction = $this->StateUserTransactions->newEntity(); + if ($this->request->is('post')) { + $stateUserTransaction = $this->StateUserTransactions->patchEntity($stateUserTransaction, $this->request->getData()); + if ($this->StateUserTransactions->save($stateUserTransaction)) { + $this->Flash->success(__('The state user transaction has been saved.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('The state user transaction could not be saved. Please, try again.')); + } + $stateUsers = $this->StateUserTransactions->StateUsers->find('list', ['limit' => 200]); + $transactions = $this->StateUserTransactions->Transactions->find('list', ['limit' => 200]); + $transactionTypes = $this->StateUserTransactions->TransactionTypes->find('list', ['limit' => 200]); + $this->set(compact('stateUserTransaction', 'stateUsers', 'transactions', 'transactionTypes')); + } + + /** + * Edit method + * + * @param string|null $id State User Transaction id. + * @return \Cake\Http\Response|null Redirects on successful edit, renders view otherwise. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function edit($id = null) + { + $stateUserTransaction = $this->StateUserTransactions->get($id, [ + 'contain' => [], + ]); + if ($this->request->is(['patch', 'post', 'put'])) { + $stateUserTransaction = $this->StateUserTransactions->patchEntity($stateUserTransaction, $this->request->getData()); + if ($this->StateUserTransactions->save($stateUserTransaction)) { + $this->Flash->success(__('The state user transaction has been saved.')); + + return $this->redirect(['action' => 'index']); + } + $this->Flash->error(__('The state user transaction could not be saved. Please, try again.')); + } + $stateUsers = $this->StateUserTransactions->StateUsers->find('list', ['limit' => 200]); + $transactions = $this->StateUserTransactions->Transactions->find('list', ['limit' => 200]); + $transactionTypes = $this->StateUserTransactions->TransactionTypes->find('list', ['limit' => 200]); + $this->set(compact('stateUserTransaction', 'stateUsers', 'transactions', 'transactionTypes')); + } + + /** + * Delete method + * + * @param string|null $id State User Transaction id. + * @return \Cake\Http\Response|null Redirects to index. + * @throws \Cake\Datasource\Exception\RecordNotFoundException When record not found. + */ + public function delete($id = null) + { + $this->request->allowMethod(['post', 'delete']); + $stateUserTransaction = $this->StateUserTransactions->get($id); + if ($this->StateUserTransactions->delete($stateUserTransaction)) { + $this->Flash->success(__('The state user transaction has been deleted.')); + } else { + $this->Flash->error(__('The state user transaction could not be deleted. Please, try again.')); + } + + return $this->redirect(['action' => 'index']); + } +} diff --git a/src/Model/Entity/StateUserTransaction.php b/src/Model/Entity/StateUserTransaction.php new file mode 100644 index 000000000..9fed345a5 --- /dev/null +++ b/src/Model/Entity/StateUserTransaction.php @@ -0,0 +1,37 @@ + true, + 'transaction_id' => true, + 'transaction_type_id' => true, + 'state_user' => true, + 'transaction' => true, + 'transaction_type' => true, + ]; +} diff --git a/src/Model/Table/StateUserTransactionsTable.php b/src/Model/Table/StateUserTransactionsTable.php new file mode 100644 index 000000000..6cfe94a23 --- /dev/null +++ b/src/Model/Table/StateUserTransactionsTable.php @@ -0,0 +1,85 @@ +setTable('state_user_transactions'); + $this->setDisplayField('id'); + $this->setPrimaryKey('id'); + + $this->belongsTo('StateUsers', [ + 'foreignKey' => 'state_user_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('Transactions', [ + 'foreignKey' => 'transaction_id', + 'joinType' => 'INNER', + ]); + $this->belongsTo('TransactionTypes', [ + 'foreignKey' => 'transaction_type_id', + 'joinType' => 'INNER', + ]); + } + + /** + * Default validation rules. + * + * @param \Cake\Validation\Validator $validator Validator instance. + * @return \Cake\Validation\Validator + */ + public function validationDefault(Validator $validator) + { + $validator + ->nonNegativeInteger('id') + ->allowEmptyString('id', null, 'create'); + + 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')); + $rules->add($rules->existsIn(['transaction_id'], 'Transactions')); + $rules->add($rules->existsIn(['transaction_type_id'], 'TransactionTypes')); + + return $rules; + } +} diff --git a/src/Template/StateUserTransactions/add.ctp b/src/Template/StateUserTransactions/add.ctp new file mode 100644 index 000000000..b131a43e5 --- /dev/null +++ b/src/Template/StateUserTransactions/add.ctp @@ -0,0 +1,31 @@ + + +
| = $this->Paginator->sort('id') ?> | += $this->Paginator->sort('state_user_id') ?> | += $this->Paginator->sort('transaction_id') ?> | += $this->Paginator->sort('transaction_type_id') ?> | += __('Actions') ?> | +
|---|---|---|---|---|
| = $this->Number->format($stateUserTransaction->id) ?> | += $stateUserTransaction->has('state_user') ? $this->Html->link($stateUserTransaction->state_user->email, ['controller' => 'StateUsers', 'action' => 'view', $stateUserTransaction->state_user->id]) : '' ?> | += $stateUserTransaction->has('transaction') ? $this->Html->link($stateUserTransaction->transaction->id, ['controller' => 'Transactions', 'action' => 'view', $stateUserTransaction->transaction->id]) : '' ?> | += $stateUserTransaction->has('transaction_type') ? $this->Html->link($stateUserTransaction->transaction_type->name, ['controller' => 'TransactionTypes', 'action' => 'view', $stateUserTransaction->transaction_type->id]) : '' ?> | ++ = $this->Html->link(__('View'), ['action' => 'view', $stateUserTransaction->id]) ?> + = $this->Html->link(__('Edit'), ['action' => 'edit', $stateUserTransaction->id]) ?> + = $this->Form->postLink(__('Delete'), ['action' => 'delete', $stateUserTransaction->id], ['confirm' => __('Are you sure you want to delete # {0}?', $stateUserTransaction->id)]) ?> + | +
= $this->Paginator->counter(['format' => __('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')]) ?>
+| = __('State User') ?> | += $stateUserTransaction->has('state_user') ? $this->Html->link($stateUserTransaction->state_user->email, ['controller' => 'StateUsers', 'action' => 'view', $stateUserTransaction->state_user->id]) : '' ?> | +
|---|---|
| = __('Transaction') ?> | += $stateUserTransaction->has('transaction') ? $this->Html->link($stateUserTransaction->transaction->id, ['controller' => 'Transactions', 'action' => 'view', $stateUserTransaction->transaction->id]) : '' ?> | +
| = __('Transaction Type') ?> | += $stateUserTransaction->has('transaction_type') ? $this->Html->link($stateUserTransaction->transaction_type->name, ['controller' => 'TransactionTypes', 'action' => 'view', $stateUserTransaction->transaction_type->id]) : '' ?> | +
| = __('Id') ?> | += $this->Number->format($stateUserTransaction->id) ?> | +