diff --git a/database/migrations/structure/20230423_2022_currency_exchange_rates.sql b/database/migrations/structure/20230423_2022_currency_exchange_rates.sql new file mode 100644 index 0000000..e37020c --- /dev/null +++ b/database/migrations/structure/20230423_2022_currency_exchange_rates.sql @@ -0,0 +1,10 @@ +CREATE TABLE `currency_exchange_rates` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `currency_id` int(10) unsigned NOT NULL, + `exchange_rate` decimal(19,9) unsigned NOT NULL, + `valid_from` timestamp NOT NULL DEFAULT current_timestamp(), + PRIMARY KEY (`id`), + KEY `currency_id` (`currency_id`), + INDEX `valid_from` (`valid_from`), + CONSTRAINT `currency_exchange_rates_currency_id` FOREIGN KEY (`currency_id`) REFERENCES `currencies` (`id`) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; diff --git a/public/static/css/rvr.css b/public/static/css/rvr.css index bef5c87..ec9c086 100644 --- a/public/static/css/rvr.css +++ b/public/static/css/rvr.css @@ -113,7 +113,7 @@ p.small, span.small { } .marginLeft { - margin-left: 10px; + margin-left: 5px; } .marginBottom { @@ -121,7 +121,7 @@ p.small, span.small { } .marginRight { - margin-right: 10px; + margin-right: 5px; } .center { @@ -455,7 +455,7 @@ table th { } table th, table td { - padding: 2px 0; + padding: 3px 0; vertical-align: middle; } @@ -485,6 +485,7 @@ table th:not(:last-child), table td:not(:last-child) { margin-top: 4px; } button, a.button { + margin: 3px 0; padding: 0; width: 100%; } diff --git a/src/Controller/CommunityController.php b/src/Controller/CommunityController.php index fb5eeca..ef2f274 100644 --- a/src/Controller/CommunityController.php +++ b/src/Controller/CommunityController.php @@ -4,9 +4,11 @@ use DateTime; use RVR\PersistentData\Model\Community; use RVR\PersistentData\Model\CommunityMember; use RVR\PersistentData\Model\Currency; +use RVR\PersistentData\Model\CurrencyExchangeRate; use RVR\PersistentData\Model\User; use RVR\Repository\CommunityRepository; use RVR\Repository\CommunityMemberRepository; +use RVR\Repository\CurrencyExchangeRateRepository; use RVR\Repository\CurrencyRepository; use RVR\Repository\UserRepository; use SokoWeb\Interfaces\Authentication\IAuthenticationRequired; @@ -24,12 +26,15 @@ class CommunityController implements IAuthenticationRequired private CurrencyRepository $currencyRepository; + private CurrencyExchangeRateRepository $currencyExchangeRatesRepository; + public function __construct() { $this->userRepository = new UserRepository(); $this->communityRepository = new CommunityRepository(); $this->communityMemberRepository = new CommunityMemberRepository(); $this->currencyRepository = new CurrencyRepository(); + $this->currencyExchangeRatesRepository = new CurrencyExchangeRateRepository(); } public function isAuthenticationRequired(): bool @@ -43,15 +48,10 @@ class CommunityController implements IAuthenticationRequired return null; } - $currencyCodes = []; - foreach ($this->getCurrencies($community) as $currency) { - $currencyCodes[] = $currency->getCode(); - } - return new HtmlContent('communities/community', [ 'community' => $community, 'members' => $this->getMembers($community), - 'currencyCodes' => $currencyCodes, + 'currencies' => $this->getCurrencies($community), 'upcomingEvents' => [], 'editPermission' => $ownCommunityMember->getOwner() ]); @@ -207,6 +207,91 @@ class CommunityController implements IAuthenticationRequired return new JsonContent(['success' => true]); } + public function getCurrencyExchangeRates(): ?IContent + { + if (!$this->checkPermission(\Container::$request->query('communityId'), true, $community, $ownCommunityMember)) { + return null; + } + + $currency = $this->currencyRepository->getByCommunityAndCurrencyCode($community, \Container::$request->query('code')); + if ($currency === null) { + return null; + } + + $currencyExchangeRates = $this->currencyExchangeRatesRepository->getAllByCurrency($currency); + + return new HtmlContent('communities/currency_exchange_rates', [ + 'community' => $community, + 'currency' => $currency, + 'currencyExchangeRates' => $currencyExchangeRates, + 'editPermission' => $ownCommunityMember->getOwner() + ]); + } + + public function newCurrencyExchangeRate(): ?IContent + { + if (!$this->checkPermission(\Container::$request->query('communityId'), true, $community, $ownCommunityMember)) { + return null; + } + + $currency = $this->currencyRepository->getByCommunityAndCurrencyCode($community, \Container::$request->query('code')); + if ($currency === null) { + return null; + } + + $exchangeRate = (float)\Container::$request->post('exchange_rate'); + if ($exchangeRate < 0) { + return new JsonContent([ + 'error' => ['errorText' => 'Please fill all required fields!'] + ]); + } + + $currencyExchangeRate = new CurrencyExchangeRate(); + $currencyExchangeRate->setCurrency($currency); + $currencyExchangeRate->setExchangeRate($exchangeRate); + $currencyExchangeRate->setValidFromDate(new DateTime(\Container::$request->post('valid_from'))); + \Container::$persistentDataManager->saveToDb($currencyExchangeRate); + + return new JsonContent(['success' => true]); + } + + public function editCurrencyExchangeRate(): ?IContent + { + if (!$this->checkPermission(\Container::$request->query('communityId'), true, $community, $ownCommunityMember)) { + return null; + } + + $currency = $this->currencyRepository->getByCommunityAndCurrencyCode($community, \Container::$request->query('code')); + if ($currency === null) { + return null; + } + + $currencyExchangeRate = $this->currencyExchangeRatesRepository->getById(\Container::$request->query('currency_exchange_rate_id')); + $currencyExchangeRate->setCurrency($currency); + $currencyExchangeRate->setExchangeRate((float)\Container::$request->post('exchange_rate')); + $currencyExchangeRate->setValidFromDate(new DateTime(\Container::$request->post('valid_from'))); + \Container::$persistentDataManager->saveToDb($currencyExchangeRate); + + return new JsonContent(['success' => true]); + } + + public function deleteCurrencyExchangeRate(): ?IContent + { + if (!$this->checkPermission(\Container::$request->query('communityId'), true, $community, $ownCommunityMember)) { + return null; + } + + $currency = $this->currencyRepository->getByCommunityAndCurrencyCode($community, \Container::$request->query('code')); + if ($currency === null) { + return null; + } + + $currencyExchangeRate = $this->currencyExchangeRatesRepository->getById(\Container::$request->query('currency_exchange_rate_id')); + \Container::$persistentDataManager->deleteFromDb($currencyExchangeRate); + + return new JsonContent(['success' => true]); + } + public function saveCommunity(): ?IContent { $communityId = \Container::$request->query('communityId'); diff --git a/src/PersistentData/Model/CurrencyExchangeRate.php b/src/PersistentData/Model/CurrencyExchangeRate.php new file mode 100644 index 0000000..0b2e403 --- /dev/null +++ b/src/PersistentData/Model/CurrencyExchangeRate.php @@ -0,0 +1,71 @@ + Currency::class]; + + private ?Currency $currency = null; + + private ?int $currencyId = null; + + private float $exchangeRate = 0.0; + + private DateTime $validFrom; + + public function setCurrency(Currency $currency): void + { + $this->currency = $currency; + } + + public function setCurrencyId(int $currencyId): void + { + $this->currencyId = $currencyId; + } + + public function setExchangeRate(float $exchangeRate): void + { + $this->exchangeRate = $exchangeRate; + } + + public function setValidFromDate(DateTime $validFrom): void + { + $this->validFrom = $validFrom; + } + + public function setValidFrom(string $validFrom): void + { + $this->validFrom = new DateTime($validFrom); + } + + public function getCurrency(): ?Currency + { + return $this->currency; + } + + public function getCurrencyId(): ?int + { + return $this->currencyId; + } + + public function getExchangeRate(): float + { + return $this->exchangeRate; + } + + public function getValidFromDate(): DateTime + { + return $this->validFrom; + } + + public function getValidFrom(): string + { + return $this->validFrom->format('Y-m-d H:i:s'); + } +} diff --git a/src/Repository/CurrencyExchangeRateRepository.php b/src/Repository/CurrencyExchangeRateRepository.php new file mode 100644 index 0000000..d382c36 --- /dev/null +++ b/src/Repository/CurrencyExchangeRateRepository.php @@ -0,0 +1,24 @@ +selectFromDbById($id, CurrencyExchangeRate::class); + } + + public function getAllByCurrency(Currency $currency): Generator + { + $select = new Select(Container::$dbConnection); + $select->where('currency_id', '=', $currency->getId()); + $select->orderBy('valid_from'); + + yield from Container::$persistentDataManager->selectMultipleFromDb($select, CurrencyExchangeRate::class); + } +} diff --git a/views/communities/community.php b/views/communities/community.php index 4630656..c703adc 100644 --- a/views/communities/community.php +++ b/views/communities/community.php @@ -17,8 +17,12 @@

