Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17d9437a50
|
||
|
|
aed4548c7b
|
||
|
|
0d6d152b82
|
||
|
|
7beec510a1
|
||
|
|
22b849a1c8
|
||
|
|
492aa9fcef
|
||
|
|
b6da70e015
|
||
|
|
afead7fd61
|
||
|
|
69acbf708b
|
||
|
|
08ebfae030
|
No files matched your search
@@ -59,32 +59,21 @@ class CommunityController implements IAuthenticationRequired
|
||||
|
||||
\Container::$persistentDataManager->loadRelationsFromDb($community, false, ['main_currency']);
|
||||
|
||||
$balanceCalculator = new BalanceCalculator($community);
|
||||
$debts = $balanceCalculator->calculate();
|
||||
$debtItems = [];
|
||||
$debtBalance = 0.0;
|
||||
$outstandingItems = [];
|
||||
$outstandingBalance = 0.0;
|
||||
foreach ($debts as $debt) {
|
||||
if ($debt['payer']->getId() === \Container::$request->user()->getUniqueId()) {
|
||||
$debtBalance += $debt['amount'];
|
||||
$debtItems[] = $debt;
|
||||
}
|
||||
if ($debt['payee']->getId() === \Container::$request->user()->getUniqueId()) {
|
||||
$outstandingBalance += $debt['amount'];
|
||||
$outstandingItems[] = $debt;
|
||||
}
|
||||
}
|
||||
$balance = $outstandingBalance - $debtBalance;
|
||||
/**
|
||||
* @var User $user
|
||||
*/
|
||||
$user = \Container::$request->user();
|
||||
$balanceCalculator = new BalanceCalculator($community, $user);
|
||||
$balance = $balanceCalculator->calculate();
|
||||
|
||||
return new HtmlContent('communities/community', [
|
||||
'community' => $community,
|
||||
'upcomingAndRecentEvents' => iterator_to_array($this->eventRepository->getUpcomingAndRecentByCommunity($community, new DateTime(), 30, 3)),
|
||||
'debtItems' => $debtItems,
|
||||
'debtBalance' => $debtBalance,
|
||||
'outstandingItems' => $outstandingItems,
|
||||
'outstandingBalance' => $outstandingBalance,
|
||||
'balance' => $balance,
|
||||
'debtItems' => $balance['debtItems'],
|
||||
'debtBalance' => $balance['debtBalance'],
|
||||
'outstandingItems' => $balance['outstandingItems'],
|
||||
'outstandingBalance' => $balance['outstandingBalance'],
|
||||
'balance' => $balance['absoluteBalance'],
|
||||
'editPermission' => $ownCommunityMember->getOwner()
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use Container;
|
||||
use DateTime;
|
||||
use RVR\Finance\BalanceCalculator;
|
||||
use RVR\Finance\ExchangeRateCalculator;
|
||||
use RVR\PersistentData\Model\Community;
|
||||
use RVR\PersistentData\Model\CommunityMember;
|
||||
@@ -105,10 +106,22 @@ class EventController implements IAuthenticationRequired, ISecured
|
||||
}
|
||||
Container::$persistentDataManager->loadRelationsFromDb($this->community, true, ['main_currency']);
|
||||
|
||||
/**
|
||||
* @var User $user
|
||||
*/
|
||||
$user = \Container::$request->user();
|
||||
$balanceCalculator = new BalanceCalculator($this->community, $user, $event);
|
||||
$balance = $balanceCalculator->calculate();
|
||||
|
||||
return new HtmlContent('events/event', [
|
||||
'community' => $this->community,
|
||||
'event' => $event,
|
||||
'totalCost' => $this->sumTransactions($event)
|
||||
'totalCost' => $this->sumTransactions($event),
|
||||
'debtItems' => $balance['debtItems'],
|
||||
'debtBalance' => $balance['debtBalance'],
|
||||
'outstandingItems' => $balance['outstandingItems'],
|
||||
'outstandingBalance' => $balance['outstandingBalance'],
|
||||
'balance' => $balance['absoluteBalance'],
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php namespace RVR\Controller;
|
||||
|
||||
use DateTime;
|
||||
use Container;
|
||||
use RVR\PersistentData\Model\Event;
|
||||
use RVR\PersistentData\Model\User;
|
||||
use RVR\Repository\EventRepository;
|
||||
use SokoWeb\Interfaces\Authentication\IAuthenticationRequired;
|
||||
use SokoWeb\Interfaces\Response\IRedirect;
|
||||
use SokoWeb\Response\HtmlContent;
|
||||
use SokoWeb\Response\Redirect;
|
||||
|
||||
class EventRedirectController implements IAuthenticationRequired
|
||||
{
|
||||
private EventRepository $eventRepository;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->eventRepository = new EventRepository();
|
||||
}
|
||||
|
||||
public function isAuthenticationRequired(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getEvent()
|
||||
{
|
||||
$currentEvent = $this->getCurrentEvent();
|
||||
if ($currentEvent === null) {
|
||||
return new HtmlContent('event_redirect/no_event');
|
||||
}
|
||||
|
||||
return new Redirect(
|
||||
\Container::$routeCollection->getRoute('community.event')
|
||||
->generateLink([
|
||||
'communitySlug' => $currentEvent->getCommunity()->getSlug(),
|
||||
'eventSlug' => $currentEvent->getSlug()
|
||||
]),
|
||||
IRedirect::TEMPORARY
|
||||
);
|
||||
}
|
||||
|
||||
public function getEventNewTransaction()
|
||||
{
|
||||
$currentEvent = $this->getCurrentEvent();
|
||||
if ($currentEvent === null) {
|
||||
return new HtmlContent('event_redirect/no_event');
|
||||
}
|
||||
|
||||
return new Redirect(
|
||||
\Container::$routeCollection->getRoute('community.transactions.new')
|
||||
->generateLink([
|
||||
'communitySlug' => $currentEvent->getCommunity()->getSlug(),
|
||||
'event' => $currentEvent->getSlug()
|
||||
]),
|
||||
IRedirect::TEMPORARY
|
||||
);
|
||||
}
|
||||
|
||||
private function getCurrentEvent(): ?Event
|
||||
{
|
||||
/**
|
||||
* @var User $user
|
||||
*/
|
||||
$user = Container::$request->user();
|
||||
|
||||
return $this->eventRepository->getCurrentByUser($user, new DateTime(), 30, true, ['community']);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
use Container;
|
||||
use RVR\PersistentData\Model\Community;
|
||||
use RVR\PersistentData\Model\Event;
|
||||
use RVR\PersistentData\Model\User;
|
||||
use RVR\Repository\CommunityMemberRepository;
|
||||
use RVR\Repository\TransactionRepository;
|
||||
|
||||
@@ -9,6 +11,10 @@ class BalanceCalculator
|
||||
{
|
||||
private Community $community;
|
||||
|
||||
private User $user;
|
||||
|
||||
private ?Event $event;
|
||||
|
||||
private TransactionRepository $transactionRepository;
|
||||
|
||||
private CommunityMemberRepository $communityMemberRepository;
|
||||
@@ -19,9 +25,13 @@ class BalanceCalculator
|
||||
|
||||
private array $payments;
|
||||
|
||||
public function __construct(Community $community)
|
||||
private array $actualDebts;
|
||||
|
||||
public function __construct(Community $community, User $user, ?Event $event = null)
|
||||
{
|
||||
$this->community = $community;
|
||||
$this->user = $user;
|
||||
$this->event = $event;
|
||||
$this->transactionRepository = new TransactionRepository();
|
||||
$this->communityMemberRepository = new CommunityMemberRepository();
|
||||
$this->exchangeRateCalculator = new ExchangeRateCalculator($this->community->getMainCurrency());
|
||||
@@ -32,7 +42,8 @@ class BalanceCalculator
|
||||
$this->collectMembers();
|
||||
$this->createPaymentsMatrix();
|
||||
$this->sumTransactions();
|
||||
return $this->calculateActualDebts();
|
||||
$this->calculateActualDebts();
|
||||
return $this->calculateBalanceForUser();
|
||||
}
|
||||
|
||||
private function collectMembers(): void
|
||||
@@ -57,7 +68,11 @@ class BalanceCalculator
|
||||
private function sumTransactions(): void
|
||||
{
|
||||
$membersCount = count($this->members);
|
||||
$transactions = iterator_to_array($this->transactionRepository->getAllByCommunity($this->community, true, ['currency']));
|
||||
if ($this->event !== null) {
|
||||
$transactions = iterator_to_array($this->transactionRepository->getAllByEvent($this->event, true, ['currency']));
|
||||
} else {
|
||||
$transactions = iterator_to_array($this->transactionRepository->getAllByCommunity($this->community, true, ['currency']));
|
||||
}
|
||||
Container::$persistentDataManager->loadMultiRelationsFromDb($transactions, 'payees');
|
||||
|
||||
foreach ($transactions as $transaction) {
|
||||
@@ -77,20 +92,45 @@ class BalanceCalculator
|
||||
}
|
||||
}
|
||||
|
||||
private function calculateActualDebts(): array
|
||||
private function calculateActualDebts(): void
|
||||
{
|
||||
$actualDebts = [];
|
||||
$this->actualDebts = [];
|
||||
|
||||
foreach ($this->payments as $payerUserId => $paymentsOfPayer) {
|
||||
foreach ($paymentsOfPayer as $payeeUserId => $sum) {
|
||||
$actualDebt = $this->payments[$payeeUserId][$payerUserId] - $sum;
|
||||
|
||||
if (round($actualDebt, $this->community->getMainCurrency()->getRoundDigits()) > 0.0) {
|
||||
$actualDebts[] = ['payer' => $this->members[$payerUserId], 'payee' => $this->members[$payeeUserId], 'amount' => $actualDebt];
|
||||
$this->actualDebts[] = ['payer' => $this->members[$payerUserId], 'payee' => $this->members[$payeeUserId], 'amount' => $actualDebt];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $actualDebts;
|
||||
private function calculateBalanceForUser(): array
|
||||
{
|
||||
$debtItems = [];
|
||||
$debtBalance = 0.0;
|
||||
$outstandingItems = [];
|
||||
$outstandingBalance = 0.0;
|
||||
foreach ($this->actualDebts as $debt) {
|
||||
if ($debt['payer']->getId() === $this->user->getId()) {
|
||||
$debtBalance += $debt['amount'];
|
||||
$debtItems[] = $debt;
|
||||
}
|
||||
if ($debt['payee']->getId() === $this->user->getId()) {
|
||||
$outstandingBalance += $debt['amount'];
|
||||
$outstandingItems[] = $debt;
|
||||
}
|
||||
}
|
||||
$absoluteBalance = $outstandingBalance - $debtBalance;
|
||||
|
||||
return [
|
||||
'absoluteBalance' => $absoluteBalance,
|
||||
'debtItems' => $debtItems,
|
||||
'debtBalance' => $debtBalance,
|
||||
'outstandingItems' => $outstandingItems,
|
||||
'outstandingBalance' => $outstandingBalance
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,16 @@ class EventRepository
|
||||
yield from Container::$persistentDataManager->selectMultipleFromDb($select, Event::class, $useRelations, $withRelations);
|
||||
}
|
||||
|
||||
public function getCurrentByUser(User $user, DateTime $from, int $days, bool $useRelations = false, array $withRelations = []): ?Event
|
||||
{
|
||||
$select = $this->selectAllByUser($user);
|
||||
$this->selectUpcomingAndRecent($select, $from, $days);
|
||||
$select->orderBy('start', 'DESC');
|
||||
$select->limit(1, 0);
|
||||
|
||||
return Container::$persistentDataManager->selectFromDb($select, Event::class, $useRelations, $withRelations);
|
||||
}
|
||||
|
||||
public function getPagedByCommunity(Community $community, int $page, int $itemsPerPage, bool $useRelations = false, array $withRelations = []): Generator
|
||||
{
|
||||
$select = $this->selectAllByCommunity($community);
|
||||
@@ -92,7 +102,11 @@ class EventRepository
|
||||
{
|
||||
$select->where(function (Select $select) use ($from, $days) {
|
||||
$select->where('start', '<', (clone $from)->add(DateInterval::createFromDateString("$days days"))->format('Y-m-d H:i:s'));
|
||||
$select->orWhere('end', '>', (clone $from)->sub(DateInterval::createFromDateString("$days days"))->format('Y-m-d H:i:s'));
|
||||
$select->where('end', '>', $from->format('Y-m-d H:i:s'));
|
||||
});
|
||||
$select->orWhere(function (Select $select) use ($from, $days) {
|
||||
$select->where('end', '>', (clone $from)->sub(DateInterval::createFromDateString("$days days"))->format('Y-m-d H:i:s'));
|
||||
$select->where('start', '<', $from->format('Y-m-d H:i:s'));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,11 @@
|
||||
@section(main)
|
||||
<h2>
|
||||
<a href="<?= Container::$routeCollection->getRoute('community')->generateLink(['communitySlug' => $community->getSlug()]) ?>"><?= $community->getName() ?></a> »
|
||||
<a href="<?= Container::$routeCollection->getRoute('community.transactions')->generateLink(['communitySlug' => $community->getSlug()]) ?>">Transactions</a> »
|
||||
<?php if (isset($event)): ?>
|
||||
<a href="<?= Container::$routeCollection->getRoute('community.events')->generateLink(['communitySlug' => $community->getSlug()]) ?>">Events</a> »
|
||||
<a href="<?= Container::$routeCollection->getRoute('community.event')->generateLink(['communitySlug' => $community->getSlug(), 'eventSlug' => $event->getSlug()]) ?>"><?= $event->getTitle() ?></a> »
|
||||
<?php endif; ?>
|
||||
<a href="<?= Container::$routeCollection->getRoute('community.transactions')->generateLink(['communitySlug' => $community->getSlug(), 'event' => isset($event) ? $event->getSlug() : null]) ?>">Transactions</a> »
|
||||
<?php if (isset($transaction)): ?>
|
||||
Edit transaction
|
||||
<?php else: ?>
|
||||
@@ -36,7 +36,12 @@
|
||||
<select class="big fullWidth" name="payer_user_id" required>
|
||||
<option value="" hidden></option>
|
||||
<?php foreach ($members as $member): ?>
|
||||
<option value="<?= $member->getUser()->getId() ?>" <?= isset($transaction) && $transaction->getPayerUserId() === $member->getUser()->getId() ? 'selected' : '' ?>><?= $member->getUser()->getDisplayName() ?></option>
|
||||
<option value="<?= $member->getUser()->getId() ?>"
|
||||
<?= isset($transaction) ?
|
||||
($transaction->getPayerUserId() === $member->getUser()->getId() ? 'selected' : '') :
|
||||
(Container::$request->user()->getUniqueId() == $member->getUser()->getId() ? 'selected' : '') ?>>
|
||||
<?= $member->getUser()->getDisplayName() ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<p class="formLabel marginTop">Payee(s)</p>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
@extends(templates/layout_normal)
|
||||
|
||||
@section(main)
|
||||
<h2>No event found</h2>
|
||||
<div class="box compactBox">
|
||||
<p class="error justify">No upcoming or recent event was found. <a href="<?= Container::$routeCollection->getRoute('home')->generateLink() ?>" title="<?= $_ENV['APP_NAME'] ?>">Back to start.</a></p>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -22,6 +22,33 @@
|
||||
<td class="mono" style="text-align: right;"><?= number_format($totalCost, $mainCurrencyRoundDigits) ?> <?= $mainCurrencyCode ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class="fullWidth marginTop">
|
||||
<tr>
|
||||
<td class="bold">You owe*</td>
|
||||
<td class="mono red" style="text-align: right;"><?= number_format($debtBalance, $mainCurrencyRoundDigits) ?> <?= $mainCurrencyCode ?></td>
|
||||
</tr>
|
||||
<?php foreach ($debtItems as $item): ?>
|
||||
<tr>
|
||||
<td class="small"><?= $item['payee']->getUser()->getDisplayName() ?></td>
|
||||
<td class="small mono red" style="text-align: right;"><?= number_format($item['amount'], $mainCurrencyRoundDigits) ?> <?= $mainCurrencyCode ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<tr>
|
||||
<td class="bold">You're owed*</td>
|
||||
<td class="mono green" style="text-align: right;"><?= number_format($outstandingBalance, $mainCurrencyRoundDigits) ?> <?= $mainCurrencyCode ?></td>
|
||||
</tr>
|
||||
<?php foreach ($outstandingItems as $item): ?>
|
||||
<tr>
|
||||
<td class="small"><?= $item['payer']->getUser()->getDisplayName() ?></td>
|
||||
<td class="small mono green" style="text-align: right;"><?= number_format($item['amount'], $mainCurrencyRoundDigits) ?> <?= $mainCurrencyCode ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<tr>
|
||||
<td class="bold">Your balance*</td>
|
||||
<td class="mono <?= $balance < 0 ? 'red' : ($balance > 0 ? 'green' : '') ?>" style="text-align: right;;"><?= number_format($balance, $mainCurrencyRoundDigits) ?> <?= $mainCurrencyCode ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p class="small right">* Virtual balance only for this event. Check <a href="<?= Container::$routeCollection->getRoute('community')->generateLink(['communitySlug' => $community->getSlug()]) ?>">community</a> finances for your real balance.</p>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -13,6 +13,7 @@ use RVR\Controller\UserController;
|
||||
use RVR\Controller\UserSearchController;
|
||||
use RVR\Controller\CommunityController;
|
||||
use RVR\Controller\TransactionController;
|
||||
use RVR\Controller\EventRedirectController;
|
||||
use RVR\Controller\EventController;
|
||||
use RVR\Repository\UserRepository;
|
||||
|
||||
@@ -62,6 +63,10 @@ Container::$routeCollection->group('account', function (RouteCollection $routeCo
|
||||
$routeCollection->get('account.googleAuthenticate-action', 'googleAuthenticate/code', [UserController::class, 'authenticateWithGoogle']);
|
||||
});
|
||||
Container::$routeCollection->get('searchUser', 'searchUser', [UserSearchController::class, 'searchUser']);
|
||||
Container::$routeCollection->group('now', function (RouteCollection $routeCollection) {
|
||||
$routeCollection->get('now.event', '', [EventRedirectController::class, 'getEvent']);
|
||||
$routeCollection->get('now.transactions.new', 'transactions/new', [EventRedirectController::class, 'getEventNewTransaction']);
|
||||
});
|
||||
Container::$routeCollection->group('communities', function (RouteCollection $routeCollection) {
|
||||
$routeCollection->get('community.new', 'new', [CommunityController::class, 'getCommunityNew']);
|
||||
$routeCollection->post('community.new-action', 'new', [CommunityController::class, 'saveCommunity']);
|
||||
|
||||
Reference in new issue
Block a user