diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 7e05d60..e2bd483 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -50,5 +50,6 @@ jobs: with: folder: php project: ${{ github.event.repository.name }} - secrets: inherit + secrets: + DOC_TOKEN: ${{ secrets.DOC_TOKEN }} diff --git a/README.md b/README.md index 5f5d281..95c0ea6 100644 --- a/README.md +++ b/README.md @@ -61,10 +61,10 @@ $statementBLL->withdrawFunds($statement); // Add 50 USD hold to the account $statement = new StatementDTO($accountId, 50); -$statementId = $statementBLL->reserveFundsForDeposit($statement); +$reserve = $statementBLL->reserveFundsForDeposit($statement); // Accept the hold -$statementBLL->acceptFundsById($statementId); +$statementBLL->acceptFundsById($reserve->getStatementId()); ``` ## Installation diff --git a/composer.phar b/composer.phar deleted file mode 100644 index bb6ba64..0000000 Binary files a/composer.phar and /dev/null differ diff --git a/db/migrations/down/00002-delete-laststatementid.sql b/db/migrations/down/00002-delete-laststatementid.sql new file mode 100644 index 0000000..cd9317c --- /dev/null +++ b/db/migrations/down/00002-delete-laststatementid.sql @@ -0,0 +1,2 @@ +alter table account + drop column laststatementid; diff --git a/db/migrations/down/00003-delete-constraint.sql b/db/migrations/down/00003-delete-constraint.sql new file mode 100644 index 0000000..1409149 --- /dev/null +++ b/db/migrations/down/00003-delete-constraint.sql @@ -0,0 +1,5 @@ +ALTER TABLE statement + DROP CONSTRAINT statement_chk_value_nonnegative; + +ALTER TABLE account + DROP CONSTRAINT account_chk_value_nonnegative; \ No newline at end of file diff --git a/db/migrations/up/00003-add-laststatementid.sql b/db/migrations/up/00003-add-laststatementid.sql new file mode 100644 index 0000000..a2b585c --- /dev/null +++ b/db/migrations/up/00003-add-laststatementid.sql @@ -0,0 +1,3 @@ +alter table account + add laststatementid int null; + diff --git a/db/migrations/up/00004-add-constraint.sql b/db/migrations/up/00004-add-constraint.sql new file mode 100644 index 0000000..41e39d1 --- /dev/null +++ b/db/migrations/up/00004-add-constraint.sql @@ -0,0 +1,8 @@ +ALTER TABLE statement + ADD CONSTRAINT statement_chk_value_nonnegative + CHECK (netbalance >= 0); + +ALTER TABLE account + ADD CONSTRAINT account_chk_value_nonnegative + CHECK (netbalance >= 0); + diff --git a/phpunit.xml.dist b/phpunit.xml.dist index a5ebdfc..93529d8 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -4,34 +4,21 @@ To change this license header, choose License Headers in Project Properties. To change this template file, choose Tools | Templates and open the template in the editor. --> - - - - - - - - - - - - - ./src - - - - - - ./tests/ - - - - \ No newline at end of file + + + + ./src + + + + + + + + + + ./tests/ + + + diff --git a/src/Bll/AccountBLL.php b/src/Bll/AccountBLL.php index a5ae1da..c1d3942 100644 --- a/src/Bll/AccountBLL.php +++ b/src/Bll/AccountBLL.php @@ -254,30 +254,26 @@ public function closeAccount(int $accountId): ?int * @param int $accountId * @param float $balance * @param string $description - * @return int|null + * @return StatementEntity * @throws AccountException * @throws AmountException * @throws InvalidArgumentException - * @throws OrmBeforeInvalidException - * @throws OrmInvalidFieldsException - * @throws RepositoryReadOnlyException * @throws StatementException - * @throws UpdateConstraintException * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException */ - public function partialBalance(int $accountId, float $balance, string $description = "Partial Balance"): ?int + public function partialBalance(int $accountId, float $balance, string $description = "Partial Balance"): StatementEntity { $account = $this->getById($accountId); $amount = $balance - $account->getNetBalance(); if ($amount >= 0) { - $statementId = $this->statementBLL->addFunds(StatementDTO::create($accountId, $amount)->setDescription($description)); + $statement = $this->statementBLL->addFunds(StatementDTO::create($accountId, $amount)->setDescription($description)); } else { - $statementId = $this->statementBLL->withdrawFunds(StatementDTO::create($accountId, abs($amount))->setDescription($description)); + $statement = $this->statementBLL->withdrawFunds(StatementDTO::create($accountId, abs($amount))->setDescription($description)); } - return $statementId; + return $statement; } /** @@ -288,11 +284,7 @@ public function partialBalance(int $accountId, float $balance, string $descripti * @throws AccountException * @throws AmountException * @throws InvalidArgumentException - * @throws OrmBeforeInvalidException - * @throws OrmInvalidFieldsException - * @throws RepositoryReadOnlyException * @throws StatementException - * @throws UpdateConstraintException * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException */ public function transferFunds(int $accountSource, int $accountTarget, float $amount): array @@ -315,10 +307,10 @@ public function transferFunds(int $accountSource, int $accountTarget, float $amo $statementTargetDTO->setReferenceId($refSource); $statementTargetDTO->setDescription('Transfer from account id ' . $accountSource); - $statementSourceId = $this->statementBLL->withdrawFunds($statementSourceDTO); - $statementTargetId = $this->statementBLL->addFunds($statementTargetDTO); + $statementSource = $this->statementBLL->withdrawFunds($statementSourceDTO); + $statementTarget = $this->statementBLL->addFunds($statementTargetDTO); - return [ $statementSourceId, $statementTargetId ]; + return [ $statementSource, $statementTarget ]; } public function getRepository(): AccountRepository diff --git a/src/Bll/AccountTypeBLL.php b/src/Bll/AccountTypeBLL.php index c4afd08..c6d2aa9 100644 --- a/src/Bll/AccountTypeBLL.php +++ b/src/Bll/AccountTypeBLL.php @@ -31,10 +31,10 @@ public function __construct(AccountTypeRepository $accountTypeRepository) * Se o ID não for passado, então devolve todos os AccountTypes. * * @param string $accountTypeId Opcional. Se não for passado obtém todos - * @return AccountTypeEntity|AccountTypeEntity[] + * @return AccountTypeEntity|AccountTypeEntity[]|null * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException */ - public function getById(string $accountTypeId): array|AccountTypeEntity + public function getById(string $accountTypeId): array|AccountTypeEntity|null { return $this->accountTypeRepository->getById($accountTypeId); } diff --git a/src/Bll/StatementBLL.php b/src/Bll/StatementBLL.php index 3b7d161..02846dc 100644 --- a/src/Bll/StatementBLL.php +++ b/src/Bll/StatementBLL.php @@ -3,7 +3,6 @@ namespace ByJG\AccountStatements\Bll; use ByJG\AccountStatements\DTO\StatementDTO; -use ByJG\AccountStatements\Entity\AccountEntity; use ByJG\AccountStatements\Entity\StatementEntity; use ByJG\AccountStatements\Exception\AccountException; use ByJG\AccountStatements\Exception\AmountException; @@ -15,9 +14,12 @@ use ByJG\MicroOrm\Exception\OrmInvalidFieldsException; use ByJG\MicroOrm\Exception\RepositoryReadOnlyException; use ByJG\MicroOrm\Exception\UpdateConstraintException; +use ByJG\MicroOrm\InsertSelectQuery; +use ByJG\MicroOrm\ORMSubject; +use ByJG\MicroOrm\Query; +use ByJG\MicroOrm\UpdateQuery; use ByJG\Serializer\Exception\InvalidArgumentException; use Exception; -use KingPandaApi\Model\StatementCodes; class StatementBLL { @@ -54,233 +56,331 @@ public function getById(int|string $statementId): mixed return $this->statementRepository->getById($statementId); } + protected function validateStatementDto(StatementDTO $dto): void + { + if (!$dto->hasAccount()) { + throw new StatementException('Account is required'); + } + if ($dto->getAmount() < 0) { + throw new AmountException('Amount needs to be greater than zero'); + } + + if (round($dto->getAmount()*100)/100 != $dto->getAmount()) { + throw new AmountException('Amount needs to have two decimal places'); + } + } + /** - * Add funds to an account + * Central method to apply a balance-changing operation. + * - Creates a new statement row reflecting the post-operation balances + * - Updates the account with the same balances and the last statement id * - * @param StatementDTO $dto - * @return int|null Statement ID + * @param string $operation One of StatementEntity::DEPOSIT, WITHDRAW, DEPOSIT_BLOCKED, WITHDRAW_BLOCKED + * @param StatementDTO $dto Input data (account, amount, description, etc.) + * @param bool $capAtZero When true and operation is WITHDRAW, caps the withdrawal so net balance never goes below zero + * @return StatementEntity * @throws AccountException * @throws AmountException * @throws InvalidArgumentException - * @throws OrmBeforeInvalidException - * @throws OrmInvalidFieldsException - * @throws RepositoryReadOnlyException * @throws StatementException - * @throws UpdateConstraintException * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException */ - public function addFunds(StatementDTO $dto): ?int + protected function updateFunds(string $operation, StatementDTO $dto, bool $capAtZero = false): StatementEntity { - // Validations $this->validateStatementDto($dto); - // Get an Account - $this->getRepository()->getDbDriver()->beginTransaction(IsolationLevelEnum::SERIALIZABLE, true); - try { - $account = $this->accountRepository->getById($dto->getAccountId()); - if (is_null($account) || $account->getAccountId() == "") { - throw new AccountException("addFunds: Account " . $dto->getAccountId() . " not found"); - } + // 1) Compute numeric deltas for balances (used for notifications) and the SQL expressions (used for insert/select) + [$grossDelta, $unclearedDelta, $netDelta] = $this->computeBalanceDeltas($operation, $dto->getAmount()); + [$exprAmount, $exprGross, $exprNet] = $this->buildAmountAndExpressions($operation, $dto->getAmount(), $capAtZero); - $result = $this->updateFunds(StatementEntity::DEPOSIT, $account, $dto); + // 2) Build the insert-select for the statement and the account update based on the new statement + $statementInsert = $this->getInsertStatementQuery( + $operation, + $dto, + $exprGross, + $exprNet, + $exprAmount, + (string)$unclearedDelta + ); - $this->getRepository()->getDbDriver()->commitTransaction(); + $accountUpdate = $this->getAccountUpdateQuery($dto); - return $result->getStatementId(); - } catch (Exception $ex) { - $this->getRepository()->getDbDriver()->rollbackTransaction(); + // 3) Execute both queries atomically + try { + $this->getRepository()->bulkExecute([ + $statementInsert, + $accountUpdate, + ])->toArray(); + + // 4) Notify observers of account change, providing an oldAccount with pre-change balances + $account = $this->accountRepository->getById($dto->getAccountId()); + if (empty($account)) { + throw new AccountException('Account not found'); + } + $oldAccount = clone $account; + $oldAccount->setGrossbalance($oldAccount->getGrossbalance() - $grossDelta); + $oldAccount->setUncleared($oldAccount->getUncleared() - $unclearedDelta); + $oldAccount->setNetbalance($oldAccount->getNetbalance() - $netDelta); + + ORMSubject::getInstance()->notify( + $this->accountRepository->getMapper()->getTable(), + ORMSubject::EVENT_UPDATE, + $account, + $oldAccount + ); + + // 5) Load the statement just created to notify and return + $statement = $this->statementRepository->getById($account->getLastStatementId()); + + ORMSubject::getInstance()->notify( + $this->statementRepository->getMapper()->getTable(), + ORMSubject::EVENT_INSERT, + $statement, + null + ); + + // If capping occurred on withdraw, the actual amount may differ from the DTO amount + $dto->setAmount($statement->getAmount()); + + return $statement; + } catch (\PDOException $ex) { + if (strpos($ex->getMessage(), 'chk_value_nonnegative') !== false) { + throw new AmountException('Cannot withdraw above the account balance'); + } throw $ex; } } - protected function validateStatementDto(StatementDTO $dto): void - { - if (!$dto->hasAccount()) { - throw new StatementException('Account is required'); - } - if ($dto->getAmount() < 0) { - throw new AmountException('Amount needs to be greater than zero'); - } - - if (round($dto->getAmount()*100)/100 != $dto->getAmount()) { - throw new AmountException('Amount needs to have two decimal places'); - } - } + // ---- Helpers: computations and query building --------------------------------------------------------------- /** - * @throws RepositoryReadOnlyException - * @throws InvalidArgumentException - * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException - * @throws OrmInvalidFieldsException - * @throws UpdateConstraintException - * @throws OrmBeforeInvalidException + * Compute numeric deltas for balances according to the operation and amount. + * Returns [grossDelta, unclearedDelta, netDelta]. */ - protected function updateFunds(string $operation, AccountEntity $account, StatementDTO $dto): StatementEntity + private function computeBalanceDeltas(string $operation, float $amount): array { - $sumGrossBalance = $dto->getAmount() * match($operation) { + $grossDelta = $amount * match ($operation) { StatementEntity::DEPOSIT => 1, StatementEntity::WITHDRAW => -1, default => 0, }; - $sumUnCleared = $dto->getAmount() * match($operation) { + + $unclearedDelta = $amount * match ($operation) { StatementEntity::DEPOSIT_BLOCKED => -1, StatementEntity::WITHDRAW_BLOCKED => 1, default => 0, }; - $sumNetBalance = $dto->getAmount() * match($operation) { + + $netDelta = $amount * match ($operation) { StatementEntity::DEPOSIT, StatementEntity::DEPOSIT_BLOCKED => 1, StatementEntity::WITHDRAW, StatementEntity::WITHDRAW_BLOCKED => -1, default => 0, }; - // Update Values in an account - $account->setGrossBalance($account->getGrossBalance() + $sumGrossBalance); - $account->setUncleared($account->getUncleared() + $sumUnCleared); - $account->setNetBalance($account->getNetBalance() + $sumNetBalance); - $this->accountRepository->save($account); - - // Add the new line - /** @var StatementEntity $statement */ - $statement = $this->statementRepository->getRepository()->entity([]); - $dto->setToStatement($statement); - $statement->setTypeId($operation); - $statement->attachAccount($account); - - // Save to DB - return $this->statementRepository->save($statement); + return [$grossDelta, $unclearedDelta, $netDelta]; } /** - * Withdraw funds from an account - * - * @param StatementDTO $dto - * @param bool $allowZeroNoBalance - * @return int|null Statement ID - * @throws AccountException - * @throws AmountException - * @throws InvalidArgumentException - * @throws OrmBeforeInvalidException - * @throws OrmInvalidFieldsException - * @throws RepositoryReadOnlyException - * @throws StatementException - * @throws UpdateConstraintException - * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException + * Build SQL literal expressions for amount, gross and net balances. + * When capping at zero (withdraw), it ensures the amount is reduced to avoid negative net balance. + * Returns [exprAmount, exprGross, exprNet]. */ - public function withdrawFunds(StatementDTO $dto, bool $allowZeroNoBalance = false): ?int + private function buildAmountAndExpressions(string $operation, float $amount, bool $capAtZero): array { - // Validations - $this->validateStatementDto($dto); + $exprGross = "grossbalance + " . ($amount * match ($operation) { + StatementEntity::DEPOSIT => 1, + StatementEntity::WITHDRAW => -1, + default => 0, + }); + $exprNet = "netbalance + " . ($amount * match ($operation) { + StatementEntity::DEPOSIT, StatementEntity::DEPOSIT_BLOCKED => 1, + StatementEntity::WITHDRAW, StatementEntity::WITHDRAW_BLOCKED => -1, + default => 0, + }); + $exprAmount = (string)$amount; + + if ($capAtZero && $operation === StatementEntity::WITHDRAW) { + // Cap withdraw so netbalance never goes below zero + $exprAmount = "case when netbalance - {$amount} < 0 then {$amount} + (netbalance - {$amount}) else {$amount} end"; + $exprGross = "grossbalance - $exprAmount"; + $exprNet = "netbalance - $exprAmount"; + } - $this->getRepository()->getDbDriver()->beginTransaction(IsolationLevelEnum::SERIALIZABLE, true); - try { - $account = $this->accountRepository->getById($dto->getAccountId()); - if (is_null($account)) { - throw new AccountException('addFunds: Account not found'); - } + return [$exprAmount, $exprGross, $exprNet]; + } - // Cannot withdraw above the account balance. - $newBalance = $account->getNetBalance() - $dto->getAmount(); - if ($newBalance < $account->getMinValue()) { - if (!$allowZeroNoBalance) { - throw new AmountException('Cannot withdraw above the account balance.'); + /** + * Append extra mapped fields from the DTO properties (extended entities) into the target/select lists. + */ + private function appendExtraMappedFields(StatementDTO $dto, array &$targetColumns, array &$selectFields): void + { + $mapper = $this->statementRepository->getMapper(); + foreach ($dto->getProperties() as $propertyName => $propertyValue) { + $fieldMap = $mapper->getFieldMap($propertyName); + if ($fieldMap && $fieldMap->isSyncWithDb()) { + $fieldName = $fieldMap->getFieldName(); + if (!in_array($fieldName, $targetColumns, true)) { + $targetColumns[] = $fieldName; + $selectFields[] = !is_null($propertyValue) ? "'" . $propertyValue . "'" : 'null'; } - $dto->setAmount($account->getNetBalance() - $account->getMinValue()); } + } + } - $result = $this->updateFunds(StatementEntity::WITHDRAW, $account, $dto); - - $this->getRepository()->getDbDriver()->commitTransaction(); + /** + * Subquery selecting the last inserted statement to update account fields with. + */ + private function buildLastInsertedStatementSnapshotQuery(): Query + { + return Query::getInstance() + ->table($this->statementRepository->getMapper()->getTable()) + ->fields(['statementid', 'accountid', 'grossbalance', 'netbalance', 'uncleared']) + ->where('statementid = (' . $this->statementRepository->getDbDriver()->getDbHelper()->getSqlLastInsertId() . ')'); + } - return $result->getStatementId(); - } catch (Exception $ex) { - $this->getRepository()->getDbDriver()->rollbackTransaction(); + protected function getInsertStatementQuery( + string $operation, + StatementDTO $dto, + string $expressionSumGrossBalance, + string $expressionSumNetBalance, + string $expressionAmount, + string $sumUnCleared + ): InsertSelectQuery + { + // Build base target columns and select fields + $targetColumns = [ + 'accountid', + 'accounttypeid', + 'grossbalance', + 'netbalance', + 'uncleared', + 'price', + 'amount', + 'description', + 'code', + 'referenceid', + 'referencesource', + 'typeid', + 'date', + 'statementparentid', + ]; + + $selectFields = [ + 'accountid', + 'accounttypeid', + $expressionSumGrossBalance, + $expressionSumNetBalance, + "uncleared + $sumUnCleared", + 'price', + $expressionAmount, + ':description', + ':code', + ':referenceid', + ':referencesource', + ':operation', + $this->statementRepository->getDbDriver()->getDbHelper()->sqlDate('Y-m-d H:i:s'), + 'null', + ]; + + // Append any extra mapped fields provided via DTO properties (for extended entities) + $this->appendExtraMappedFields($dto, $targetColumns, $selectFields); + + $statementQuery = Query::getInstance() + ->table('account') + ->fields($selectFields) + ->where('accountid = :accid2', [ + 'accid2' => $dto->getAccountId(), + 'description' => $dto->getDescription(), + 'code' => $dto->getCode(), + 'referenceid' => $dto->getReferenceId(), + 'referencesource' => $dto->getReferenceSource(), + 'operation' => $operation, + ]); + + return InsertSelectQuery::getInstance( + $this->statementRepository->getMapper()->getTable(), + $targetColumns + )->fromQuery($statementQuery); + } - throw $ex; - } + public function getAccountUpdateQuery(StatementDTO $dto): UpdateQuery + { + $statementSnapshot = $this->buildLastInsertedStatementSnapshotQuery(); + + return UpdateQuery::getInstance() + ->table('account') + ->setLiteral('account.grossbalance', 'st.grossbalance') + ->setLiteral('account.uncleared', 'st.uncleared') + ->setLiteral('account.netbalance', 'st.netbalance') + ->setLiteral('account.laststatementid', 'st.statementid') + ->where('account.accountid = :accid', ['accid' => $dto->getAccountId()]) + ->join($statementSnapshot, 'st.accountid = account.accountid', 'st'); } /** - * Reserve funds to future withdrawn. It affects the net balance but not the gross balance + * Add funds to an account * * @param StatementDTO $dto - * @return int|null Statement ID + * @return StatementEntity Newly created statement entity * @throws AccountException * @throws AmountException * @throws InvalidArgumentException - * @throws OrmBeforeInvalidException - * @throws OrmInvalidFieldsException - * @throws RepositoryReadOnlyException * @throws StatementException - * @throws UpdateConstraintException * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException */ - public function reserveFundsForWithdraw(StatementDTO $dto): ?int + public function addFunds(StatementDTO $dto): StatementEntity { - // Validations - $this->validateStatementDto($dto); - - $this->getRepository()->getDbDriver()->beginTransaction(IsolationLevelEnum::SERIALIZABLE, true); - try { - $account = $this->accountRepository->getById($dto->getAccountId()); - if (is_null($account)) { - throw new AccountException('reserveFundsForWithdraw: Account not found'); - } - - // Cannot withdraw above the account balance. - if ($account->getNetBalance() - $dto->getAmount() < $account->getMinValue()) { - throw new AmountException('Cannot withdraw above the account balance.'); - } - - $result = $this->updateFunds(StatementEntity::WITHDRAW_BLOCKED, $account, $dto); - - $this->getRepository()->getDbDriver()->commitTransaction(); + return $this->updateFunds(StatementEntity::DEPOSIT, $dto); + } - return $result->getStatementId(); - } catch (Exception $ex) { - $this->getRepository()->getDbDriver()->rollbackTransaction(); + /** + * Withdraw funds from an account + * + * @param StatementDTO $dto + * @param bool $capAtZero + * @return StatementEntity Statement ID + * @throws AccountException + * @throws AmountException + * @throws InvalidArgumentException + * @throws StatementException + * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException + */ + public function withdrawFunds(StatementDTO $dto, bool $capAtZero = false): StatementEntity + { + return $this->updateFunds(StatementEntity::WITHDRAW, $dto, $capAtZero); + } - throw $ex; - } + /** + * Reserve funds to future withdrawn. It affects the net balance but not the gross balance + * + * @param StatementDTO $dto + * @return StatementEntity Statement ID + * @throws AccountException + * @throws AmountException + * @throws InvalidArgumentException + * @throws StatementException + * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException + */ + public function reserveFundsForWithdraw(StatementDTO $dto): StatementEntity + { + return $this->updateFunds(StatementEntity::WITHDRAW_BLOCKED, $dto); } /** * Reserve funds to future deposit. Update net balance but not gross balance. * * @param StatementDTO $dto - * @return int|null Statement ID + * @return StatementEntity Statement ID * @throws AccountException * @throws AmountException * @throws InvalidArgumentException - * @throws OrmBeforeInvalidException - * @throws OrmInvalidFieldsException - * @throws RepositoryReadOnlyException * @throws StatementException - * @throws UpdateConstraintException * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException */ - public function reserveFundsForDeposit(StatementDTO $dto): ?int + public function reserveFundsForDeposit(StatementDTO $dto): StatementEntity { - // Validações - $this->validateStatementDto($dto); - - $this->getRepository()->getDbDriver()->beginTransaction(IsolationLevelEnum::SERIALIZABLE, true); - try { - $account = $this->accountRepository->getById($dto->getAccountId()); - if (is_null($account)) { - throw new AccountException('reserveFundsForDeposit: Account not found'); - } - - $result = $this->updateFunds(StatementEntity::DEPOSIT_BLOCKED, $account, $dto); - - $this->getRepository()->getDbDriver()->commitTransaction(); - - return $result->getStatementId(); - } catch (Exception $ex) { - $this->getRepository()->getDbDriver()->rollbackTransaction(); - - throw $ex; - } + return $this->updateFunds(StatementEntity::DEPOSIT_BLOCKED, $dto); } /** @@ -356,7 +456,7 @@ public function acceptFundsById(int $statementId, ?StatementDTO $statementDto = * @param int $statementId * @param StatementDTO $statementDtoWithdraw * @param StatementDTO $statementDtoRefund - * @return int|null + * @return StatementEntity * @throws AccountException * @throws AmountException * @throws InvalidArgumentException @@ -367,7 +467,7 @@ public function acceptFundsById(int $statementId, ?StatementDTO $statementDto = * @throws UpdateConstraintException * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException */ - public function acceptPartialFundsById(int $statementId, StatementDTO $statementDtoWithdraw, StatementDTO $statementDtoRefund): ?int + public function acceptPartialFundsById(int $statementId, StatementDTO $statementDtoWithdraw, StatementDTO $statementDtoRefund): StatementEntity { $partialAmount = $statementDtoWithdraw->getAmount(); @@ -399,11 +499,11 @@ public function acceptPartialFundsById(int $statementId, StatementDTO $statement $statementDtoWithdraw->setAccountId($statement->getAccountId()); - $finalDebitStatementId = $this->withdrawFunds($statementDtoWithdraw); + $finalDebitStatement = $this->withdrawFunds($statementDtoWithdraw); $this->getRepository()->getDbDriver()->commitTransaction(); - return $finalDebitStatementId; + return $finalDebitStatement; } catch (Exception $ex) { $this->getRepository()->getDbDriver()->rollbackTransaction(); diff --git a/src/DTO/StatementDTO.php b/src/DTO/StatementDTO.php index 3ce897e..e5b9ace 100644 --- a/src/DTO/StatementDTO.php +++ b/src/DTO/StatementDTO.php @@ -137,40 +137,40 @@ public function setAmount(float $amount): static } /** - * @param string $description + * @param string|null $description * @return $this */ - public function setDescription(string $description): static + public function setDescription(?string $description): static { $this->description = $description; return $this; } /** - * @param string $referenceId + * @param string|null $referenceId * @return $this */ - public function setReferenceId(string $referenceId): static + public function setReferenceId(?string $referenceId): static { $this->referenceId = $referenceId; return $this; } /** - * @param string $referenceSource + * @param string|null $referenceSource * @return $this */ - public function setReferenceSource(string $referenceSource): static + public function setReferenceSource(?string $referenceSource): static { $this->referenceSource = $referenceSource; return $this; } /** - * @param string $code + * @param string|null $code * @return $this */ - public function setCode(string $code): static + public function setCode(?string $code): static { $this->code = $code; return $this; @@ -186,5 +186,4 @@ public function getProperties(): array { return $this->properties; } - } \ No newline at end of file diff --git a/src/Entity/AccountEntity.php b/src/Entity/AccountEntity.php index c977df0..0e5135b 100644 --- a/src/Entity/AccountEntity.php +++ b/src/Entity/AccountEntity.php @@ -73,6 +73,8 @@ class AccountEntity extends BaseModel #[FieldAttribute(syncWithDb: false)] protected ?string $entrydate = null; + protected ?int $laststatementid = null; + /** * @var float|null * @OA\Property() @@ -179,6 +181,16 @@ public function setMinValue(?float $minvalue): void $this->minvalue = $minvalue; } + public function getLastStatementId(): ?int + { + return $this->laststatementid; + } + + public function setLastStatementId(?int $laststatementid): void + { + $this->laststatementid = $laststatementid; + } + /** * * @throws AmountException diff --git a/src/Repository/BaseRepository.php b/src/Repository/BaseRepository.php index 3c0b45f..edfa903 100644 --- a/src/Repository/BaseRepository.php +++ b/src/Repository/BaseRepository.php @@ -2,8 +2,10 @@ namespace ByJG\AccountStatements\Repository; +use ByJG\AnyDataset\Core\GenericIterator; use ByJG\AnyDataset\Core\IteratorFilter; use ByJG\AnyDataset\Db\DbDriverInterface; +use ByJG\AnyDataset\Db\IsolationLevelEnum; use ByJG\MicroOrm\Exception\OrmBeforeInvalidException; use ByJG\MicroOrm\Exception\OrmInvalidFieldsException; use ByJG\MicroOrm\Exception\RepositoryReadOnlyException; @@ -89,6 +91,11 @@ public function save($model): mixed return $this->repository->save($model); } + public function bulkExecute(array $queries): ?GenericIterator + { + return $this->repository->bulkExecute($queries, IsolationLevelEnum::SERIALIZABLE); + } + public function getDbDriver(): DbDriverInterface { return $this->repository->getDbDriver(); diff --git a/tests/BaseDALTrait.php b/tests/BaseDALTrait.php index dd1b34e..117b952 100644 --- a/tests/BaseDALTrait.php +++ b/tests/BaseDALTrait.php @@ -11,6 +11,7 @@ use ByJG\AccountStatements\Exception\AccountException; use ByJG\AccountStatements\Exception\AccountTypeException; use ByJG\AccountStatements\Exception\AmountException; +use ByJG\AccountStatements\Exception\StatementException; use ByJG\AccountStatements\Repository\AccountRepository; use ByJG\AccountStatements\Repository\AccountTypeRepository; use ByJG\AccountStatements\Repository\StatementRepository; @@ -21,7 +22,8 @@ use ByJG\MicroOrm\Exception\OrmBeforeInvalidException; use ByJG\MicroOrm\Exception\OrmInvalidFieldsException; use ByJG\MicroOrm\Exception\OrmModelInvalidException; -use ByJG\MicroOrm\Exception\TransactionException; +use ByJG\MicroOrm\Exception\RepositoryReadOnlyException; +use ByJG\MicroOrm\Exception\UpdateConstraintException; use ByJG\Util\Uri; use ReflectionException; @@ -77,7 +79,13 @@ public function dbSetUp() $migration = new Migration($this->uri, __DIR__ . "/../db"); $migration->prepareEnvironment(); - $migration->reset(); + // This will delete the constraint to validate the negative amount + $maxVersion = null; + /** @psalm-suppress InternalMethod */ + if (strpos($this->getName(), "Allow_Negativ") !== false) { + $maxVersion = 3; + } + $migration->reset($maxVersion); $migration->getDbDriver()->execute("CREATE TABLE statement_extended LIKE statement"); $migration->getDbDriver()->execute("alter table statement_extended add extra_property varchar(100) null;"); @@ -109,7 +117,9 @@ protected function dbClear(): void * @throws InvalidArgumentException * @throws OrmBeforeInvalidException * @throws OrmInvalidFieldsException - * @throws TransactionException + * @throws StatementException + * @throws RepositoryReadOnlyException + * @throws UpdateConstraintException * @throws \ByJG\Serializer\Exception\InvalidArgumentException */ protected function createDummyData() @@ -126,9 +136,14 @@ protected function createDummyData() $dto3->setAccountTypeId('ABCTEST'); $dto3->setName('Test 3'); + $dto4 = new AccountTypeEntity(); + $dto4->setAccountTypeId('NEGTEST'); + $dto4->setName('Test 4'); + $this->accountTypeBLL->update($dto1); $this->accountTypeBLL->update($dto2); $this->accountTypeBLL->update($dto3); + $this->accountTypeBLL->update($dto4); $this->accountBLL->createAccount('BRLTEST', '___TESTUSER-1', 1000, 1); } diff --git a/tests/Classes/AccountRepositoryExtended.php b/tests/Classes/AccountRepositoryExtended.php new file mode 100644 index 0000000..a5ce626 --- /dev/null +++ b/tests/Classes/AccountRepositoryExtended.php @@ -0,0 +1,42 @@ +getRepository()->addObserver(new ObserverAccount($this)); + } + + public function getReach(): bool + { + return $this->reach; + } + + public function setReach(bool $reach): void + { + $this->reach = $reach; + } +} \ No newline at end of file diff --git a/tests/Classes/ObserverAccount.php b/tests/Classes/ObserverAccount.php new file mode 100644 index 0000000..bc5a4d2 --- /dev/null +++ b/tests/Classes/ObserverAccount.php @@ -0,0 +1,31 @@ +repository->setReach($observerData->getEvent() == 'update' && $observerData->getData()->getNetbalance() == 1250); + } + + public function getObservedTable(): string + { + return "account"; + } + + public function onError(Throwable $exception, ObserverData $observerData): void + { + throw $exception; + } +} \ No newline at end of file diff --git a/tests/Classes/ObserverStatement.php b/tests/Classes/ObserverStatement.php new file mode 100644 index 0000000..9238af9 --- /dev/null +++ b/tests/Classes/ObserverStatement.php @@ -0,0 +1,31 @@ +repository->setReach($observerData->getData()->getStatementId() == 3 && $observerData->getData()->getAmount() == 250); + } + + public function getObservedTable(): string + { + return "statement"; + } + + public function onError(Throwable $exception, ObserverData $observerData): void + { + throw $exception; + } +} \ No newline at end of file diff --git a/tests/Classes/StatementRepositoryExtended.php b/tests/Classes/StatementRepositoryExtended.php new file mode 100644 index 0000000..64cfe75 --- /dev/null +++ b/tests/Classes/StatementRepositoryExtended.php @@ -0,0 +1,27 @@ +getRepository()->addObserver(new ObserverStatement($this)); + } + + public function getReach(): bool + { + return $this->reach; + } + + public function setReach(bool $reach): void + { + $this->reach = $reach; + } +} \ No newline at end of file diff --git a/tests/Database/AccountStatementsTest.php b/tests/Database/AccountStatementsTest.php index a882930..af1c8dd 100644 --- a/tests/Database/AccountStatementsTest.php +++ b/tests/Database/AccountStatementsTest.php @@ -3,19 +3,23 @@ namespace Tests\Database; use ByJG\AccountStatements\DTO\StatementDTO; +use ByJG\AccountStatements\Entity\AccountEntity; use ByJG\AccountStatements\Entity\StatementEntity; use ByJG\AccountStatements\Exception\AccountException; use ByJG\AccountStatements\Exception\AccountTypeException; use ByJG\AccountStatements\Exception\AmountException; use ByJG\AnyDataset\Db\Exception\TransactionStartedException; use ByJG\AnyDataset\Db\IsolationLevelEnum; +use ByJG\MicroOrm\Exception\InvalidArgumentException; use ByJG\MicroOrm\Exception\OrmBeforeInvalidException; use ByJG\MicroOrm\Exception\OrmInvalidFieldsException; use ByJG\MicroOrm\Exception\TransactionException; use ByJG\Serializer\Serialize; use PHPUnit\Framework\TestCase; use Tests\BaseDALTrait; +use Tests\Classes\AccountRepositoryExtended; use Tests\Classes\StatementExtended; +use Tests\Classes\StatementRepositoryExtended; class AccountStatementsTest extends TestCase @@ -45,15 +49,14 @@ protected function tearDown(): void /** * @return void - * @throws \ByJG\MicroOrm\Exception\InvalidArgumentException - * @throws \ByJG\Serializer\Exception\InvalidArgumentException + * @throws InvalidArgumentException */ public function testGetAccountType() { $accountTypeRepo = $this->accountTypeBLL->getRepository(); - $list = $accountTypeRepo->getAll(null, null, null, [["accounttypeid like '___TEST'", []]]); + $list = $accountTypeRepo->getAll(null, null, null, [["accounttypeid like '___TEST'", []]]); - $this->assertEquals(3, count($list)); + $this->assertEquals(4, count($list)); $this->assertEquals( [ @@ -65,6 +68,10 @@ public function testGetAccountType() 'accounttypeid' => 'BRLTEST', 'name' => 'Test 2' ], + [ + 'accounttypeid' => 'NEGTEST', + 'name' => 'Test 4' + ], [ 'accounttypeid' => 'USDTEST', 'name' => 'Test 1' @@ -82,13 +89,13 @@ public function testGetById() { // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->withdrawFunds( + $actual = $this->statementBLL->withdrawFunds( StatementDTO::create($accountId, 10) - ->setDescription( 'Test') + ->setDescription('Test') ->setReferenceId('Referencia') ->setReferenceSource('Source') ->setCode('XYZ') - ); + ); // Objeto que é esperado $statement = new StatementEntity(); @@ -97,7 +104,7 @@ public function testGetById() $statement->setDescription('Test'); $statement->setGrossBalance('990.00'); $statement->setAccountId($accountId); - $statement->setStatementId($statementId); + $statement->setStatementId($actual->getStatementId()); $statement->setTypeId('W'); $statement->setNetBalance('990.00'); $statement->setPrice('1.00'); @@ -106,8 +113,6 @@ public function testGetById() $statement->setReferenceSource('Source'); $statement->setCode('XYZ'); $statement->setAccountTypeId('USDTEST'); - - $actual = $this->statementBLL->getById($statementId); $statement->setDate($actual->getDate()); // Executar teste @@ -118,9 +123,9 @@ public function testGetById_Zero() { // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 0); - $statementId = $this->statementBLL->addFunds( + $actual = $this->statementBLL->addFunds( StatementDTO::create($accountId, 10) - ->setDescription( 'Test') + ->setDescription('Test') ->setReferenceId('Referencia') ->setReferenceSource('Source') ->setCode('XYZ') @@ -133,7 +138,7 @@ public function testGetById_Zero() $statement->setDescription('Test'); $statement->setGrossBalance('10.00'); $statement->setAccountId($accountId); - $statement->setStatementId($statementId); + $statement->setStatementId($actual->getStatementId());; $statement->setTypeId('D'); $statement->setNetBalance('10.00'); $statement->setPrice('1.00'); @@ -142,8 +147,6 @@ public function testGetById_Zero() $statement->setReferenceSource('Source'); $statement->setCode('XYZ'); $statement->setAccountTypeId('USDTEST'); - - $actual = $this->statementBLL->getById($statementId); $statement->setDate($actual->getDate()); // Executar teste @@ -160,18 +163,18 @@ public function testGetAll() { // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->withdrawFunds( + $statementResult = $this->statementBLL->withdrawFunds( StatementDTO::create($accountId, 10) - ->setDescription( 'Test') + ->setDescription('Test') ->setReferenceId('Referencia') ->setReferenceSource('Source') - ); + ); $this->statementBLL->withdrawFunds( StatementDTO::create($accountId, 50) ->setDescription('Test') ->setReferenceId('Referencia') ->setReferenceSource('Source') - ); + ); $statement = []; @@ -198,7 +201,7 @@ public function testGetAll() $statement[1]->setDescription('Test'); $statement[1]->setGrossBalance('990.00'); $statement[1]->setAccountId($accountId); - $statement[1]->setStatementId($statementId); + $statement[1]->setStatementId($statementResult->getStatementId()); $statement[1]->setTypeId('W'); $statement[1]->setNetBalance('990.00'); $statement[1]->setPrice('1.00'); @@ -222,10 +225,10 @@ public function testGetAll() $statement[2]->setReferenceSource('Source'); $statement[2]->setAccountTypeId('USDTEST'); - $listAll = $this->statementBLL->getRepository()->getAll(null, null, null, [["accounttypeid = :id",["id" => 'USDTEST']]]); + $listAll = $this->statementBLL->getRepository()->getAll(null, null, null, [["accounttypeid = :id", ["id" => 'USDTEST']]]); /** @psalm-suppress InvalidArrayOffset */ - for ($i=0; $isetDate(null); $statement[$i]->setStatementId(null); $listAll[$i]->setDate(null); @@ -243,12 +246,12 @@ public function testAddFunds() { // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->addFunds( + $actual = $this->statementBLL->addFunds( StatementDTO::create($accountId, 250) ->setDescription('Test Add Funds') ->setReferenceId('Referencia Add Funds') ->setReferenceSource('Source Add Funds') - ); + ); // Check $statement = new StatementEntity; @@ -257,7 +260,7 @@ public function testAddFunds() $statement->setDescription('Test Add Funds'); $statement->setGrossBalance('1250.00'); $statement->setAccountId($accountId); - $statement->setStatementId($statementId); + $statement->setStatementId($actual->getStatementId()); $statement->setTypeId('D'); $statement->setNetBalance('1250.00'); $statement->setPrice('1.00'); @@ -265,8 +268,6 @@ public function testAddFunds() $statement->setReferenceId('Referencia Add Funds'); $statement->setReferenceSource('Source Add Funds'); $statement->setAccountTypeId('USDTEST'); - - $actual = $this->statementBLL->getById($statementId); $statement->setDate($actual->getDate()); $this->assertEquals($statement->toArray(), $actual->toArray()); @@ -296,7 +297,7 @@ public function testAddFundsDecimal($amount) { // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->addFunds( + $actual = $this->statementBLL->addFunds( StatementDTO::create($accountId, $amount) ->setDescription('Test Add Funds') ->setReferenceId('Referencia Add Funds') @@ -310,7 +311,7 @@ public function testAddFundsDecimal($amount) $statement->setDescription('Test Add Funds'); $statement->setGrossBalance(1000 + $amount); $statement->setAccountId($accountId); - $statement->setStatementId($statementId); + $statement->setStatementId($actual->getStatementId());; $statement->setTypeId('D'); $statement->setNetBalance(1000 + $amount); $statement->setPrice('1.00'); @@ -318,8 +319,6 @@ public function testAddFundsDecimal($amount) $statement->setReferenceId('Referencia Add Funds'); $statement->setReferenceSource('Source Add Funds'); $statement->setAccountTypeId('USDTEST'); - - $actual = $this->statementBLL->getById($statementId); $statement->setDate($actual->getDate()); $this->assertEquals($statement->toArray(), $actual->toArray()); @@ -353,12 +352,12 @@ public function testWithdrawFunds() { // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->withdrawFunds( + $actual = $this->statementBLL->withdrawFunds( StatementDTO::create($accountId, 350) - ->setDescription( 'Test Withdraw') + ->setDescription('Test Withdraw') ->setReferenceId('Referencia Withdraw') ->setReferenceSource('Source Withdraw') - ); + ); // Objeto que é esperado $statement = new StatementEntity(); @@ -367,7 +366,7 @@ public function testWithdrawFunds() $statement->setDescription('Test Withdraw'); $statement->setGrossBalance('650.00'); $statement->setAccountId($accountId); - $statement->setStatementId($statementId); + $statement->setStatementId($actual->getStatementId()); $statement->setTypeId('W'); $statement->setNetBalance('650.00'); $statement->setPrice('1.00'); @@ -375,8 +374,6 @@ public function testWithdrawFunds() $statement->setReferenceId('Referencia Withdraw'); $statement->setReferenceSource('Source Withdraw'); $statement->setAccountTypeId('USDTEST'); - - $actual = $this->statementBLL->getById($statementId); $statement->setDate($actual->getDate()); // Executar teste @@ -407,16 +404,16 @@ public function testWithdrawFunds_InvalidRound() $this->statementBLL->withdrawFunds(StatementDTO::create($accountId, 10.001)); } - public function testWithdrawFunds_Negative() + public function testWithdrawFunds_Allow_Negative() { // Populate Data! - $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000, 1, -400); - $statementId = $this->statementBLL->withdrawFunds( + $accountId = $this->accountBLL->createAccount('NEGTEST', "___TESTUSER-1", 1000, 1, -400); + $actual = $this->statementBLL->withdrawFunds( StatementDTO::create($accountId, 1150) ->setDescription('Test Withdraw') ->setReferenceId('Referencia Withdraw') ->setReferenceSource('Source Withdraw') - ); + ); // Objeto que é esperado $statement = new StatementEntity(); @@ -425,40 +422,39 @@ public function testWithdrawFunds_Negative() $statement->setDescription('Test Withdraw'); $statement->setGrossBalance('-150.00'); $statement->setAccountId($accountId); - $statement->setStatementId($statementId); + $statement->setStatementId($actual->getStatementId()); $statement->setTypeId('W'); $statement->setNetBalance('-150.00'); $statement->setPrice('1.00'); $statement->setUnCleared('0.00'); $statement->setReferenceId('Referencia Withdraw'); $statement->setReferenceSource('Source Withdraw'); - $statement->setAccountTypeId('USDTEST'); - - $actual = $this->statementBLL->getById($statementId); + $statement->setAccountTypeId('NEGTEST'); $statement->setDate($actual->getDate()); // Executar teste $this->assertEquals($statement->toArray(), $actual->toArray()); } - public function testWithdrawFunds_NegativeInvalid() + public function testWithdrawFunds_Allow_Negative2() { - $this->expectException(AmountException::class); - // Populate Data! - $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000, 1, -400); - $this->statementBLL->withdrawFunds(StatementDTO::create($accountId, 1401)->setDescription('Test Withdraw')->setReferenceId('Referencia Withdraw')); + $accountId = $this->accountBLL->createAccount('NEGTEST', "___TESTUSER-1", 1000, 1, -400); + $statement = $this->statementBLL->withdrawFunds(StatementDTO::create($accountId, 1400)->setDescription('Test Withdraw')->setReferenceId('Referencia Withdraw')); + + $statement = $this->statementBLL->getById($statement->getStatementId()); + $this->assertEquals(-400, $statement->getNetBalance()); + $this->assertEquals(1400, $statement->getAmount()); } - public function testWithdrawFunds_NegativeInvalid_AllowZero() + + public function testWithdrawFunds_NegativeInvalid() { + $this->expectException(AmountException::class); + // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000, 1, -400); - $id = $this->statementBLL->withdrawFunds(StatementDTO::create($accountId, 1401)->setDescription('Test Withdraw')->setReferenceId('Referencia Withdraw'), true); - - $statement = $this->statementBLL->getById($id); - $this->assertEquals(-400, $statement->getNetBalance()); - $this->assertEquals(1400, $statement->getAmount()); + $this->statementBLL->withdrawFunds(StatementDTO::create($accountId, 1401)->setDescription('Test Withdraw')->setReferenceId('Referencia Withdraw')); } /** @@ -496,11 +492,12 @@ public function testGetAccountByUserId() "price" => 1, "extra" => "Extra Information", "entrydate" => null, - "minvalue" => "0.00" + "minvalue" => "0.00", + "laststatementid" => 2, ]); $this->assertEquals([ - $accountEntity + $accountEntity ], $account); } @@ -538,7 +535,8 @@ public function testGetAccountByAccountType() "price" => 1, "extra" => "Extra Information", "entrydate" => null, - "minvalue" => "0.00" + "minvalue" => "0.00", + "laststatementid" => 2, ]); $this->assertEquals([ @@ -557,16 +555,17 @@ public function testOverrideFunds() // Executar teste $this->assertEquals([ - 'accountid' => $accountId, - 'accounttypeid' => 'USDTEST', - 'userid' => "___TESTUSER-1", - 'grossbalance' => '650.00', - 'uncleared' => '0.00', - 'netbalance' => '650.00', - 'price' => '1.00', - 'extra' => '', - 'minvalue' => '0.00', - ], + 'accountid' => $accountId, + 'accounttypeid' => 'USDTEST', + 'userid' => "___TESTUSER-1", + 'grossbalance' => '650.00', + 'uncleared' => '0.00', + 'netbalance' => '650.00', + 'price' => '1.00', + 'extra' => '', + 'minvalue' => '0.00', + "laststatementid" => 2, + ], $account ); @@ -574,21 +573,21 @@ public function testOverrideFunds() unset($statement["date"]); $this->assertEquals([ - 'accountid' => $accountId, - 'accounttypeid' => 'USDTEST', - 'grossbalance' => '650.00', - 'uncleared' => '0.00', - 'netbalance' => '650.00', - 'price' => '1.00', - 'statementid' => $statementId, - 'typeid' => 'B', - 'amount' => '650.00', - 'description' => 'Reset Balance', - 'statementparentid' => '', - 'code' => 'BAL', - 'referenceid' => '', - 'referencesource' => '' - ], + 'accountid' => $accountId, + 'accounttypeid' => 'USDTEST', + 'grossbalance' => '650.00', + 'uncleared' => '0.00', + 'netbalance' => '650.00', + 'price' => '1.00', + 'statementid' => $statementId, + 'typeid' => 'B', + 'amount' => '650.00', + 'description' => 'Reset Balance', + 'statementparentid' => '', + 'code' => 'BAL', + 'referenceid' => '', + 'referencesource' => '' + ], $statement ); } @@ -598,12 +597,13 @@ public function testPartialFunds() // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->accountBLL->partialBalance($accountId, 650); + $statementPartial = $this->accountBLL->partialBalance($accountId, 650); $account = $this->accountBLL->getById($accountId)->toArray(); unset($account["entrydate"]); // Executar teste - $this->assertEquals([ + $this->assertEquals( + [ 'accountid' => $accountId, 'accounttypeid' => 'USDTEST', 'userid' => "___TESTUSER-1", @@ -613,21 +613,23 @@ public function testPartialFunds() 'price' => '1.00', 'extra' => '', 'minvalue' => '0.00', + "laststatementid" => 3, ], $account ); - $statement = $this->statementBLL->getById($statementId)->toArray(); + $statement = Serialize::from($statementPartial)->toArray(); unset($statement["date"]); - $this->assertEquals([ + $this->assertEquals( + [ 'accountid' => $accountId, 'accounttypeid' => 'USDTEST', 'grossbalance' => '650.00', 'uncleared' => '0.00', 'netbalance' => '650.00', 'price' => '1.00', - 'statementid' => $statementId, + 'statementid' => $statementPartial->getStatementId(), 'typeid' => 'W', 'amount' => '350.00', 'description' => 'Partial Balance', @@ -666,6 +668,7 @@ public function testCloseAccount() 'price' => '0.00', 'extra' => '', 'minvalue' => '0.00', + "laststatementid" => 5, ], $account ); @@ -705,7 +708,7 @@ public function testGetByDate() $ignore = $this->accountBLL->createAccount('BRLTEST', "___TESTUSER-999", 1000); // I dont want this account $this->statementBLL->addFunds(StatementDTO::create($ignore, 200)); - $startDate = date('Y'). "/" . date('m') . "/01"; + $startDate = date('Y') . "/" . date('m') . "/01"; $endDate = (intval(date('Y')) + (date('m') == 12 ? 1 : 0)) . "/" . (date('m') == 12 ? 1 : intval(date('m')) + 1) . "/01"; $statementList = $this->statementBLL->getByDate($accountId, $startDate, $endDate); @@ -782,7 +785,7 @@ public function testGetByStatementId() { // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->addFunds(StatementDTO::create($accountId, 400)); + $statement = $this->statementBLL->addFunds(StatementDTO::create($accountId, 400)); $this->statementBLL->withdrawFunds(StatementDTO::create($accountId, 300)); $ignore = $this->accountBLL->createAccount('BRLTEST', "___TESTUSER-999", 1000); // I dont want this account @@ -790,7 +793,7 @@ public function testGetByStatementId() $accountRepo = $this->accountBLL->getRepository(); - $accountResult = $accountRepo->getByStatementId($statementId); + $accountResult = $accountRepo->getByStatementId($statement->getStatementId());; $accountExpected = $accountRepo->getById($accountId); // Executar testestatementBLL @@ -901,10 +904,10 @@ public function testTransferFunds() $accountBrlId = $this->accountBLL->getByAccountTypeId('BRLTEST')[0]->getAccountId(); $accountUsdId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - [ $statementSourceId, $statementTargetId ] = $this->accountBLL->transferFunds($accountBrlId, $accountUsdId, 300); + [$statementSource, $statementTarget] = $this->accountBLL->transferFunds($accountBrlId, $accountUsdId, 300); - $accountSource = $this->accountBLL->getById($accountBrlId); - $accountTarget = $this->accountBLL->getById($accountUsdId); + $accountSource = $this->accountBLL->getById($statementSource->getAccountId()); + $accountTarget = $this->accountBLL->getById($statementTarget->getAccountId()); $this->assertEquals(700, $accountSource->getNetBalance()); $this->assertEquals(1300, $accountTarget->getNetBalance()); @@ -918,7 +921,7 @@ public function testTransferFundsFail() $this->expectException(AmountException::class); $this->expectExceptionMessage('Cannot withdraw above the account balance'); - [ $statementSourceId, $statementTargetId ] = $this->accountBLL->transferFunds($accountBrlId, $accountUsdId, 1100); + $this->accountBLL->transferFunds($accountBrlId, $accountUsdId, 1100); } public function testJoinTransactionAndCommit() @@ -927,9 +930,9 @@ public function testJoinTransactionAndCommit() $this->dbDriver->beginTransaction(IsolationLevelEnum::SERIALIZABLE); $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->withdrawFunds( + $statement = $this->statementBLL->withdrawFunds( StatementDTO::create($accountId, 10) - ->setDescription( 'Test') + ->setDescription('Test') ->setReferenceId('Referencia') ->setReferenceSource('Source') ->setCode('XYZ') @@ -938,7 +941,7 @@ public function testJoinTransactionAndCommit() // Needs to commit inside the context $this->dbDriver->commitTransaction(); - $statement = $this->statementBLL->getById($statementId); + $statement = $this->statementBLL->getById($statement->getStatementId()); $this->assertNotNull($statement); } @@ -948,9 +951,9 @@ public function testJoinTransactionAndRollback() $this->dbDriver->beginTransaction(IsolationLevelEnum::SERIALIZABLE); $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->withdrawFunds( + $statement = $this->statementBLL->withdrawFunds( StatementDTO::create($accountId, 10) - ->setDescription( 'Test') + ->setDescription('Test') ->setReferenceId('Referencia') ->setReferenceSource('Source') ->setCode('XYZ') @@ -959,7 +962,7 @@ public function testJoinTransactionAndRollback() // Needs to commit inside the context $this->dbDriver->rollbackTransaction(); - $statement = $this->statementBLL->getById($statementId); + $statement = $this->statementBLL->getById($statement->getStatementId()); $this->assertNull($statement); } @@ -973,15 +976,14 @@ public function testJoinTransactionDifferentIsolationLevel() try { $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->withdrawFunds( + $this->statementBLL->withdrawFunds( StatementDTO::create($accountId, 10) ->setDescription('Test') ->setReferenceId('Referencia') ->setReferenceSource('Source') ->setCode('XYZ') ); - } - finally { + } finally { $this->dbDriver->rollbackTransaction(); } @@ -993,7 +995,7 @@ public function testAddFundsExtendedStatement() // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->addFunds( + $actual = $this->statementBLL->addFunds( StatementDTO::create($accountId, 250) ->setDescription('Test Add Funds') ->setReferenceId('Referencia Add Funds') @@ -1008,7 +1010,7 @@ public function testAddFundsExtendedStatement() $statement->setDescription('Test Add Funds'); $statement->setGrossBalance('1250.00'); $statement->setAccountId($accountId); - $statement->setStatementId($statementId); + $statement->setStatementId($actual->getStatementId());; $statement->setTypeId('D'); $statement->setNetBalance('1250.00'); $statement->setPrice('1.00'); @@ -1017,11 +1019,136 @@ public function testAddFundsExtendedStatement() $statement->setReferenceSource('Source Add Funds'); $statement->setAccountTypeId('USDTEST'); $statement->setExtraProperty('Extra'); - - $actual = $this->statementBLL->getById($statementId); $statement->setDate($actual->getDate()); $this->assertEquals($statement, $actual); } -} + public function testAddFundAccountNotFound() + { + $this->expectException(AccountException::class); + $this->expectExceptionMessage('Account not found'); + $this->statementBLL->addFunds(StatementDTO::create(1023, 400)->setReferenceId('REFID')->setReferenceSource('REFSRC')); + } + + public function testWithdrawFundAccountNotFound() + { + $this->expectException(AccountException::class); + $this->expectExceptionMessage('Account not found'); + $this->statementBLL->withdrawFunds(StatementDTO::create(1023, 300)->setReferenceId('REFID2')->setReferenceSource('REFSRC')); + } + + public function testReserveWithdrawFundAccountNotFound() + { + $this->expectException(AccountException::class); + $this->expectExceptionMessage('Account not found'); + $this->statementBLL->reserveFundsForWithdraw(StatementDTO::create(1023, 300)->setReferenceId('REFID2')->setReferenceSource('REFSRC')); + } + + public function testReserveDepositFundAccountNotFound() + { + $this->expectException(AccountException::class); + $this->expectExceptionMessage('Account not found'); + $this->statementBLL->reserveFundsForDeposit(StatementDTO::create(1023, 300)->setReferenceId('REFID2')->setReferenceSource('REFSRC')); + } + + public function testStatementObserver() + { + $accountRepository = new AccountRepositoryExtended($this->dbDriver, AccountEntity::class); + $statementRepository = new StatementRepositoryExtended($this->dbDriver, StatementEntity::class); + + // Sanity Check + $this->assertFalse($accountRepository->getReach()); + $this->assertFalse($statementRepository->getReach()); + + $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); + $this->statementBLL->addFunds( + StatementDTO::create($accountId, 250) + ->setDescription('Test Add Funds') + ->setReferenceId('Referencia Add Funds') + ->setReferenceSource('Source Add Funds') + ); + + // I don´t need to test the values, because it is tested before. + // I just need to check if the observer was called. + // And inside the observer, I will check the values. + $this->assertTrue($accountRepository->getReach()); + $this->assertTrue($statementRepository->getReach()); + } + + public function testCapAtZeroFalse() + { + $this->expectException(AmountException::class); + $this->expectExceptionMessage('Cannot withdraw above the account balance'); + + $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); + $this->statementBLL->withdrawFunds( + StatementDTO::create($accountId, 1250) + ->setDescription('Test Add Funds') + ->setReferenceId('Referencia Add Funds') + ->setReferenceSource('Source Add Funds'), + capAtZero: false + ); + } + + public function testCapAtZeroTrue() + { + $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); + + $dto = StatementDTO::create($accountId, 1100) + ->setDescription('Test Add Funds') + ->setReferenceId('Referencia Add Funds') + ->setReferenceSource('Source Add Funds'); + $statement = $this->statementBLL->withdrawFunds( + $dto, + capAtZero: true + ); + + // Should be zero, because allow cap at zero + $account = $this->accountBLL->getById($accountId); + $this->assertEquals(0, $account->getGrossBalance()); + $this->assertEquals(0, $account->getUnCleared()); + $this->assertEquals(0, $account->getNetBalance()); + + // Needs to be adjusted to the new balance - 750 + $statement = $this->statementBLL->getById($statement->getStatementId()); + $this->assertEquals(1000, $statement->getAmount()); + + // The DTO should be the same + $this->assertEquals(1000, $dto->getAmount());; + } + + public function testCapAtZeroTrueUncleared() + { + $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); + + $this->statementBLL->reserveFundsForWithdraw( + StatementDTO::create($accountId, 250) + ->setDescription('Test Reserve Funds') + ->setReferenceId('Referencia Add Funds') + ->setReferenceSource('Source Add Funds') + ); + + $dto = StatementDTO::create($accountId, 800) + ->setDescription('Test Add Funds') + ->setReferenceId('Referencia Add Funds') + ->setReferenceSource('Source Add Funds'); + $withdraw = $this->statementBLL->withdrawFunds( + $dto, + capAtZero: true + ); + + // Should be zero, because allow cap at zero + $account = $this->accountBLL->getById($accountId); + $this->assertEquals(250, $account->getGrossBalance()); + $this->assertEquals(250, $account->getUnCleared()); + $this->assertEquals(0, $account->getNetBalance()); + + // Needs to be adjusted to the new balance - 750 + $statement = $this->statementBLL->getById($withdraw->getStatementId()); + $this->assertEquals(750, $statement->getAmount()); + + // The DTO should be the same + $this->assertEquals(750, $dto->getAmount());; + } +} \ No newline at end of file diff --git a/tests/Database/ReserveFundsDepositTest.php b/tests/Database/ReserveFundsDepositTest.php index 12d63a1..61d0be8 100644 --- a/tests/Database/ReserveFundsDepositTest.php +++ b/tests/Database/ReserveFundsDepositTest.php @@ -38,7 +38,7 @@ public function testReserveForDepositFunds() { // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->reserveFundsForDeposit( + $actual = $this->statementBLL->reserveFundsForDeposit( StatementDTO::create($accountId, 350) ->setDescription('Test Deposit') ->setReferenceId('Referencia Deposit') @@ -52,7 +52,7 @@ public function testReserveForDepositFunds() $statement->setDescription('Test Deposit'); $statement->setGrossBalance('1000.00'); $statement->setAccountId($accountId); - $statement->setStatementId($statementId); + $statement->setStatementId($actual->getStatementId()); $statement->setTypeId('DB'); $statement->setNetBalance('1350.00'); $statement->setPrice('1.00'); @@ -61,8 +61,6 @@ public function testReserveForDepositFunds() $statement->setReferenceSource('Source Deposit'); $statement->setAccountTypeId('USDTEST'); $statement->setStatementParentId(null); - - $actual = $this->statementBLL->getById($statementId); $statement->setDate($actual->getDate()); // Executar teste @@ -89,11 +87,11 @@ public function testReserveForDepositFunds_InvalidRound() $this->statementBLL->reserveFundsForDeposit(StatementDTO::create($accountId, 10.031)->setDescription('Test Withdraw')->setReferenceId('Referencia Withdraw')); } - public function testReserveForDepositFunds_Negative() + public function testReserveForDepositFunds_Allow_Negative() { // Populate Data! - $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", -200, 1, -400); - $statementId = $this->statementBLL->reserveFundsForDeposit( + $accountId = $this->accountBLL->createAccount('NEGTEST', "___TESTUSER-1", -200, 1, -400); + $actual = $this->statementBLL->reserveFundsForDeposit( StatementDTO::create($accountId, 300) ->setDescription('Test Deposit') ->setReferenceId('Referencia Deposit') @@ -107,16 +105,14 @@ public function testReserveForDepositFunds_Negative() $statement->setDescription('Test Deposit'); $statement->setGrossBalance('-200.00'); $statement->setAccountId($accountId); - $statement->setStatementId($statementId); + $statement->setStatementId($actual->getStatementId()); $statement->setTypeId('DB'); $statement->setNetBalance('100.00'); $statement->setPrice('1.00'); $statement->setUnCleared('-300.00'); $statement->setReferenceId('Referencia Deposit'); $statement->setReferenceSource('Source Deposit'); - $statement->setAccountTypeId('USDTEST'); - - $actual = $this->statementBLL->getById($statementId); + $statement->setAccountTypeId('NEGTEST'); $statement->setDate($actual->getDate()); // Executar teste @@ -141,14 +137,14 @@ public function testAcceptFundsById_InvalidType() // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->addFunds( + $statement = $this->statementBLL->addFunds( StatementDTO::create($accountId, 200) ->setDescription('Test Deposit') ->setReferenceId('Referencia Deposit') ->setReferenceSource('Source Deposit') ); - $this->statementBLL->acceptFundsById($statementId); + $this->statementBLL->acceptFundsById($statement->getStatementId());; } public function testAcceptFundsById_HasParentTransation() @@ -158,13 +154,13 @@ public function testAcceptFundsById_HasParentTransation() // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); $this->statementBLL->addFunds(StatementDTO::create($accountId, 150)->setDescription('Test Deposit')->setReferenceId('Referencia Deposit')); - $statementId = $this->statementBLL->reserveFundsForDeposit(StatementDTO::create($accountId, 350)->setDescription('Test Deposit')->setReferenceId('Referencia Deposit')); + $statement = $this->statementBLL->reserveFundsForDeposit(StatementDTO::create($accountId, 350)->setDescription('Test Deposit')->setReferenceId('Referencia Deposit')); // Executar ação - $this->statementBLL->acceptFundsById($statementId); + $this->statementBLL->acceptFundsById($statement->getStatementId());; // Provar o erro: - $this->statementBLL->acceptFundsById($statementId); + $this->statementBLL->acceptFundsById($statement->getStatementId());; } public function testAcceptFundsById_OK() @@ -177,7 +173,7 @@ public function testAcceptFundsById_OK() ->setReferenceId('Referencia Deposit') ->setReferenceSource('Source Deposit') ); - $statementId = $this->statementBLL->reserveFundsForDeposit( + $reserveStatement = $this->statementBLL->reserveFundsForDeposit( StatementDTO::create($accountId, 350) ->setDescription('Test Deposit') ->setReferenceId('Referencia Deposit') @@ -185,7 +181,7 @@ public function testAcceptFundsById_OK() ); // Executar ação - $actualId = $this->statementBLL->acceptFundsById($statementId); + $actualId = $this->statementBLL->acceptFundsById($reserveStatement->getStatementId()); $actual = $this->statementBLL->getById($actualId); // Objeto que é esperado @@ -195,7 +191,7 @@ public function testAcceptFundsById_OK() $statement->setGrossBalance('1500.00'); $statement->setAccountId($accountId); $statement->setStatementId($actualId); - $statement->setStatementParentId($statementId); + $statement->setStatementParentId($reserveStatement->getStatementId()); $statement->setTypeId('D'); $statement->setNetBalance('1500.00'); $statement->setPrice('1.00'); @@ -214,7 +210,7 @@ public function testAcceptPartialFundsById_PartialAmountZero() $this->expectException(AmountException::class); $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $reserveStatementId = $this->statementBLL->reserveFundsForWithdraw( + $reserveStatement = $this->statementBLL->reserveFundsForWithdraw( StatementDTO::create($accountId, 100) ); @@ -223,7 +219,7 @@ public function testAcceptPartialFundsById_PartialAmountZero() ->setReferenceSource("test-source"); $statementDTO = StatementDTO::createEmpty()->setAmount(0); - $this->statementBLL->acceptPartialFundsById($reserveStatementId, $statementDTO, $statementRefundDto); + $this->statementBLL->acceptPartialFundsById($reserveStatement->getStatementId(), $statementDTO, $statementRefundDto); } public function testAcceptPartialFundsById_AmountMoreThanWithdrawBlocked() @@ -232,7 +228,7 @@ public function testAcceptPartialFundsById_AmountMoreThanWithdrawBlocked() $this->expectExceptionMessage('Partial amount must be greater than zero and less than the original reserved amount.'); $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $reserveStatementId = $this->statementBLL->reserveFundsForWithdraw( + $reserveStatement = $this->statementBLL->reserveFundsForWithdraw( StatementDTO::create($accountId, 100) ); @@ -241,13 +237,13 @@ public function testAcceptPartialFundsById_AmountMoreThanWithdrawBlocked() ->setReferenceSource("test-source"); $statementDTO = StatementDTO::createEmpty()->setAmount(100.01); - $this->statementBLL->acceptPartialFundsById($reserveStatementId, $statementDTO, $statementRefundDto); + $this->statementBLL->acceptPartialFundsById($reserveStatement->getStatementId(), $statementDTO, $statementRefundDto); } public function testAcceptPartialFundsById_OK() { $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $reserveStatementId = $this->statementBLL->reserveFundsForWithdraw( + $reserveStatement = $this->statementBLL->reserveFundsForWithdraw( StatementDTO::create($accountId, 100)->setDescription('Reserva para Aposta') ); @@ -260,8 +256,8 @@ public function testAcceptPartialFundsById_OK() ->setDescription("Refund") ->setReferenceSource("test-source"); - $finalDebitStatementId = $this->statementBLL->acceptPartialFundsById( - $reserveStatementId, + $finalDebitStatement = $this->statementBLL->acceptPartialFundsById( + $reserveStatement->getStatementId(), $statementWithdrawDto, $statementRefundDto ); @@ -271,13 +267,13 @@ public function testAcceptPartialFundsById_OK() $this->assertEquals('920.00', $accountAfter->getNetBalance()); $this->assertEquals('0.00', $accountAfter->getUnCleared()); - $rejectedStatement = $this->statementBLL->getRepository()->getByParentId($reserveStatementId); + $rejectedStatement = $this->statementBLL->getRepository()->getByParentId($reserveStatement->getStatementId()); $this->assertNotNull($rejectedStatement); $this->assertEquals(StatementEntity::REJECT, $rejectedStatement->getTypeId()); $this->assertEquals('100.00', $rejectedStatement->getAmount()); /** @var StatementEntity $finalDebitStatement */ - $finalDebitStatement = $this->statementBLL->getById($finalDebitStatementId); + $finalDebitStatement = $this->statementBLL->getById($finalDebitStatement->getStatementId()); $this->assertEquals('80.00', $finalDebitStatement->getAmount()); $this->assertEquals(StatementEntity::WITHDRAW, $finalDebitStatement->getTypeId()); $this->assertEquals("Deposit", $finalDebitStatement->getDescription()); @@ -289,9 +285,9 @@ public function testRejectFundsById_InvalidType() // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->addFunds(StatementDTO::create($accountId, 300)); + $statement = $this->statementBLL->addFunds(StatementDTO::create($accountId, 300)); - $this->statementBLL->rejectFundsById($statementId); + $this->statementBLL->rejectFundsById($statement->getStatementId()); } public function testRejectFundsById_HasParentTransation() @@ -301,13 +297,13 @@ public function testRejectFundsById_HasParentTransation() // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); $this->statementBLL->addFunds(StatementDTO::create($accountId, 150)->setDescription('Test Deposit')->setReferenceId('Referencia Deposit')); - $statementId = $this->statementBLL->reserveFundsForDeposit(StatementDTO::create($accountId, 350)->setDescription('Test Deposit')->setReferenceId('Referencia Deposit')); + $reserveStatement = $this->statementBLL->reserveFundsForDeposit(StatementDTO::create($accountId, 350)->setDescription('Test Deposit')->setReferenceId('Referencia Deposit')); // Executar ação - $this->statementBLL->rejectFundsById($statementId); + $this->statementBLL->rejectFundsById($reserveStatement->getStatementId()); // Provocar o erro: - $this->statementBLL->rejectFundsById($statementId); + $this->statementBLL->rejectFundsById($reserveStatement->getStatementId()); } public function testRejectFundsById_OK() @@ -320,7 +316,7 @@ public function testRejectFundsById_OK() ->setReferenceId('Referencia Deposit') ->setReferenceSource('Source Deposit') ); - $statementId = $this->statementBLL->reserveFundsForDeposit( + $reserveStatement = $this->statementBLL->reserveFundsForDeposit( StatementDTO::create($accountId, 350) ->setDescription('Test Deposit') ->setReferenceId('Referencia Deposit') @@ -328,7 +324,7 @@ public function testRejectFundsById_OK() ); // Executar ação - $actualId = $this->statementBLL->rejectFundsById($statementId); + $actualId = $this->statementBLL->rejectFundsById($reserveStatement->getStatementId()); $actual = $this->statementBLL->getById($actualId); // Objeto que é esperado @@ -338,7 +334,7 @@ public function testRejectFundsById_OK() $statement->setGrossBalance('1150.00'); $statement->setAccountId($accountId); $statement->setStatementId($actualId); - $statement->setStatementParentId($statementId); + $statement->setStatementParentId($reserveStatement->getStatementId()); $statement->setTypeId('R'); $statement->setNetBalance('1150.00'); $statement->setPrice('1.00'); diff --git a/tests/Database/ReserveFundsWithdrawTest.php b/tests/Database/ReserveFundsWithdrawTest.php index 76dfa9d..81bfe72 100644 --- a/tests/Database/ReserveFundsWithdrawTest.php +++ b/tests/Database/ReserveFundsWithdrawTest.php @@ -37,7 +37,7 @@ public function testReserveForWithdrawFunds() { // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->reserveFundsForWithdraw( + $actual = $this->statementBLL->reserveFundsForWithdraw( StatementDTO::create($accountId, 350) ->setDescription('Test Withdraw') ->setReferenceId('Referencia Withdraw') @@ -51,7 +51,7 @@ public function testReserveForWithdrawFunds() $statement->setDescription('Test Withdraw'); $statement->setGrossBalance('1000.00'); $statement->setAccountId($accountId); - $statement->setStatementId($statementId); + $statement->setStatementId($actual->getStatementId());; $statement->setTypeId('WB'); $statement->setNetBalance('650.00'); $statement->setPrice('1.00'); @@ -59,8 +59,6 @@ public function testReserveForWithdrawFunds() $statement->setReferenceId('Referencia Withdraw'); $statement->setReferenceSource('Source Withdraw'); $statement->setAccountTypeId('USDTEST'); - - $actual = $this->statementBLL->getById($statementId); $statement->setDate($actual->getDate()); // Executar teste @@ -95,11 +93,11 @@ public function testReserveForWithdrawFunds_InvalidRound() ->setReferenceSource('Source Withdraw')); } - public function testReserveForWithdrawFunds_Negative() + public function testReserveForWithdrawFunds_Allow_Negative() { // Populate Data! - $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000, 1, -400); - $statementId = $this->statementBLL->reserveFundsForWithdraw( + $accountId = $this->accountBLL->createAccount('NEGTEST', "___TESTUSER-1", 1000, 1, -400); + $actual = $this->statementBLL->reserveFundsForWithdraw( StatementDTO::create($accountId, 1150) ->setDescription('Test Withdraw') ->setReferenceId('Referencia Withdraw') @@ -113,16 +111,14 @@ public function testReserveForWithdrawFunds_Negative() $statement->setDescription('Test Withdraw'); $statement->setGrossBalance('1000.00'); $statement->setAccountId($accountId); - $statement->setStatementId($statementId); + $statement->setStatementId($actual->getStatementId()); $statement->setTypeId('WB'); $statement->setNetBalance('-150.00'); $statement->setPrice('1.00'); $statement->setUnCleared('1150.00'); $statement->setReferenceId('Referencia Withdraw'); $statement->setReferenceSource('Source Withdraw'); - $statement->setAccountTypeId('USDTEST'); - - $actual = $this->statementBLL->getById($statementId); + $statement->setAccountTypeId('NEGTEST'); $statement->setDate($actual->getDate()); // Executar teste @@ -159,14 +155,14 @@ public function testAcceptFundsById_InvalidType() // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->withdrawFunds( + $statement = $this->statementBLL->withdrawFunds( StatementDTO::create($accountId, 200) ->setDescription('Test Withdraw') ->setReferenceId('Referencia Withdraw') ->setReferenceSource('Source Withdraw') ); - $this->statementBLL->acceptFundsById($statementId); + $this->statementBLL->acceptFundsById($statement->getStatementId()); } public function testAcceptFundsById_HasParentTransation() @@ -176,13 +172,13 @@ public function testAcceptFundsById_HasParentTransation() // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); $this->statementBLL->withdrawFunds(StatementDTO::create($accountId, 150)->setDescription('Test Withdraw')->setReferenceId('Referencia Withdraw')); - $statementId = $this->statementBLL->reserveFundsForWithdraw(StatementDTO::create($accountId, 350)->setDescription('Test Withdraw')->setReferenceId('Referencia Withdraw')); + $statement = $this->statementBLL->reserveFundsForWithdraw(StatementDTO::create($accountId, 350)->setDescription('Test Withdraw')->setReferenceId('Referencia Withdraw')); // Executar ação - $this->statementBLL->acceptFundsById($statementId); + $this->statementBLL->acceptFundsById($statement->getStatementId()); // Provar o erro: - $this->statementBLL->acceptFundsById($statementId); + $this->statementBLL->acceptFundsById($statement->getStatementId()); } public function testAcceptFundsById_OK() @@ -195,7 +191,7 @@ public function testAcceptFundsById_OK() ->setReferenceId('Referencia Withdraw') ->setReferenceSource('Source Withdraw') ); - $statementId = $this->statementBLL->reserveFundsForWithdraw( + $reserveStatement = $this->statementBLL->reserveFundsForWithdraw( StatementDTO::create($accountId, 350) ->setDescription('Test Withdraw') ->setReferenceId('Referencia Withdraw') @@ -203,7 +199,7 @@ public function testAcceptFundsById_OK() ); // Executar ação - $actualId = $this->statementBLL->acceptFundsById($statementId); + $actualId = $this->statementBLL->acceptFundsById($reserveStatement->getStatementId()); $actual = $this->statementBLL->getById($actualId); // Objeto que é esperado @@ -213,7 +209,7 @@ public function testAcceptFundsById_OK() $statement->setGrossBalance('500.00'); $statement->setAccountId($accountId); $statement->setStatementId($actualId); - $statement->setStatementParentId($statementId); + $statement->setStatementParentId($reserveStatement->getStatementId()); $statement->setTypeId('W'); $statement->setNetBalance('500.00'); $statement->setPrice('1.00'); @@ -243,9 +239,9 @@ public function testRejectFundsById_InvalidType() // Populate Data! $accountId = $this->accountBLL->createAccount('USDTEST', "___TESTUSER-1", 1000); - $statementId = $this->statementBLL->withdrawFunds(StatementDTO::create($accountId, 300)); + $statement = $this->statementBLL->withdrawFunds(StatementDTO::create($accountId, 300)); - $this->statementBLL->rejectFundsById($statementId); + $this->statementBLL->rejectFundsById($statement->getStatementId()); } public function testRejectFundsById_HasParentTransation() @@ -260,7 +256,7 @@ public function testRejectFundsById_HasParentTransation() ->setReferenceId('Referencia Withdraw') ->setReferenceSource('Source Withdraw') ); - $statementId = $this->statementBLL->reserveFundsForWithdraw( + $statement = $this->statementBLL->reserveFundsForWithdraw( StatementDTO::create($accountId, 350) ->setDescription('Test Withdraw') ->setReferenceId('Referencia Withdraw') @@ -268,10 +264,10 @@ public function testRejectFundsById_HasParentTransation() ); // Executar ação - $this->statementBLL->rejectFundsById($statementId); + $this->statementBLL->rejectFundsById($statement->getStatementId()); // Provocar o erro: - $this->statementBLL->rejectFundsById($statementId); + $this->statementBLL->rejectFundsById($statement->getStatementId()); } public function testRejectFundsById_OK() @@ -284,7 +280,7 @@ public function testRejectFundsById_OK() ->setReferenceId('Referencia Withdraw') ->setReferenceSource('Source Withdraw') ); - $statementId = $this->statementBLL->reserveFundsForWithdraw( + $reserveStatement = $this->statementBLL->reserveFundsForWithdraw( StatementDTO::create($accountId, 350) ->setDescription('Test Withdraw') ->setReferenceId('Referencia Withdraw') @@ -292,7 +288,7 @@ public function testRejectFundsById_OK() ); // Executar ação - $actualId = $this->statementBLL->rejectFundsById($statementId); + $actualId = $this->statementBLL->rejectFundsById($reserveStatement->getStatementId()); $actual = $this->statementBLL->getById($actualId); // Objeto que é esperado @@ -302,7 +298,7 @@ public function testRejectFundsById_OK() $statement->setGrossBalance('850.00'); $statement->setAccountId($accountId); $statement->setStatementId($actualId); - $statement->setStatementParentId($statementId); + $statement->setStatementParentId($reserveStatement->getStatementId()); $statement->setTypeId('R'); $statement->setNetBalance('850.00'); $statement->setPrice('1.00');