Currencies

Main currency: getCurrency() ?>

- 0): ?> -

Further currencies:

+ 0): ?> +

Further currencies: + + getCode() ?> + +


diff --git a/views/communities/community_currencies.php b/views/communities/community_currencies.php index 5fe60ca..9f51ec5 100644 --- a/views/communities/community_currencies.php +++ b/views/communities/community_currencies.php @@ -1,7 +1,7 @@ @extends(templates/layout_normal) @section(main) -

getName() ?> - Edit currencies

+

getName() ?> - Edit currencies

diff --git a/views/communities/community_edit.php b/views/communities/community_edit.php index 7b03346..bd2b0e1 100644 --- a/views/communities/community_edit.php +++ b/views/communities/community_edit.php @@ -1,7 +1,13 @@ @extends(templates/layout_normal) @section(main) -

getName() . ' - Edit' : 'New community' ?>

+

+ + getName() ?> - Edit + + New community + +

getName() ?> - Edit members +

getName() ?> - Edit members

diff --git a/views/communities/currency_exchange_rates.php b/views/communities/currency_exchange_rates.php new file mode 100644 index 0000000..60f0fe7 --- /dev/null +++ b/views/communities/currency_exchange_rates.php @@ -0,0 +1,57 @@ +@extends(templates/layout_normal) + +@section(main) +

