From 6a4f97bc51562cdfd84fc6c842878537faeee7db Mon Sep 17 00:00:00 2001 From: Daniel Subiabre Date: Fri, 25 Oct 2024 12:28:01 +0200 Subject: [PATCH] Pass WalletGatewayServiceTest --- .../Economy/Payment/WalletGatewayService.php | 99 ++++++++++++++++--- 1 file changed, 85 insertions(+), 14 deletions(-) diff --git a/src/Library/Economy/Payment/WalletGatewayService.php b/src/Library/Economy/Payment/WalletGatewayService.php index 63fa5a8..398af09 100644 --- a/src/Library/Economy/Payment/WalletGatewayService.php +++ b/src/Library/Economy/Payment/WalletGatewayService.php @@ -3,42 +3,113 @@ namespace App\Library\Economy\Payment; use App\Entity\Accounting; +use App\Entity\AccountingTransaction; use App\Entity\Money; +use App\Entity\WalletStatement; use App\Entity\WalletStatementDirection; +use App\Library\Economy\MoneyService; use App\Repository\WalletStatementRepository; use Brick\Money as Brick; +use Doctrine\ORM\EntityManagerInterface; class WalletGatewayService { public function __construct( + private MoneyService $money, private WalletStatementRepository $walletStatementRepository, + private EntityManagerInterface $entityManager, ) {} - public function getAccountingBalance(Accounting $accounting): Money + /** + * @return \App\Entity\WalletStatement[] + */ + public function getStatements(Accounting $accounting): array { - $available = Brick\Money::ofMinor(0, $accounting->getCurrency()); - $statements = $this->walletStatementRepository->findByAccounting($accounting); + return $this->walletStatementRepository->findByAccounting($accounting); + } + + public function getBalance(Accounting $accounting): Money + { + $total = Brick\Money::ofMinor(0, $accounting->getCurrency()); + $statements = $this->getStatements($accounting); foreach ($statements as $statement) { - $transaction = $statement->getTransaction(); - $money = Brick\Money::ofMinor( - $transaction->getMoney()->amount, - $transaction->getMoney()->currency - ); + $transacted = $this->money->toBrick($statement->getTransaction()->getMoney()); switch ($statement->getDirection()) { case WalletStatementDirection::Incoming: - $available = $available->plus($money); + $total = $total->plus($transacted); break; case WalletStatementDirection::Outgoing: - $available = $available->minus($money); + $total = $total->minus($transacted); break; } } - return new Money( - $available->getMinorAmount()->toInt(), - $available->getCurrency()->getCurrencyCode() - ); + return $this->money->toMoney($total); + } + + /** + * Puts the money of a Transaction into the target wallet. + * + * @param AccountingTransaction $transaction The Transaction targetting a wallet + * @return \App\Entity\WalletStatement An incoming statement for the target wallet + */ + public function save(AccountingTransaction $transaction): WalletStatement + { + $statement = new WalletStatement(); + $statement->setTransaction($transaction); + $statement->setDirection(WalletStatementDirection::Incoming); + $statement->setBalance($transaction->getMoney()); + + $this->entityManager->persist($statement); + $this->entityManager->flush(); + + return $statement; + } + + /** + * Takes the money of a Transaction from the origin wallet. + * + * @param AccountingTransaction $transaction The Transaction originating from a wallet + * @return \App\Entity\WalletStatement An outgoing statement financed by previous incoming statements + */ + public function spend(AccountingTransaction $transaction): WalletStatement + { + $origin = $transaction->getOrigin(); + $toSpend = $transaction->getMoney(); + + $outgoing = new WalletStatement(); + $outgoing->setTransaction($transaction); + $outgoing->setDirection(WalletStatementDirection::Outgoing); + + $incomings = $this->getStatements($origin); + foreach ($incomings as $incoming) { + $spent = new Money(0, $toSpend->currency); + $balance = $incoming->getBalance(); + + if ($balance->amount === 0) { + continue; + } + + if ($this->money->isMoreOrSame($balance, $spent)) { + $spent = $toSpend; + } else { + $spent = $this->money->add($balance, $spent); + } + + $balance = $this->money->substract($spent, $balance); + + $incoming->setBalance($balance); + + $outgoing->setBalance($spent); + $outgoing->addFinancedBy($incoming); + + $this->entityManager->persist($incoming); + $this->entityManager->persist($outgoing); + $this->entityManager->flush(); + + return $outgoing; + } } }