community = $community; $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(); return $this->calculateActualDebts(); } 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); $transactions = $this->transactionRepository->getAllByCommunity($this->community, true, ['currency']); foreach ($transactions as $transaction) { $sum = $this->exchangeRateCalculator->calculate($transaction->getSum(), $transaction->getCurrency(), $transaction->getTimeDate()); if ($transaction->getPayeeUserId()) { $this->payments[$transaction->getPayerUserId()][$transaction->getPayeeUserId()] += $sum; } else { foreach ($this->members as $payeeUserId => $member) { $this->payments[$transaction->getPayerUserId()][$payeeUserId] += $sum / $membersCount; } } } } private function calculateActualDebts(): array { $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]; } } } return $actualDebts; } }