getName() ?> - Exchange rates for getCode() ?>

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Exchange rateValid fromExchange rateValid from
+
+
+ +
+ + + + getExchangeRate() ?>getValidFromDate()->format('Y-m-d H:i') ?>
+
+ +
+ + + +
+

+
+@endsection diff --git a/web.php b/web.php index 15addbe..4b7f3a8 100644 --- a/web.php +++ b/web.php @@ -70,6 +70,12 @@ Container::$routeCollection->group('communities', function (RouteCollection $rou $routeCollection->post('community-currencies-new', 'newCurrency', [CommunityController::class, 'newCurrency']); $routeCollection->post('community-currencies-edit', 'editCurrency', [CommunityController::class, 'editCurrency']); $routeCollection->post('community-currencies-delete', 'deleteCurrency', [CommunityController::class, 'deleteCurrency']); + $routeCollection->group('currencyExchangeRates', function (RouteCollection $routeCollection) { + $routeCollection->get('community-currency-exchange-rates', '{code}', [CommunityController::class, 'getCurrencyExchangeRates']); + $routeCollection->post('community-currency-exchange-rates-new', '{code}/new', [CommunityController::class, 'newCurrencyExchangeRate']); + $routeCollection->post('community-currency-exchange-rates-edit', '{code}/edit', [CommunityController::class, 'editCurrencyExchangeRate']); + $routeCollection->post('community-currency-exchange-rates-delete', '{code}/delete', [CommunityController::class, 'deleteCurrencyExchangeRate']); + }); }); });