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 @@
Main currency: = $community->getCurrency() ?>
- 0): ?> -Further currencies: = implode(', ', $currencyCodes) ?>
+ 0): ?> +Further currencies: + + = $currency->getCode() ?> + +
Exchange rate | +Valid from | ++ + | Exchange rate | +Valid from | + +
---|---|---|---|---|
+ + + + | ++ + | ++ + | + += $currencyExchangeRate->getExchangeRate() ?> | += $currencyExchangeRate->getValidFromDate()->format('Y-m-d H:i') ?> | + +
+ + + | ++ + | ++ + | +