diff --git a/composer.json b/composer.json index 784c6d123..6a5700b0d 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "license": "MIT", "require": { "php": ">=5.6", - "cakephp/cakephp": "3.8.*", + "cakephp/cakephp": "3.9.*", "cakephp/migrations": "^2.0.0", "cakephp/plugin-installer": "^1.0", "datto/json-rpc": "^6.0", diff --git a/config/routes.php b/config/routes.php index 3400992ac..f92b66b8b 100644 --- a/config/routes.php +++ b/config/routes.php @@ -110,8 +110,10 @@ Router::scope('/', function (RouteBuilder $routes) { */ //$routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']); $routes->connect('/', ['controller' => 'Dashboard', 'action' => 'index']); - $routes->connect('/client', ['controller' => 'Pages', 'action' => 'display', 'js']); + //$routes->connect('/client', ['controller' => 'Pages', 'action' => 'display', 'js']); $routes->connect('/server', ['controller' => 'Dashboard', 'action' => 'serverIndex']); + $routes->connect('/client', ['controller' => 'Pages', 'action' => 'display', 'vue']); + $routes->connect('/vue-dev', ['controller' => 'Pages', 'action' => 'display', 'vue-dev']); //$routes->connect('/', 'https://gradido2.dario-rekowski.de/account', array('status' => 303)); /** diff --git a/src/Controller/AppController.php b/src/Controller/AppController.php index 729cd88b0..41ce0ff6a 100644 --- a/src/Controller/AppController.php +++ b/src/Controller/AppController.php @@ -207,7 +207,10 @@ class AppController extends Controller $stateUserQuery = $stateUserTable ->find('all') ->where(['public_key' => $public_key_bin]) - ->contain(['StateBalances']); + ->contain('StateBalances', function ($q) { + return $q->order(['record_date' => 'DESC']) + ->limit(1); + }); if ($stateUserQuery->count() == 1) { $stateUser = $stateUserQuery->first(); if ($stateUser->first_name != $json['user']['first_name'] || @@ -228,6 +231,7 @@ class AppController extends Controller } //var_dump($stateUser); if (count($stateUser->state_balances) > 0) { + $session->write('StateUser.balance', $stateUser->state_balances[0]->decay); } $session->write('StateUser.id', $stateUser->id); diff --git a/src/Controller/JsonRequestHandlerController.php b/src/Controller/JsonRequestHandlerController.php index 90150f16e..6fef9451b 100644 --- a/src/Controller/JsonRequestHandlerController.php +++ b/src/Controller/JsonRequestHandlerController.php @@ -62,12 +62,35 @@ class JsonRequestHandlerController extends AppController { case 'getUserBalance': return $this->getUserBalance($jsonData->email, $jsonData->last_name); case 'errorInTransaction': return $this->errorInTransaction($jsonData); case 'updateReadNode': return $this->updateReadNode(); + case 'addUser' : return $this->addUser($jsonData->user); } return $this->returnJson(['state' => 'error', 'msg' => 'unknown method for post', 'details' => $method]); } return $this->returnJson(['state' => 'error', 'msg' => 'no post or get']); } + private function addUser($newUser) + { + $stateUsersTable = TableRegistry::getTableLocator()->get('StateUsers'); + $entity = $stateUsersTable->newEntity(); + $required_fields = ['first_name', 'last_name', 'email', 'public_key', 'disabled']; + foreach($required_fields as $required_field) { + if(!isset($newUser->$required_field)) { + return $this->returnJson(['state' => 'error', 'msg' => 'missing required field in addUser', 'details' => $required_field]); + } + if('public_key' == $required_field) { + $entity->$required_field = hex2bin($newUser->public_hex); + } else { + $entity->$required_field = $newUser->$required_field; + } + } + if($stateUsersTable->save($entity)) { + return $this->returnJson(['state' => 'success']); + } else { + return $this->returnJson(['state' => 'error', 'msg' => 'error saving state_user', 'details' => $entity->getErrors()]); + } + } + // Called from login server like a cron job every 10 minutes or after sending transaction to hedera private function updateReadNode() { diff --git a/src/Controller/PagesController.php b/src/Controller/PagesController.php index 87ecc569f..69f57356b 100644 --- a/src/Controller/PagesController.php +++ b/src/Controller/PagesController.php @@ -62,14 +62,17 @@ class PagesController extends AppController if (!empty($path[1])) { $subpage = $path[1]; } - $session = $this->getRequest()->getSession(); + /*$session = $this->getRequest()->getSession(); $result = $this->requestLogin(); if($result !== true) { return $result; } $user = $session->read('StateUser'); - $login_server_session = $this->request->getCookie('GRADIDO_LOGIN', ''); - $this->set(compact('page', 'subpage', 'user', 'login_server_session')); + $login_server_session = $this->request->getCookie('GRADIDO_LOGIN', '');*/ + if($page == "vue" || $page == "vue-dev") { + $this->viewBuilder()->setLayout(false); + } + $this->set(compact('page', 'subpage')); try { $this->render(implode('/', $path)); diff --git a/src/Controller/StateBalancesController.php b/src/Controller/StateBalancesController.php index c87a3032b..435a9329f 100644 --- a/src/Controller/StateBalancesController.php +++ b/src/Controller/StateBalancesController.php @@ -250,13 +250,16 @@ class StateBalancesController extends AppController $current_state_balance->record_date = $date; } - echo "amount: ". ($current_state_balance->amount / 10000) . ", duration: " . $current_state_balance->decayDuration(Time::now()) . "
"; - array_push($transactions_reversed, [ - 'type' => 'decay', - 'balance' => -($current_state_balance->amount - $current_state_balance->decay), - 'decay_duration' => $current_state_balance->record_date->timeAgoInWords(),// $current_state_balance->decayDuration(Time::now()), - 'memo' => '' - ]); + if($current_state_balance) { + echo "amount: ". ($current_state_balance->amount / 10000) . ", duration: " . $current_state_balance->decayDuration(Time::now()) . "
"; + + array_push($transactions_reversed, [ + 'type' => 'decay', + 'balance' => -($current_state_balance->amount - $current_state_balance->decay), + 'decay_duration' => $current_state_balance->record_date->timeAgoInWords(),// $current_state_balance->decayDuration(Time::now()), + 'memo' => '' + ]); + } $this->set('transactions', array_reverse($transactions_reversed)); $this->set('transactionExecutingCount', $session->read('Transaction.executing')); diff --git a/src/Model/Table/StateBalancesTable.php b/src/Model/Table/StateBalancesTable.php index 64606e941..cae6e0fe8 100644 --- a/src/Model/Table/StateBalancesTable.php +++ b/src/Model/Table/StateBalancesTable.php @@ -82,14 +82,17 @@ class StateBalancesTable extends Table return $rules; } - + /* + * create new state balance at beginning of next month from $previousStateBalance + * calculate decay for the time diff + */ private function calculateStateBalance($previousStateBalance) { $entity = $this->newEntity(); $entity->state_user_id = $previousStateBalance->state_user_id; $newDate = $previousStateBalance->record_date; $newDate->day(1); - if($newDate->month > 12) { + if($newDate->month <= 12) { $newDate->month($newDate->month + 1); } else { $newDate->month(1); @@ -103,16 +106,113 @@ class StateBalancesTable extends Table return ['state' => 'error', 'msg' => 'couldn\'t save', 'details' => $entity->getErrors()]; } - // getting start balance for month, if exist else create and create all missing state_balances before, in while loop - public function chooseForMonthAndUser($month, $year, $state_user_id) + public function sortTransactions($a, $b) + { + if ($a['date'] == $b['date']) { + return 0; + } + return ($a['date'] > $b['date']) ? -1 : 1; + } + /* + * calculate balance at end of month + * work only if state balance at begin of month exist + * use transaction_send_coins and transaction_creations + */ + public function updateLastStateBalanceOfMonth($month, $year, $state_user_id) { - //'created' => 'identifier' - $first_of_month = new Time("$year-$month-01 00:00"); $last_of_month = new Time($first_of_month); $last_of_month->addMonth(1); $last_of_month->subSecond(1); - echo "first of month: " . $first_of_month->i18nFormat() . ", last of month: " . $last_of_month->i18nFormat() . "
"; + $query = $this->find('all') + ->where(['AND' => [ + 'state_user_id' => $state_user_id, + 'record_date >=' => $first_of_month, + 'record_date <=' => $last_of_month + ]]) + ->order(['record_date' => 'ASC']); + if($query->isEmpty()) { + return [ + 'state' => 'error', + 'msg' => 'no state balance in this month found', + 'details' => [ + 'month' => $month, + 'year' => $year, + 'state_user_id' => $state_user_id + ] + ]; + } + // get transactions from this month + $balance_changes = []; + $transactionCreationsTable = TableRegistry::getTableLocator()->get('TransactionCreations'); + $transactionTransfersTable = TableRegistry::getTableLocator()->get('TransactionSendCoins'); + $relevant_creations = $transactionCreationsTable + ->find('all') + ->where(['AND' => [ + 'state_user_id' => $state_user_id, + 'target_date >=' => $first_of_month, + 'target_date <=' => $last_of_month + ]])->contain(false); + foreach($relevant_creations as $creation) { + $balance_changes[] = ['amount' => $creation->amount, 'date' => $creation->target_date]; + } + $relevant_transfers = $transactionTransfersTable + ->find('all') + ->where(['AND' => [ + 'OR' => [ + 'state_user_id' => $state_user_id, + 'receiver_user_id' => $state_user_id + ], + 'transaction.received >= ' => $first_of_month, + 'transaction.received <=' => $last_of_month + ]])->contain(['Transactions']); + debug($relevant_transfers); + foreach($relevant_transfers as $transfer) { + $amount = $transfer->amount; + // if it is a send transaction, negate the value + if($transfer->state_user_id == $state_user_id) { + $amount *= -1.0; + } + $balance_changes[] = ['amount' => $amount, 'date' => $transfer->transaction->received]; + } + uasort($balance_changes, array($this, 'sortTransactions')); + $current_state_balance = null; + if($query->count() == 1) { + $current_state_balance = $this->newEntity(); + $current_state_balance->amount = $query->first()->amount; + $current_state_balance->state_user_id = $state_user_id; + $current_state_balance->record_date = $query->first()->record_date; + } else if($query->count() == 2) { + $array = $query->toArray(); + $current_state_balance = $array[1]; + } else { + throw new Exception('Should\'n occure, never'); + } + + foreach($balance_changes as $change) { + $current_state_balance->amount = $current_state_balance->getDecay($change['date']); + $current_state_balance->amount += $change['amount']; + $current_state_balance->record_date = $change['date']; + } + if(!$this->save($current_state_balance)) { + return ['state' => 'error', 'msg' => 'couldn\'t save', 'details' => $current_state_balance->getErrors()]; + } + return $current_state_balance; + } + + /* + * getting start balance for month + * create and create all missing state_balances before if not exist + * in while loop + */ + + public function chooseForMonthAndUser($month, $year, $state_user_id) + { + $first_of_month = new Time("$year-$month-01 00:00"); + $last_of_month = new Time($first_of_month); + $last_of_month->addMonth(1); + $last_of_month->subSecond(1); + //echo "first of month: " . $first_of_month->i18nFormat() . ", last of month: " . $last_of_month->i18nFormat() . "
"; $query = $this->find('all'); $query->select([ @@ -127,6 +227,7 @@ class StateBalancesTable extends Table ] ]) ->order(['record_date' => 'ASC']) + ->limit(1) ->contain([]); if($query->count() == 0) { @@ -136,24 +237,8 @@ class StateBalancesTable extends Table ->limit(1) ->order(['record_date' => 'DESC']) ; - if($state_balances->count() == 1) - { - $current_state_balance = $state_balances->first(); - while(true) - { - $new_state_balance = $this->calculateStateBalance($current_state_balance); - if(is_array($new_state_balance)) { - return ['state' => 'error', 'msg' => 'error calculate state balance', 'details' => $new_state_balance]; - } - $record_date = $new_state_balance->record_date; - if($record_date->month === $month && $record_date->year === $year) { - return $new_state_balance; - } - $current_state_balance = $new_state_balance; - } - } - // else create one for first user transaction - else + // create one for first user transaction + if($state_balances->isEmpty()) { $state_user_transactions_table = TableRegistry::getTableLocator()->get('StateUserTransactions'); $state_user_transaction = $state_user_transactions_table->find('all') @@ -179,13 +264,89 @@ class StateBalancesTable extends Table } if(!$this->save($entity)) { return ['state' => 'error', 'msg' => 'error by saving state balance', 'details' => $entity->getErrors()]; - } else { - return $entity; } } - - + $state_balances = $this->find('all') + ->where(['state_user_id' => $state_user_id]) + ->limit(1) + ->order(['record_date' => 'DESC']) + ; + if($state_balances->count() == 1) + { + $current_state_balance = $state_balances->first(); + while(true) + { + $new_state_balance_begin = $this->calculateStateBalance($current_state_balance); + if(is_array($new_state_balance_begin)) { + return ['state' => 'error', 'msg' => 'error calculate state balance', 'details' => $new_state_balance_begin]; + } + $record_date = $new_state_balance_begin->record_date; + if($record_date->month === $month && $record_date->year === $year) { + return $new_state_balance_begin; + } + $current_state_balance = $this->updateLastStateBalanceOfMonth($month, $year, $state_user_id); + } + } + else + { + return ['state' => 'error', 'msg' => 'creation of first state_balance failes']; + } } return $query->first(); } + + public function updateBalanceWithTransaction($newBalance, $recordDate, $userId) + { + // max 2 StateBalance Entrys per month: + // 1. first of month or first transaction of user + // 2. last of month or last transaction of user + $first_state_balance_of_month = $this->chooseForMonthAndUser($recordDate->month, $recordDate->year, $userId); + $updated_state_balance = null; + + if($first_state_balance_of_month == null || is_array($first_state_balance_of_month)) { + return $first_state_balance_of_month; + } + + if($first_state_balance_of_month->record_date->day == $recordDate->day && + $recordDate > $first_state_balance_of_month->record_date) { + if($first_state_balance_of_month->amount == $newBalance) { + // nothing to do here + return true; + } + $updated_state_balance = $first_state_balance_of_month; + $updated_state_balance->amount = $newBalance; + // copy complete record date, inclusive time + $first_state_balance_of_month->record_date = $recordDate; + } else { + $query = $this->find('all') + ->where(['AND' => [ + 'record_date >' => $first_state_balance_of_month->record_date, + 'record_date <=' => $recordDate, + 'state_user_id' => $userId + ]]); + if(!$query->isEmpty()) { + $updated_state_balance = $query->first(); + if($updated_state_balance->record_date == $recordDate) { + return true; + } + } else { + $updated_state_balance = $this->newEntity(); + $updated_state_balance->state_user_id = $userId; + } + $updated_state_balance->record_date = $recordDate; + $updated_state_balance->amount = $newBalance; + } + + if($updated_state_balance) { + if(!$this->save($updated_state_balance)) { + return ['state' => 'error', 'msg' => 'error by saving state balance', 'details' => $entity->getErrors()]; + } + + // delete all state_balances which came after + // they will be automaticlly recovered by next call of chooseForMonthAndUser + $this->deleteAll(['state_user_id' => $userId, 'record_date >' => $recordDate]); + } + + return true; + } } diff --git a/src/Model/Transactions/Record.php b/src/Model/Transactions/Record.php index ac378d56c..686994137 100644 --- a/src/Model/Transactions/Record.php +++ b/src/Model/Transactions/Record.php @@ -77,13 +77,22 @@ class GradidoModifieUserBalance public function updateBalance($newBalance, $recordDate, $userId) { + $stateBalancesTable = TableRegistry::getTableLocator()->get('StateBalances'); - $stateBalanceQuery = $stateBalancesTable->find('all')->where(['state_user_id' => $userId]); + return $stateBalancesTable->updateBalanceWithTransaction($newBalance, $recordDate, $userId); + + /*$first_of_month = new Time("$year-$month-01 00:00"); + $stateBalanceQuery = $stateBalancesTable + ->find('all') + ->where(['state_user_id' => $userId]) + ->order(['record_date' => 'DESC']) + ->limit(1); $entity = null; if(!$stateBalanceQuery->isEmpty()) { $entity = $stateBalanceQuery->first(); - if($entity->record_date != NULL && $entity->record_date > $recordDate) { + if($entity->record_date != NULL && + ($entity->record_date > $recordDate || $entity->record_date->day == 1)) { return false; } } else { @@ -95,7 +104,7 @@ class GradidoModifieUserBalance /*if(!$stateBalancesTable->save($entity)) { return ['state' => 'error', 'msg' => 'error saving state balance', 'details' => $entity->getErrors()]; }*/ - return true; + //return true; } public function getAllStateUsers() @@ -209,8 +218,8 @@ class GradidoCreation extends GradidoModifieUserBalance public function __construct($data) { $this->userPubkey = $data['user']; - $this->amount = $data['amount']; - $this->new_balance = $data['new_balance']; + $this->amount = $data['amount']['amount']; + $this->new_balance = $data['new_balance']['amount']; //$this->targetDate = $received; } @@ -276,15 +285,15 @@ class GradidoTransfer extends GradidoModifieUserBalance public function __construct($data) { - $this->amount = $data['amount']; + $this->amount = $data['amount']['amount']; $sender = $data['sender']; $this->sender_pubkey = $sender['user']; - $this->sender_new_balance = $sender['new_balance']; + $this->sender_new_balance = $sender['new_balance']['amount']; $receiver = $data['receiver']; $this->receiver_pubkey = $receiver['user']; - $this->receiver_new_balance = $receiver['new_balance']; + $this->receiver_new_balance = $receiver['new_balance']['amount']; } diff --git a/src/Template/Pages/js.ctp b/src/Template/Pages/js.ctp index bb3167acf..60868adc4 100644 --- a/src/Template/Pages/js.ctp +++ b/src/Template/Pages/js.ctp @@ -1,14 +1,41 @@ -layout = false;?> - - Vue Test - - - -
Wird geladen...
- - - \ No newline at end of file +layout = false;?> + + + + + + + + + BootstrapVue Argon Dashboard by Creative Tim + + + + + + + + + +
+ wird geladen... +
+ + + + diff --git a/src/Template/StateBalances/overview.ctp b/src/Template/StateBalances/overview.ctp index 8ac2f769b..94564e3e5 100644 --- a/src/Template/StateBalances/overview.ctp +++ b/src/Template/StateBalances/overview.ctp @@ -79,7 +79,7 @@ $this->assign('header', $header); minus_circle_multiple - + diff --git a/testJson.sh b/testJson.sh new file mode 100755 index 000000000..b66cf8d18 --- /dev/null +++ b/testJson.sh @@ -0,0 +1,5 @@ +#!/bin/bash +#sudo -u www-data ./vendor/bin/phpunit --filter testIndex tests/TestCase/Controller/TransactionJsonRequestHandlerControllerTest + +sudo -u www-data ./vendor/bin/phpunit --testdox tests/TestCase/Controller/JsonRequestHandlerControllerTest + diff --git a/tests/Fixture/StateUserTransactionsFixture.php b/tests/Fixture/StateUserTransactionsFixture.php new file mode 100644 index 000000000..c1aadb046 --- /dev/null +++ b/tests/Fixture/StateUserTransactionsFixture.php @@ -0,0 +1,48 @@ + ['type' => 'integer', 'length' => 10, 'unsigned' => true, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null], + 'state_user_id' => ['type' => 'integer', 'length' => 10, 'unsigned' => true, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null], + 'transaction_id' => ['type' => 'integer', 'length' => 10, 'unsigned' => true, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null], + 'transaction_type_id' => ['type' => 'integer', 'length' => 10, 'unsigned' => true, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null], + '_constraints' => [ + 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], + ], + '_options' => [ + 'engine' => 'InnoDB', + 'collation' => 'utf8mb4_unicode_ci' + ], + ]; + // @codingStandardsIgnoreEnd + /** + * Init method + * + * @return void + */ + public function init() + { + $this->records = [ + [ + 'id' => 1, + 'state_user_id' => 1, + 'transaction_id' => 1, + 'transaction_type_id' => 1, + ], + ]; + parent::init(); + } +} diff --git a/tests/TestCase/Controller/AddressTypesControllerTest.php b/tests/TestCase/Controller/AddressTypesControllerTest.php new file mode 100644 index 000000000..835fc8d08 --- /dev/null +++ b/tests/TestCase/Controller/AddressTypesControllerTest.php @@ -0,0 +1,77 @@ +markTestIncomplete('Not implemented yet.'); + } + + /** + * Test view method + * + * @return void + */ + public function testView() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test add method + * + * @return void + */ + public function testAdd() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test edit method + * + * @return void + */ + public function testEdit() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test delete method + * + * @return void + */ + public function testDelete() + { + $this->markTestIncomplete('Not implemented yet.'); + } +} diff --git a/tests/TestCase/Controller/StateUserTransactionsControllerTest.php b/tests/TestCase/Controller/StateUserTransactionsControllerTest.php new file mode 100644 index 000000000..0c9e0a513 --- /dev/null +++ b/tests/TestCase/Controller/StateUserTransactionsControllerTest.php @@ -0,0 +1,78 @@ +markTestIncomplete('Not implemented yet.'); + } + + /** + * Test view method + * + * @return void + */ + public function testView() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test add method + * + * @return void + */ + public function testAdd() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test edit method + * + * @return void + */ + public function testEdit() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test delete method + * + * @return void + */ + public function testDelete() + { + $this->markTestIncomplete('Not implemented yet.'); + } +} diff --git a/tests/TestCase/Model/Entity/TableTest.php b/tests/TestCase/Model/Entity/TableTest.php new file mode 100644 index 000000000..5a189942a --- /dev/null +++ b/tests/TestCase/Model/Entity/TableTest.php @@ -0,0 +1,51 @@ +Table = new Table(); + } + + /** + * tearDown method + * + * @return void + */ + public function tearDown() + { + unset($this->Table); + + parent::tearDown(); + } + + /** + * Test initial setup + * + * @return void + */ + public function testInitialization() + { + $this->markTestIncomplete('Not implemented yet.'); + } +} diff --git a/tests/TestCase/Model/Table/AddressTypesTableTest.php b/tests/TestCase/Model/Table/AddressTypesTableTest.php new file mode 100644 index 000000000..8f145215c --- /dev/null +++ b/tests/TestCase/Model/Table/AddressTypesTableTest.php @@ -0,0 +1,74 @@ +exists('AddressTypes') ? [] : ['className' => AddressTypesTable::class]; + $this->AddressTypes = TableRegistry::getTableLocator()->get('AddressTypes', $config); + } + + /** + * tearDown method + * + * @return void + */ + public function tearDown() + { + unset($this->AddressTypes); + + parent::tearDown(); + } + + /** + * Test initialize method + * + * @return void + */ + public function testInitialize() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test validationDefault method + * + * @return void + */ + public function testValidationDefault() + { + $this->markTestIncomplete('Not implemented yet.'); + } +} diff --git a/tests/TestCase/Model/Table/StateBalancesTableTest.php b/tests/TestCase/Model/Table/StateBalancesTableTest.php new file mode 100644 index 000000000..9ab6d30f0 --- /dev/null +++ b/tests/TestCase/Model/Table/StateBalancesTableTest.php @@ -0,0 +1,133 @@ +exists('StateBalances') ? [] : ['className' => StateBalancesTable::class]; + $this->StateBalancesTable = TableRegistry::getTableLocator()->get('StateBalances', $config); + } + + /** + * tearDown method + * + * @return void + */ + public function tearDown() + { + unset($this->StateBalancesTable); + + parent::tearDown(); + } + + /** + * Test initialize method + * + * @return void + */ + public function testInitialize() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test validationDefault method + * + * @return void + */ + public function testValidationDefault() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test buildRules method + * + * @return void + */ + public function testBuildRules() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test sortTransactions method + * + * @return void + */ + public function testSortTransactions() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test updateLastStateBalanceOfMonth method + * + * @return void + */ + public function testUpdateLastStateBalanceOfMonth() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test chooseForMonthAndUser method + * + * @return void + */ + public function testChooseForMonthAndUser() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test updateBalanceWithTransaction method + * + * @return void + */ + public function testUpdateBalanceWithTransaction() + { + $this->markTestIncomplete('Not implemented yet.'); + } + /* + * calculate balance at end of month + * work only if state balance at begin of month exist + * use transaction_send_coins and transaction_creations + */ + //public function updateLastStateBalanceOfMonth($month, $year, $state_user_id) + public function testUpdateLastStateBalanceOfMonth() + { + + } +} diff --git a/tests/TestCase/Model/Table/StateUserTransactionsTableTest.php b/tests/TestCase/Model/Table/StateUserTransactionsTableTest.php new file mode 100644 index 000000000..173ad8e12 --- /dev/null +++ b/tests/TestCase/Model/Table/StateUserTransactionsTableTest.php @@ -0,0 +1,85 @@ +exists('StateUserTransactions') ? [] : ['className' => StateUserTransactionsTable::class]; + $this->StateUserTransactions = TableRegistry::getTableLocator()->get('StateUserTransactions', $config); + } + + /** + * tearDown method + * + * @return void + */ + public function tearDown() + { + unset($this->StateUserTransactions); + + parent::tearDown(); + } + + /** + * Test initialize method + * + * @return void + */ + public function testInitialize() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test validationDefault method + * + * @return void + */ + public function testValidationDefault() + { + $this->markTestIncomplete('Not implemented yet.'); + } + + /** + * Test buildRules method + * + * @return void + */ + public function testBuildRules() + { + $this->markTestIncomplete('Not implemented yet.'); + } +} diff --git a/webroot/css/fonts_local.css b/webroot/css/fonts_local.css new file mode 100644 index 000000000..99dac0484 --- /dev/null +++ b/webroot/css/fonts_local.css @@ -0,0 +1,79 @@ +/* +To change this license header, choose License Headers in Project Properties. +To change this template file, choose Tools | Templates +and open the template in the editor. +*/ +/* + Created on : 21.01.2021, 12:32:20 + Author : einhornimmond +*/ + +/* open-sans-300 - latin */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 300; + src: url('../fonts/open-sans-v18-latin-300.eot'); /* IE9 Compat Modes */ + src: local(''), + url('../fonts/open-sans-v18-latin-300.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/open-sans-v18-latin-300.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/open-sans-v18-latin-300.woff') format('woff'), /* Modern Browsers */ + url('../fonts/open-sans-v18-latin-300.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/open-sans-v18-latin-300.svg#OpenSans') format('svg'); /* Legacy iOS */ +} + +/* open-sans-regular - latin */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + src: url('../fonts/open-sans-v18-latin-regular.eot'); /* IE9 Compat Modes */ + src: local(''), + url('../fonts/open-sans-v18-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/open-sans-v18-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/open-sans-v18-latin-regular.woff') format('woff'), /* Modern Browsers */ + url('../fonts/open-sans-v18-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/open-sans-v18-latin-regular.svg#OpenSans') format('svg'); /* Legacy iOS */ +} + +/* open-sans-600 - latin */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 600; + src: url('../fonts/open-sans-v18-latin-600.eot'); /* IE9 Compat Modes */ + src: local(''), + url('../fonts/open-sans-v18-latin-600.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/open-sans-v18-latin-600.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/open-sans-v18-latin-600.woff') format('woff'), /* Modern Browsers */ + url('../fonts/open-sans-v18-latin-600.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/open-sans-v18-latin-600.svg#OpenSans') format('svg'); /* Legacy iOS */ +} + +/* open-sans-700 - latin */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 700; + src: url('../fonts/open-sans-v18-latin-700.eot'); /* IE9 Compat Modes */ + src: local(''), + url('../fonts/open-sans-v18-latin-700.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/open-sans-v18-latin-700.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/open-sans-v18-latin-700.woff') format('woff'), /* Modern Browsers */ + url('../fonts/open-sans-v18-latin-700.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/open-sans-v18-latin-700.svg#OpenSans') format('svg'); /* Legacy iOS */ +} + +/* open-sans-800 - latin */ +@font-face { + font-family: 'Open Sans'; + font-style: normal; + font-weight: 800; + src: url('../fonts/open-sans-v18-latin-800.eot'); /* IE9 Compat Modes */ + src: local(''), + url('../fonts/open-sans-v18-latin-800.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('../fonts/open-sans-v18-latin-800.woff2') format('woff2'), /* Super Modern Browsers */ + url('../fonts/open-sans-v18-latin-800.woff') format('woff'), /* Modern Browsers */ + url('../fonts/open-sans-v18-latin-800.ttf') format('truetype'), /* Safari, Android, iOS */ + url('../fonts/open-sans-v18-latin-800.svg#OpenSans') format('svg'); /* Legacy iOS */ +} diff --git a/webroot/favicon.png b/webroot/favicon.png new file mode 100644 index 000000000..5c437973e Binary files /dev/null and b/webroot/favicon.png differ diff --git a/webroot/fonts/open-sans-v18-latin-300.eot b/webroot/fonts/open-sans-v18-latin-300.eot new file mode 100644 index 000000000..1c0f100ba Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-300.eot differ diff --git a/webroot/fonts/open-sans-v18-latin-300.svg b/webroot/fonts/open-sans-v18-latin-300.svg new file mode 100644 index 000000000..c0a1c8cd7 --- /dev/null +++ b/webroot/fonts/open-sans-v18-latin-300.svg @@ -0,0 +1,332 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/webroot/fonts/open-sans-v18-latin-300.ttf b/webroot/fonts/open-sans-v18-latin-300.ttf new file mode 100644 index 000000000..dcce1bb7d Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-300.ttf differ diff --git a/webroot/fonts/open-sans-v18-latin-300.woff b/webroot/fonts/open-sans-v18-latin-300.woff new file mode 100644 index 000000000..26567ff25 Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-300.woff differ diff --git a/webroot/fonts/open-sans-v18-latin-300.woff2 b/webroot/fonts/open-sans-v18-latin-300.woff2 new file mode 100644 index 000000000..7bf901c28 Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-300.woff2 differ diff --git a/webroot/fonts/open-sans-v18-latin-600.eot b/webroot/fonts/open-sans-v18-latin-600.eot new file mode 100644 index 000000000..b0d46a4ce Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-600.eot differ diff --git a/webroot/fonts/open-sans-v18-latin-600.svg b/webroot/fonts/open-sans-v18-latin-600.svg new file mode 100644 index 000000000..410561e78 --- /dev/null +++ b/webroot/fonts/open-sans-v18-latin-600.svg @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/webroot/fonts/open-sans-v18-latin-600.ttf b/webroot/fonts/open-sans-v18-latin-600.ttf new file mode 100644 index 000000000..25fdf1eb3 Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-600.ttf differ diff --git a/webroot/fonts/open-sans-v18-latin-600.woff b/webroot/fonts/open-sans-v18-latin-600.woff new file mode 100644 index 000000000..9d0eb42db Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-600.woff differ diff --git a/webroot/fonts/open-sans-v18-latin-600.woff2 b/webroot/fonts/open-sans-v18-latin-600.woff2 new file mode 100644 index 000000000..5c5d54e2f Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-600.woff2 differ diff --git a/webroot/fonts/open-sans-v18-latin-700.eot b/webroot/fonts/open-sans-v18-latin-700.eot new file mode 100644 index 000000000..5b9ddb4eb Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-700.eot differ diff --git a/webroot/fonts/open-sans-v18-latin-700.svg b/webroot/fonts/open-sans-v18-latin-700.svg new file mode 100644 index 000000000..8e6b61ade --- /dev/null +++ b/webroot/fonts/open-sans-v18-latin-700.svg @@ -0,0 +1,334 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/webroot/fonts/open-sans-v18-latin-700.ttf b/webroot/fonts/open-sans-v18-latin-700.ttf new file mode 100644 index 000000000..c9a3c7a48 Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-700.ttf differ diff --git a/webroot/fonts/open-sans-v18-latin-700.woff b/webroot/fonts/open-sans-v18-latin-700.woff new file mode 100644 index 000000000..b8b46d0b4 Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-700.woff differ diff --git a/webroot/fonts/open-sans-v18-latin-700.woff2 b/webroot/fonts/open-sans-v18-latin-700.woff2 new file mode 100644 index 000000000..3a38286c6 Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-700.woff2 differ diff --git a/webroot/fonts/open-sans-v18-latin-800.eot b/webroot/fonts/open-sans-v18-latin-800.eot new file mode 100644 index 000000000..b9d7b260c Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-800.eot differ diff --git a/webroot/fonts/open-sans-v18-latin-800.svg b/webroot/fonts/open-sans-v18-latin-800.svg new file mode 100644 index 000000000..f2a2d9f6e --- /dev/null +++ b/webroot/fonts/open-sans-v18-latin-800.svg @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/webroot/fonts/open-sans-v18-latin-800.ttf b/webroot/fonts/open-sans-v18-latin-800.ttf new file mode 100644 index 000000000..a62af861f Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-800.ttf differ diff --git a/webroot/fonts/open-sans-v18-latin-800.woff b/webroot/fonts/open-sans-v18-latin-800.woff new file mode 100644 index 000000000..bdac80d5c Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-800.woff differ diff --git a/webroot/fonts/open-sans-v18-latin-800.woff2 b/webroot/fonts/open-sans-v18-latin-800.woff2 new file mode 100644 index 000000000..86a8a8757 Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-800.woff2 differ diff --git a/webroot/fonts/open-sans-v18-latin-regular.eot b/webroot/fonts/open-sans-v18-latin-regular.eot new file mode 100644 index 000000000..8f3becf66 Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-regular.eot differ diff --git a/webroot/fonts/open-sans-v18-latin-regular.svg b/webroot/fonts/open-sans-v18-latin-regular.svg new file mode 100644 index 000000000..78eb653a7 --- /dev/null +++ b/webroot/fonts/open-sans-v18-latin-regular.svg @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/webroot/fonts/open-sans-v18-latin-regular.ttf b/webroot/fonts/open-sans-v18-latin-regular.ttf new file mode 100644 index 000000000..fb23764c1 Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-regular.ttf differ diff --git a/webroot/fonts/open-sans-v18-latin-regular.woff b/webroot/fonts/open-sans-v18-latin-regular.woff new file mode 100644 index 000000000..39e88ed92 Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-regular.woff differ diff --git a/webroot/fonts/open-sans-v18-latin-regular.woff2 b/webroot/fonts/open-sans-v18-latin-regular.woff2 new file mode 100644 index 000000000..e9f58b775 Binary files /dev/null and b/webroot/fonts/open-sans-v18-latin-regular.woff2 differ