diff --git a/src/Finance/BalanceCalculator.php b/src/Finance/BalanceCalculator.php new file mode 100644 index 0000000..6842b0f --- /dev/null +++ b/src/Finance/BalanceCalculator.php @@ -0,0 +1,90 @@ +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; + } +}