rvr-nextgen/src/Finance/BalanceCalculator.php
Pőcze Bence 08ebfae030
All checks were successful
rvr-nextgen/pipeline/pr-master This commit looks good
show balance for events
2023-07-12 00:26:59 +02:00

137 lines
4.7 KiB
PHP

<?php namespace RVR\Finance;
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;
class BalanceCalculator
{
private Community $community;
private User $user;
private ?Event $event;
private TransactionRepository $transactionRepository;
private CommunityMemberRepository $communityMemberRepository;
private ExchangeRateCalculator $exchangeRateCalculator;
private array $members;
private array $payments;
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());
}
public function calculate(): array
{
$this->collectMembers();
$this->createPaymentsMatrix();
$this->sumTransactions();
$this->calculateActualDebts();
return $this->calculateBalanceForUser();
}
private function collectMembers(): void
{
$this->members = [];
foreach ($this->communityMemberRepository->getAllByCommunity($this->community, true, ['user']) as $member) {
$this->members[$member->getUserId()] = $member;
}
}
private function createPaymentsMatrix(): void
{
$this->payments = [];
foreach ($this->members as $payerUserId => $member) {
$this->payments[$payerUserId] = [];
foreach ($this->members as $payeeUserId => $member) {
$this->payments[$payerUserId][$payeeUserId] = 0;
}
}
}
private function sumTransactions(): void
{
$membersCount = count($this->members);
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) {
$sum = $this->exchangeRateCalculator->calculate($transaction->getSum(), $transaction->getCurrency(), $transaction->getTimeDate());
$payees = $transaction->getPayees();
$payeeCount = count($payees);
if ($payeeCount > 0) {
foreach ($payees as $payee) {
$this->payments[$transaction->getPayerUserId()][$payee->getUserId()] += $sum / $payeeCount;
}
} else {
foreach ($this->members as $payeeUserId => $member) {
$this->payments[$transaction->getPayerUserId()][$payeeUserId] += $sum / $membersCount;
}
}
}
}
private function calculateActualDebts(): void
{
$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) {
$this->actualDebts[] = ['payer' => $this->members[$payerUserId], 'payee' => $this->members[$payeeUserId], 'amount' => $actualDebt];
}
}
}
}
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
];
}
}