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 ]; } }