From 0ee2533dcf9ec29c15cc0a8e203faf6887143168 Mon Sep 17 00:00:00 2001 From: Daniil Tkachev Date: Fri, 14 Feb 2025 15:42:38 +0100 Subject: [PATCH] UNZER-542 --draft-- Fixing ordersnr in admin b2b/b2c paylater --- src/Controller/Admin/AdminOrderController.php | 2 +- src/Model/Order.php | 3 + src/Service/Payment.php | 5 +- src/Service/RequestService.php | 25 ++ .../SavedPaymentFetchPaymentTypeService.php | 73 ++++++ .../SavedPaymentLoadFilterService.php | 38 +++ .../SavedPaymentLoadGroupService.php | 26 ++ .../SavedPayment/SavedPaymentMapper.php | 84 ++++++ .../SavedPaymentMethodValidator.php | 21 ++ .../SavedPaymentSessionService.php | 43 ++++ src/Service/SavedPayment/UserIdService.php | 24 ++ src/Service/SavedPaymentLoadService.php | 82 ++++++ src/Service/SavedPaymentSaveService.php | 54 ++++ src/Service/Transaction.php | 65 ++++- src/Service/UserRepository.php | 3 + tests/Codeception/acceptance.suite.yml | 4 +- .../Model/TestCardPaymentType.php | 25 ++ .../Service/SavedPayment/SQL/LoadQueries.php | 25 ++ ...avedPaymentFetchPaymentTypeServiceTest.php | 160 ++++++++++++ .../SavedPaymentLoadFilterServiceTest.php | 84 ++++++ .../SavedPaymentLoadGroupServiceTest.php | 94 +++++++ .../SavedPaymentMapperIntegrationTest.php | 241 ++++++++++++++++++ .../SavedPaymentMethodValidatorTest.php | 55 ++++ .../SavedPaymentSessionServiceTest.php | 86 +++++++ .../SavedPayment/UserIdServiceTest.php | 79 ++++++ .../Service/SavedPaymentLoadServiceTest.php | 211 +++++++++++++++ .../Service/SavedPaymentSaveServiceTest.php | 125 +++++++++ 27 files changed, 1720 insertions(+), 17 deletions(-) create mode 100644 src/Service/RequestService.php create mode 100644 src/Service/SavedPayment/SavedPaymentFetchPaymentTypeService.php create mode 100644 src/Service/SavedPayment/SavedPaymentLoadFilterService.php create mode 100644 src/Service/SavedPayment/SavedPaymentLoadGroupService.php create mode 100644 src/Service/SavedPayment/SavedPaymentMapper.php create mode 100644 src/Service/SavedPayment/SavedPaymentMethodValidator.php create mode 100644 src/Service/SavedPayment/SavedPaymentSessionService.php create mode 100644 src/Service/SavedPayment/UserIdService.php create mode 100644 src/Service/SavedPaymentLoadService.php create mode 100644 src/Service/SavedPaymentSaveService.php create mode 100644 tests/Unit/Service/SavedPayment/Model/TestCardPaymentType.php create mode 100644 tests/Unit/Service/SavedPayment/SQL/LoadQueries.php create mode 100644 tests/Unit/Service/SavedPayment/SavedPaymentFetchPaymentTypeServiceTest.php create mode 100644 tests/Unit/Service/SavedPayment/SavedPaymentLoadFilterServiceTest.php create mode 100644 tests/Unit/Service/SavedPayment/SavedPaymentLoadGroupServiceTest.php create mode 100644 tests/Unit/Service/SavedPayment/SavedPaymentMapperIntegrationTest.php create mode 100644 tests/Unit/Service/SavedPayment/SavedPaymentMethodValidatorTest.php create mode 100644 tests/Unit/Service/SavedPayment/SavedPaymentSessionServiceTest.php create mode 100644 tests/Unit/Service/SavedPayment/UserIdServiceTest.php create mode 100644 tests/Unit/Service/SavedPaymentLoadServiceTest.php create mode 100644 tests/Unit/Service/SavedPaymentSaveServiceTest.php diff --git a/src/Controller/Admin/AdminOrderController.php b/src/Controller/Admin/AdminOrderController.php index ddc6cf4a..e8f5b7d8 100644 --- a/src/Controller/Admin/AdminOrderController.php +++ b/src/Controller/Admin/AdminOrderController.php @@ -311,7 +311,7 @@ protected function addAuthorizationViewData(Authorization $authorization): void protected function getCustomerTypeAndCurrencyFromTransaction(): array { $transactionService = $this->getServiceFromContainer(TransactionService::class); - return $transactionService->getCustomerTypeAndCurrencyFromTransactionByOrderId($this->getEditObjectId()); + return $transactionService->getCustomerTypeAndCurrencyByOrderId($this->getEditObjectId()); } /** diff --git a/src/Model/Order.php b/src/Model/Order.php index 482407cd..9ee5cb11 100644 --- a/src/Model/Order.php +++ b/src/Model/Order.php @@ -96,6 +96,9 @@ public function finalizeUnzerOrderAfterRedirect( $this->setTmpOrderStatus($unzerOrderId, 'FINISHED'); $iRet = $this->sendOrderConfirmationEmail($oUser, $oBasket, $oUserPayment); } else { + if ($unzerPaymentStatus !== PaymentService::STATUS_NOT_FINISHED) { + Registry::getSession()->setVariable('orderCancellationProcessed', true); + } $isError = $unzerPaymentStatus === PaymentService::STATUS_ERROR; if (!$isError && !isset($params['finalizeCancellation'])) { $this->sendOrderConfirmationEmail($oUser, $oBasket, $oUserPayment); diff --git a/src/Service/Payment.php b/src/Service/Payment.php index 9611f0ad..7602f28c 100644 --- a/src/Service/Payment.php +++ b/src/Service/Payment.php @@ -473,6 +473,8 @@ public function doUnzerAuthorizationCancel( /** * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @throws \Doctrine\DBAL\Driver\Exception + * @throws \Doctrine\DBAL\Exception */ public function sendShipmentNotification( ?Order $oOrder, @@ -483,8 +485,9 @@ public function sendShipmentNotification( } $sPaymentId = $sPaymentId ?? $this->transactionService->getPaymentIdByOrderId($oOrder->getId()); + $transactionDetails = $this->transactionService - ->getCustomerTypeAndCurrencyFromTransactionByOrderId($oOrder->getId()); + ->getCustomerTypeAndCurrencyByOrderId($oOrder->getId()); $blSuccess = false; diff --git a/src/Service/RequestService.php b/src/Service/RequestService.php new file mode 100644 index 00000000..1b745386 --- /dev/null +++ b/src/Service/RequestService.php @@ -0,0 +1,25 @@ +oxidRequest = $oxidRequest; + } + public function isSavePaymentSelectedByUserInRequest(): bool + { + return $this->getUnzerBoolRequestParameter('oscunzersavepayment'); + } + + private function getUnzerBoolRequestParameter(string $varName): bool + { + return (bool) $this->oxidRequest->getRequestParameter($varName); + } +} diff --git a/src/Service/SavedPayment/SavedPaymentFetchPaymentTypeService.php b/src/Service/SavedPayment/SavedPaymentFetchPaymentTypeService.php new file mode 100644 index 00000000..ec2fdd56 --- /dev/null +++ b/src/Service/SavedPayment/SavedPaymentFetchPaymentTypeService.php @@ -0,0 +1,73 @@ +unzerSDKLoader = $unzerSDKLoader; + $this->debugHandler = $debugHandler; + } + + /** + * @param array $transactions transactions got from + * SavedPaymentFetchPaymentTypeService::getSavedPaymentTransactions + */ + public function fetchPaymentTypes(array $transactions): array + { + $paymentTypes = []; + foreach ($transactions as $transaction) { + $paymentTypeId = $transaction['PAYMENTTYPEID']; + $paymentId = (string)$transaction['OXPAYMENTTYPE']; + $currency = $transaction['CURRENCY']; + $customerType = $transaction['CUSTOMERTYPE']; + $transactionOxId = $transaction['OXID']; + + if (empty($paymentTypeId)) { + continue; + } + + try { + $unzerSDK = $this->unzerSDKLoader->getUnzerSDK( + $paymentId, + $currency, + $customerType + ); + $paymentType = $unzerSDK->fetchPaymentType($paymentTypeId); + if ($paymentType instanceof Card) { + $paymentTypes[$paymentType->getBrand()][$transactionOxId] = $paymentType->expose(); + } + if ($paymentType instanceof Paypal) { + $paymentTypes['paypal'][$transactionOxId] = $paymentType->expose(); + } + if ($paymentType instanceof SepaDirectDebit) { + $paymentTypes['sepa'][$transactionOxId] = $paymentType->expose(); + } + } catch (UnzerApiException | UnzerException | \Throwable $e) { + if ($e->getCode() !== 'API.500.100.001') { + $logEntry = sprintf( + 'Unknown error code while creating the PaymentList: "%s", message: "%s" ', + $e->getCode(), + $e->getMessage() + ); + $this->debugHandler->log($logEntry); + continue; + } + } + } + + return $paymentTypes; + } +} diff --git a/src/Service/SavedPayment/SavedPaymentLoadFilterService.php b/src/Service/SavedPayment/SavedPaymentLoadFilterService.php new file mode 100644 index 00000000..43e085fc --- /dev/null +++ b/src/Service/SavedPayment/SavedPaymentLoadFilterService.php @@ -0,0 +1,38 @@ +methodValidator = $methodValidator; + } + + public function getPaymentTypeIdLikeExpression(string $savedPaymentMethod): string + { + if (!$this->methodValidator->validate(($savedPaymentMethod))) { + throw new InvalidArgumentException( + "Invalid savedPaymentMethod SavedPaymentService::getLastSavedPaymentTransaction" + . ": $savedPaymentMethod" + ); + } + + if (SavedPaymentLoadService::SAVED_PAYMENT_ALL === $savedPaymentMethod) { + return "transactionAfterOrder.PAYMENTTYPEID LIKE 's-" + . SavedPaymentLoadService::SAVED_PAYMENT_PAYPAL . "%'" + . " OR transactionAfterOrder.PAYMENTTYPEID LIKE 's-" + . SavedPaymentLoadService::SAVED_PAYMENT_CREDIT_CARD . "%'" + . " OR transactionAfterOrder.PAYMENTTYPEID LIKE 's-" + . SavedPaymentLoadService::SAVED_PAYMENT_SEPA_DIRECT_DEBIT . "%'"; + } + + return "transactionAfterOrder.PAYMENTTYPEID LIKE 's-{$savedPaymentMethod}%'"; + } +} diff --git a/src/Service/SavedPayment/SavedPaymentLoadGroupService.php b/src/Service/SavedPayment/SavedPaymentLoadGroupService.php new file mode 100644 index 00000000..147b08a2 --- /dev/null +++ b/src/Service/SavedPayment/SavedPaymentLoadGroupService.php @@ -0,0 +1,26 @@ + $paymentTypesOfMethod) { + $groupedPaymentTypes[$paymentMethod] = $this->groupPaymentTypesInner( + $paymentTypesOfMethod + ); + } + + return $groupedPaymentTypes; + } + + private function groupPaymentTypesInner(array $paymentTypes): array + { + $groupedPaymentTypes = []; + foreach ($paymentTypes as $paymentType) { + $groupingKeyBy = $this->getGroupingKey($paymentType); + if ($groupingKeyBy && $this->paymentTypeMatchesGroupingKey($paymentType, $groupingKeyBy)) { + $groupedPaymentTypes[$this->getGroupingValue($paymentType, $groupingKeyBy)] = $paymentType; + } + } + + return $groupedPaymentTypes; + } + + private function paymentTypeMatchesGroupingKey(array $paymentType, string $groupingKey): bool + { + if (stripos($groupingKey, '|')) { + $paymentTypeKeys = explode('|', $groupingKey); + + return $this->areKeysDefined($paymentTypeKeys, $paymentType); + } + return isset($paymentType[$groupingKey]); + } + + /** + * the order of if statements is important because email is defined in all payment types, number only for + * credit card and iban only for sepa payments + */ + private function getGroupingKey(array $paymentType): ?string + { + if ($this->paymentTypeMatchesGroupingKey($paymentType, self::GROUPING_KEY_CARD)) { + return self::GROUPING_KEY_CARD; + } elseif (isset($paymentType[self::GROUPING_KEY_SEPA])) { + return self::GROUPING_KEY_SEPA; + } elseif (isset($paymentType[self::GROUPING_KEY_PAYPAL])) { + return self::GROUPING_KEY_PAYPAL; + } + + return null; + } + + private function getGroupingValue(array $paymentType, string $groupingKeyBy): string + { + if ($this->paymentTypeMatchesGroupingKey($paymentType, self::GROUPING_KEY_CARD)) { + $paymentTypeKeys = explode('|', self::GROUPING_KEY_CARD); + return $paymentType[$paymentTypeKeys[0]] . '|' . $paymentType[$paymentTypeKeys[1]]; + } + + return $paymentType[$groupingKeyBy]; + } + + private function areKeysDefined(array $requiredKeys, array $array): bool + { + $arrayKeys = array_keys($array); + $missingKeys = array_diff($requiredKeys, $arrayKeys); + + return empty($missingKeys); + } +} diff --git a/src/Service/SavedPayment/SavedPaymentMethodValidator.php b/src/Service/SavedPayment/SavedPaymentMethodValidator.php new file mode 100644 index 00000000..aacab82b --- /dev/null +++ b/src/Service/SavedPayment/SavedPaymentMethodValidator.php @@ -0,0 +1,21 @@ +session = $session; + $this->requestService = $requestService; + } + + public function isSavedPayment(): bool + { + return (bool) $this->session->getVariable($this->getSessionVariableName()); + } + + public function setSavedPayment(): void + { + $this->session->setVariable( + $this->getSessionVariableName(), + $this->requestService->isSavePaymentSelectedByUserInRequest() + ); + } + + public function unsetSavedPayment(): void + { + $this->session->deleteVariable( + $this->getSessionVariableName() + ); + } + + private function getSessionVariableName(): string + { + return self::class . '_userClickedSavePaymentCheckbox'; + } +} diff --git a/src/Service/SavedPayment/UserIdService.php b/src/Service/SavedPayment/UserIdService.php new file mode 100644 index 00000000..028ce446 --- /dev/null +++ b/src/Service/SavedPayment/UserIdService.php @@ -0,0 +1,24 @@ +getEmail() ?? ''; + } elseif ($paymentType instanceof Card) { + return $paymentType->getNumber() . '|' . $paymentType->getExpiryDate(); + } elseif ($paymentType instanceof SepaDirectDebit) { + return $paymentType->getIban() ?? ''; + } + + return ''; + } +} diff --git a/src/Service/SavedPaymentLoadService.php b/src/Service/SavedPaymentLoadService.php new file mode 100644 index 00000000..de20eb62 --- /dev/null +++ b/src/Service/SavedPaymentLoadService.php @@ -0,0 +1,82 @@ +queryBuilder = $queryBuilderFactory->create(); + $this->methodValidator = $methodValidator; + $this->loadFilterService = $loadFilterService; + $this->loadGroupService = $loadGroupService; + } + + /** + * Returns the saved transactions of given $savedPaymentMethod and $userId. + * The resulting array has the same structure as the result from Transaction::getTransactionIds(). + * + * @throws \Doctrine\DBAL\Driver\Exception + * @throws \Doctrine\DBAL\Exception + */ + public function getSavedPaymentTransactions(string $oxUserId, string $savedPaymentMethod): array + { + if (!$this->methodValidator->validate($savedPaymentMethod)) { + throw new InvalidArgumentException( + "Invalid savedPaymentMethod SavedPaymentService::getLastSavedPaymentTransaction: $savedPaymentMethod" + ); + } + + $queryBuilder = clone $this->queryBuilder; + $queryBuilder->select('*') + ->from('transactionAfterOrder') + ->where('OXUSERID = :oxuserid') + ->setParameter('oxuserid', $oxUserId); + + $filterSQL = $this->loadFilterService->getPaymentTypeIdLikeExpression($savedPaymentMethod); + if ($filterSQL) { + $queryBuilder->andWhere($filterSQL); + } + + $queryBuilder->orderBy('OXACTIONDATE'); + + $ungroupedRows = $queryBuilder->executeQuery()->fetchAllAssociative(); + + return $this->loadGroupService->groupByPaymentTypeId($ungroupedRows); + } + + public function getSavedPaymentTransactionsByUserId(string $savedPaymentUserId): array + { + $queryBuilder = clone $this->queryBuilder; + $queryBuilder->select('OXID') + ->from('transactionAfterOrder') + ->where('OXUSERID = :savedPaymentUserId') + ->setParameter('savedPaymentUserId', $savedPaymentUserId); + + $rowsFromDB = $queryBuilder->executeQuery()->fetchAllAssociative(); + + return array_map(fn($row) => $row['OXID'], $rowsFromDB); + } +} diff --git a/src/Service/SavedPaymentSaveService.php b/src/Service/SavedPaymentSaveService.php new file mode 100644 index 00000000..2b4f464c --- /dev/null +++ b/src/Service/SavedPaymentSaveService.php @@ -0,0 +1,54 @@ +queryBuilder = $queryBuilderFactory->create(); + $this->userIdService = $userIdService; + $this->sessionService = $sessionService; + } + + public function getTransactionParameters(Payment $payment): array + { + $paymentType = $payment->getPaymentType(); + + if ($this->sessionService->isSavedPayment()) { + return [ + 'savepaymentuserid' => $paymentType ? $this->userIdService->getUserIdByPaymentType($paymentType) : '', + 'savepayment' => $paymentType ? '1' : '0', + ]; + } + + return []; + } + + public function unsetSavedPayments(array $transactionIds): bool + { + $queryBuilder = $this->queryBuilder; + $queryBuilder + ->update('oscunzertransaction') + ->set('SAVEPAYMENT', 0) + ->where($queryBuilder->expr()->in('OXID', ':transactionIds')) + ->setParameter('transactionIds', $transactionIds, Connection::PARAM_STR_ARRAY); + + return $queryBuilder->executeStatement() > 0; + } +} diff --git a/src/Service/Transaction.php b/src/Service/Transaction.php index 11c46e83..3f5ac7c7 100644 --- a/src/Service/Transaction.php +++ b/src/Service/Transaction.php @@ -82,25 +82,34 @@ public function writeTransactionToDB( string $orderid, string $userId, ?Payment $unzerPayment, - ?Shipment $unzerShipment = null + ?Shipment $unzerShipment = null, + ?AbstractTransactionType $transaction = null ): bool { $oOrder = oxNew(Order::class); $oOrder->load($orderid); - $params = [ - 'oxorderid' => $orderid, - 'oxshopid' => $this->context->getCurrentShopId(), - 'oxuserid' => $userId, - 'oxactiondate' => date('Y-m-d H:i:s', $this->utilsDate->getTime()), - 'customertype' => $this->getCustomerTypeByOrder($oOrder) - ]; + $params = $this->getBasicSaveParameters($orderid, $userId); if ($unzerPayment) { - $unzerPaymentData = $unzerShipment !== null ? - $this->getUnzerShipmentData($unzerShipment) : - $this->getUnzerPaymentData($unzerPayment); - $params = array_merge($params, $unzerPaymentData); + $this->extendSaveParameters( + $params, + $unzerPayment, + $unzerShipment, + $transaction + ); + + if ( + $unzerPayment->getPaymentType() instanceof PaylaterInvoice || + $unzerPayment->getPaymentType() instanceof PaylaterInstallment + ) { + $delCompany = $oOrder->getFieldData('oxdelcompany') ?? ''; + $billCompany = $oOrder->getFieldData('oxbillcompany') ?? ''; + $params['customertype'] = 'B2C'; + if (!empty($delCompany) || !empty($billCompany)) { + $params['customertype'] = 'B2B'; + } + } } if ($this->saveTransaction($params, $oOrder)) { @@ -511,7 +520,7 @@ public function getTransactionIdByOrderId(string $orderid): string * @throws Exception * @throws \Doctrine\DBAL\Exception */ - public function getCustomerTypeAndCurrencyFromTransactionByOrderId(string $orderId): array + public function getCustomerTypeAndCurrencyByOrderId(string $orderId): array { $transaction = oxNew(TransactionModel::class); $transactionId = $this->getTransactionIdByOrderId($orderId); @@ -717,4 +726,34 @@ private function getCustomerTypeByOrder(Order $oOrder): string return $customerType; } + + private function getBasicSaveParameters(string $orderId, string $userId): array + { + $customerData = $this->getCustomerTypeAndCurrencyByOrderId($orderId); + return [ + 'oxorderid' => $orderId, + 'oxshopid' => $this->context->getCurrentShopId(), + 'oxuserid' => $userId, + 'oxactiondate' => date('Y-m-d H:i:s', $this->utilsDate->getTime()), + 'customertype' => $customerData['customertype'], + ]; + } + + private function extendSaveParameters( + array &$parameters, + Payment $unzerPayment, + ?Shipment $unzerShipment = null, + ?AbstractTransactionType $transaction = null + ): void { + $unzerPaymentData = !is_null($unzerShipment) ? + $this->getUnzerShipmentData($unzerShipment, $unzerPayment) : + $this->getUnzerPaymentData($unzerPayment, $transaction); + $parameters = array_merge($parameters, $unzerPaymentData); + + $parameters = array_merge( + $parameters, + $this->getServiceFromContainer(SavedPaymentSaveService::class) + ->getTransactionParameters($unzerPayment) + ); + } } diff --git a/src/Service/UserRepository.php b/src/Service/UserRepository.php index 2a3a2dce..28ed8b4f 100644 --- a/src/Service/UserRepository.php +++ b/src/Service/UserRepository.php @@ -34,6 +34,9 @@ public function getUserCountryIso(): string $country->load($countryId); /** @var string $result */ $result = $country->getFieldData('oxisoalpha2'); + if (null == $result) { + $result = ''; + } } return $result; } diff --git a/tests/Codeception/acceptance.suite.yml b/tests/Codeception/acceptance.suite.yml index 5661411b..afa5319a 100644 --- a/tests/Codeception/acceptance.suite.yml +++ b/tests/Codeception/acceptance.suite.yml @@ -30,8 +30,8 @@ modules: populate: true # run populator before all tests cleanup: false # run populator before each test# populator: > - bin/oe-console oe:setup:demodata && - bin/oe-console oe:module:activate osc-unzer && + ./bin/oe-console oe:setup:demodata && + ./bin/oe-console oe:module:activate osc-unzer && mysql --defaults-file=$mysql_config --default-character-set=utf8 $dbname < $module_dump - \OxidEsales\Codeception\Module\Oxideshop: screen_shot_url: '%SCREEN_SHOT_URL%' diff --git a/tests/Unit/Service/SavedPayment/Model/TestCardPaymentType.php b/tests/Unit/Service/SavedPayment/Model/TestCardPaymentType.php new file mode 100644 index 00000000..e54e6df8 --- /dev/null +++ b/tests/Unit/Service/SavedPayment/Model/TestCardPaymentType.php @@ -0,0 +1,25 @@ +brand = $brand; + } + + public function getBrand(): string + { + return $this->brand; + } +} diff --git a/tests/Unit/Service/SavedPayment/SQL/LoadQueries.php b/tests/Unit/Service/SavedPayment/SQL/LoadQueries.php new file mode 100644 index 00000000..71f2f6ab --- /dev/null +++ b/tests/Unit/Service/SavedPayment/SQL/LoadQueries.php @@ -0,0 +1,25 @@ +unzerSDKLoader = $this->createMock(UnzerSDKLoader::class); + $this->debugHandler = $this->createMock(DebugHandler::class); + $this->fetchPaymentTypeService = new SavedPaymentFetchPaymentTypeService( + $this->unzerSDKLoader, + $this->debugHandler + ); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentFetchPaymentTypeService::fetchPaymentTypes + */ + public function testFetchPaymentTypesSuccess() + { + $paymentTypes = [ + 'crd1' => new TestCardPaymentType('4012001037461114', '03/30', null, 'Visa'), + 'ppl1' => new Paypal(), + 'sdd1' => new SepaDirectDebit('DE89370400440532013000') + ]; + + $savedPaymentTransactions = [ + [ + 'PAYMENTTYPEID' => 'crd1', + 'OXPAYMENTTYPE' => 'somePaymentId1', + 'CURRENCY' => 'USD', + 'CUSTOMERTYPE' => 'B2B', + 'OXID' => 'txn1' + ], + [ + 'PAYMENTTYPEID' => 'ppl1', + 'OXPAYMENTTYPE' => 'somePaymentId2', + 'CURRENCY' => 'EUR', + 'CUSTOMERTYPE' => 'B2C', + 'OXID' => 'txn2' + ], + [ + 'PAYMENTTYPEID' => 'sdd1', + 'OXPAYMENTTYPE' => 'somePaymentId3', + 'CURRENCY' => 'GBP', + 'CUSTOMERTYPE' => 'B2B', + 'OXID' => 'txn3' + ] + ]; + + $this->unzerSDK = $this->createMock(Unzer::class); + $this->unzerSDKLoader + ->expects($this->exactly(3)) + ->method('getUnzerSDK') + ->willReturn($this->unzerSDK); + + $this->unzerSDK + ->expects($this->exactly(3)) + ->method('fetchPaymentType') + ->will($this->returnCallback(function ($paymentTypeId) use ($paymentTypes) { + return $paymentTypes[$paymentTypeId]; + })); + + $this->debugHandler + ->expects($this->exactly(0)) + ->method('log'); + + $result = $this->fetchPaymentTypeService->fetchPaymentTypes($savedPaymentTransactions); + + $this->assertArrayHasKey('Visa', $result); + $this->assertArrayHasKey('paypal', $result); + $this->assertArrayHasKey('sepa', $result); + $this->assertCount(1, $result['Visa']); + $this->assertCount(1, $result['paypal']); + $this->assertCount(1, $result['sepa']); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentFetchPaymentTypeService::fetchPaymentTypes + */ + public function testFetchPaymentTypesExceptionHandling() + { + $savedPaymentTransactions = [ + [ + 'PAYMENTTYPEID' => 'crd1', + 'OXPAYMENTTYPE' => 'somePaymentId1', + 'CURRENCY' => 'USD', + 'CUSTOMERTYPE' => 'B2B', + 'OXID' => 'txn1' + ] + ]; + + $this->unzerSDK = $this->createMock(Unzer::class); + $this->unzerSDKLoader + ->expects($this->once()) + ->method('getUnzerSDK') + ->willReturn($this->unzerSDK); + + $this->unzerSDK + ->expects($this->once()) + ->method('fetchPaymentType') + ->willThrowException(new UnzerApiException('Error', 500)); + + $this->debugHandler + ->expects($this->once()) + ->method('log') + ->with($this->stringContains('Unknown error code while creating the PaymentList')); + + $this->unzerSDKLoader + ->expects($this->exactly(1)) + ->method('getUnzerSDK'); + + $result = $this->fetchPaymentTypeService->fetchPaymentTypes($savedPaymentTransactions); + + $this->assertEmpty($result); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentFetchPaymentTypeService::fetchPaymentTypes + */ + public function testFetchPaymentTypesInvalidPaymentTypeId() + { + $savedPaymentTransactions = [ + [ + 'PAYMENTTYPEID' => '', + 'OXPAYMENTTYPE' => 'somePaymentId1', + 'CURRENCY' => 'USD', + 'CUSTOMERTYPE' => 'B2B', + 'OXID' => 'txn1' + ] + ]; + + $result = $this->fetchPaymentTypeService->fetchPaymentTypes($savedPaymentTransactions); + + $this->assertEmpty($result); + } +} diff --git a/tests/Unit/Service/SavedPayment/SavedPaymentLoadFilterServiceTest.php b/tests/Unit/Service/SavedPayment/SavedPaymentLoadFilterServiceTest.php new file mode 100644 index 00000000..d4366198 --- /dev/null +++ b/tests/Unit/Service/SavedPayment/SavedPaymentLoadFilterServiceTest.php @@ -0,0 +1,84 @@ +savedPaymentMethodValidator = $this->createMock(SavedPaymentMethodValidator::class); + $this->filterService = new SavedPaymentLoadFilterService($this->savedPaymentMethodValidator); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentLoadFilterService::getPaymentTypeIdLikeExpression + */ + public function testGetPaymentTypeIdLikeExpressionValidMethodAll() + { + $this->savedPaymentMethodValidator + ->method('validate') + ->with(SavedPaymentLoadService::SAVED_PAYMENT_ALL) + ->willReturn(true); + + $result = $this->filterService->getPaymentTypeIdLikeExpression(SavedPaymentLoadService::SAVED_PAYMENT_ALL); + + $expected = "transactionAfterOrder.PAYMENTTYPEID LIKE 's-" + . SavedPaymentLoadService::SAVED_PAYMENT_PAYPAL . "%'" + . " OR transactionAfterOrder.PAYMENTTYPEID LIKE 's-" + . SavedPaymentLoadService::SAVED_PAYMENT_CREDIT_CARD . "%'" + . " OR transactionAfterOrder.PAYMENTTYPEID LIKE 's-" + . SavedPaymentLoadService::SAVED_PAYMENT_SEPA_DIRECT_DEBIT . "%'"; + + $this->assertEquals($expected, $result); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentLoadFilterService::getPaymentTypeIdLikeExpression + */ + public function testGetPaymentTypeIdLikeExpressionValidMethodSpecific() + { + $method = SavedPaymentLoadService::SAVED_PAYMENT_PAYPAL; + + $this->savedPaymentMethodValidator + ->method('validate') + ->with($method) + ->willReturn(true); + + $result = $this->filterService->getPaymentTypeIdLikeExpression($method); + + $expected = "transactionAfterOrder.PAYMENTTYPEID LIKE 's-{$method}%'"; + + $this->assertEquals($expected, $result); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentLoadFilterService::getPaymentTypeIdLikeExpression + */ + public function testGetPaymentTypeIdLikeExpressionInvalidMethod() + { + $invalidMethod = 'invalid_method'; + + $this->savedPaymentMethodValidator + ->method('validate') + ->with($invalidMethod) + ->willReturn(false); + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage( + "Invalid savedPaymentMethod SavedPaymentService::getLastSavedPaymentTransaction: $invalidMethod" + ); + + $this->filterService->getPaymentTypeIdLikeExpression($invalidMethod); + } +} diff --git a/tests/Unit/Service/SavedPayment/SavedPaymentLoadGroupServiceTest.php b/tests/Unit/Service/SavedPayment/SavedPaymentLoadGroupServiceTest.php new file mode 100644 index 00000000..8ef4bf93 --- /dev/null +++ b/tests/Unit/Service/SavedPayment/SavedPaymentLoadGroupServiceTest.php @@ -0,0 +1,94 @@ +groupService = new SavedPaymentLoadGroupService(); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentLoadGroupService::groupByPaymentTypeId + */ + public function testGroupByPaymentTypeId() + { + // Sample data + $ungroupedTransactions = [ + ['PAYMENTTYPEID' => 'card-123', 'OXID' => 'tx1', 'amount' => 100], + ['PAYMENTTYPEID' => 'card-123', 'OXID' => 'tx2', 'amount' => 200], + ['PAYMENTTYPEID' => 'paypal-456', 'OXID' => 'tx3', 'amount' => 300], + ['PAYMENTTYPEID' => 'sepa-789', 'OXID' => 'tx4', 'amount' => 400], + ]; + + // Expected output + $expectedGroupedTransactions = [ + ['PAYMENTTYPEID' => 'card-123', 'OXID' => 'tx2', 'amount' => 200], + ['PAYMENTTYPEID' => 'paypal-456', 'OXID' => 'tx3', 'amount' => 300], + ['PAYMENTTYPEID' => 'sepa-789', 'OXID' => 'tx4', 'amount' => 400], + ]; + + $result = $this->groupService->groupByPaymentTypeId($ungroupedTransactions); + + $this->assertEquals($expectedGroupedTransactions, $result); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentLoadGroupService::groupByPaymentTypeId + */ + public function testGroupByPaymentTypeIdEmptyArray() + { + $ungroupedTransactions = []; + + $expectedGroupedTransactions = []; + + $result = $this->groupService->groupByPaymentTypeId($ungroupedTransactions); + + $this->assertEquals($expectedGroupedTransactions, $result); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentLoadGroupService::groupByPaymentTypeId + */ + public function testGroupByPaymentTypeIdSingleGroup() + { + $ungroupedTransactions = [ + ['PAYMENTTYPEID' => 'card-123', 'OXID' => 'tx1', 'amount' => 100], + ]; + + $expectedGroupedTransactions = [ + ['PAYMENTTYPEID' => 'card-123', 'OXID' => 'tx1', 'amount' => 100], + ]; + + $result = $this->groupService->groupByPaymentTypeId($ungroupedTransactions); + + $this->assertEquals($expectedGroupedTransactions, $result); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentLoadGroupService::groupByPaymentTypeId + */ + public function testGroupByPaymentTypeIdMultipleGroupsWithSameID() + { + $ungroupedTransactions = [ + ['PAYMENTTYPEID' => 'card-123', 'OXID' => 'tx1', 'amount' => 100], + ['PAYMENTTYPEID' => 'card-123', 'OXID' => 'tx2', 'amount' => 200], + ['PAYMENTTYPEID' => 'card-123', 'OXID' => 'tx3', 'amount' => 300], + ]; + + $expectedGroupedTransactions = [ + ['PAYMENTTYPEID' => 'card-123', 'OXID' => 'tx3', 'amount' => 300], + ]; + + $result = $this->groupService->groupByPaymentTypeId($ungroupedTransactions); + + $this->assertEquals($expectedGroupedTransactions, $result); + } +} diff --git a/tests/Unit/Service/SavedPayment/SavedPaymentMapperIntegrationTest.php b/tests/Unit/Service/SavedPayment/SavedPaymentMapperIntegrationTest.php new file mode 100644 index 00000000..6ee48f38 --- /dev/null +++ b/tests/Unit/Service/SavedPayment/SavedPaymentMapperIntegrationTest.php @@ -0,0 +1,241 @@ +validator = $this->createMock(SavedPaymentMethodValidator::class); + $this->mapper = new SavedPaymentMapper($this->validator); + } + + /** + * Test the grouping of payment types with various methods + * + * @dataProvider getTestData + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentMapper::groupPaymentTypes + */ + public function testGroupPaymentTypes($given, $expected) + { + // Mock the validator to always return true + $this->validator->method('validate')->willReturn(true); + + $result = $this->mapper->groupPaymentTypes($given); + + $this->assertEquals($expected, $result); + } + + public function getTestData(): array + { + return [ + $this->getTestData1(), + $this->getTestData2(), + $this->getTestData3(), + $this->getTestData4(), + ]; + } + + private function getTestData1(): array + { + return [ + [//given + 'paypal' => [ + 'user1@example.com' => ['email' => 'user1@example.com', 'other' => 'data'], + 'user2@example.com' => ['email' => 'user2@example.com', 'other' => 'data'], + ], + 'card' => [ + '1234567812345678|03/40' => [ + 'number' => '1234567812345678', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + '8765432187654321|03/40' => [ + 'number' => '8765432187654321', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + ], + 'sepa' => [ + 'DE89370400440532013000' => ['iban' => 'DE89370400440532013000', 'other' => 'data'], + 'DE89370400440532013001' => ['iban' => 'DE89370400440532013001', 'other' => 'data'], + ], + ], + [//result + 'paypal' => [ + 'user1@example.com' => ['email' => 'user1@example.com', 'other' => 'data'], + 'user2@example.com' => ['email' => 'user2@example.com', 'other' => 'data'], + ], + 'card' => [ + '1234567812345678|03/40' => [ + 'number' => '1234567812345678', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + '8765432187654321|03/40' => [ + 'number' => '8765432187654321', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + ], + 'sepa' => [ + 'DE89370400440532013000' => ['iban' => 'DE89370400440532013000', 'other' => 'data'], + 'DE89370400440532013001' => ['iban' => 'DE89370400440532013001', 'other' => 'data'], + ], + ] + ]; + } + + private function getTestData2(): array + { + return [ + [//given + 'paypal' => [ + 'user1@example.com' => ['email' => 'user1@example.com', 'other' => 'data'], + 'user1@example.com' => ['email' => 'user1@example.com', 'other' => 'data'], + ], + 'card' => [ + '1234567812345678|03/40' => [ + 'number' => '1234567812345678', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + '8765432187654321|03/40' => [ + 'number' => '8765432187654321', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + ], + 'sepa' => [ + 'DE89370400440532013000' => ['iban' => 'DE89370400440532013000', 'other' => 'data'], + 'DE89370400440532013001' => ['iban' => 'DE89370400440532013001', 'other' => 'data'], + ], + ], + [//result + 'paypal' => [ + 'user1@example.com' => ['email' => 'user1@example.com', 'other' => 'data'], + ], + 'card' => [ + '1234567812345678|03/40' => [ + 'number' => '1234567812345678', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + '8765432187654321|03/40' => [ + 'number' => '8765432187654321', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + ], + 'sepa' => [ + 'DE89370400440532013000' => ['iban' => 'DE89370400440532013000', 'other' => 'data'], + 'DE89370400440532013001' => ['iban' => 'DE89370400440532013001', 'other' => 'data'], + ], + ] + ]; + } + + private function getTestData3(): array + { + return [ + [//given + 'paypal' => [ + 'user1@example.com' => ['email' => 'user1@example.com', 'other' => 'data'], + 'user2@example.com' => ['email' => 'user2@example.com', 'other' => 'data'], + ], + 'card' => [ + '1234567812345678|03/40' => [ + 'number' => '1234567812345678', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + '1234567812345678|03/40' => [ + 'number' => '1234567812345678', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + ], + 'sepa' => [ + 'DE89370400440532013000' => ['iban' => 'DE89370400440532013000', 'other' => 'data'], + 'DE89370400440532013001' => ['iban' => 'DE89370400440532013001', 'other' => 'data'], + ], + ], + [//result + 'paypal' => [ + 'user1@example.com' => ['email' => 'user1@example.com', 'other' => 'data'], + 'user2@example.com' => ['email' => 'user2@example.com', 'other' => 'data'], + ], + 'card' => [ + '1234567812345678|03/40' => [ + 'number' => '1234567812345678', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + ], + 'sepa' => [ + 'DE89370400440532013000' => ['iban' => 'DE89370400440532013000', 'other' => 'data'], + 'DE89370400440532013001' => ['iban' => 'DE89370400440532013001', 'other' => 'data'], + ], + ] + ]; + } + + private function getTestData4(): array + { + return [ + [//given + 'paypal' => [ + 'user1@example.com' => ['email' => 'user1@example.com', 'other' => 'data'], + 'user2@example.com' => ['email' => 'user2@example.com', 'other' => 'data'], + ], + 'card' => [ + '1234567812345678|03/40' => [ + 'number' => '1234567812345678', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + '8765432187654321|03/40' => [ + 'number' => '8765432187654321', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + ], + 'sepa' => [ + 'DE89370400440532013000' => ['iban' => 'DE89370400440532013000', 'other' => 'data'], + 'DE89370400440532013000' => ['iban' => 'DE89370400440532013000', 'other' => 'data'], + ], + ], + [//result + 'paypal' => [ + 'user1@example.com' => ['email' => 'user1@example.com', 'other' => 'data'], + 'user2@example.com' => ['email' => 'user2@example.com', 'other' => 'data'], + ], + 'card' => [ + '1234567812345678|03/40' => [ + 'number' => '1234567812345678', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + '8765432187654321|03/40' => [ + 'number' => '8765432187654321', + 'expiryDate' => '03/40', + 'other' => 'data' + ], + ], + 'sepa' => [ + 'DE89370400440532013000' => ['iban' => 'DE89370400440532013000', 'other' => 'data'], + ], + ] + ]; + } +} diff --git a/tests/Unit/Service/SavedPayment/SavedPaymentMethodValidatorTest.php b/tests/Unit/Service/SavedPayment/SavedPaymentMethodValidatorTest.php new file mode 100644 index 00000000..ceabf276 --- /dev/null +++ b/tests/Unit/Service/SavedPayment/SavedPaymentMethodValidatorTest.php @@ -0,0 +1,55 @@ +validator = new SavedPaymentMethodValidator(); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentMethodValidator::validate + */ + public function testValidateReturnsTrueForValidPaymentMethods() + { + $validMethods = [ + SavedPaymentLoadService::SAVED_PAYMENT_PAYPAL, + SavedPaymentLoadService::SAVED_PAYMENT_CREDIT_CARD, + SavedPaymentLoadService::SAVED_PAYMENT_SEPA_DIRECT_DEBIT, + SavedPaymentLoadService::SAVED_PAYMENT_ALL + ]; + + foreach ($validMethods as $method) { + $this->assertTrue($this->validator->validate($method), "Expected true for valid payment method: $method"); + } + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentMethodValidator::validate + */ + public function testValidateReturnsFalseForInvalidPaymentMethods() + { + $invalidMethods = [ + 'invalid', + 'unknown', + '123', + 'paypal', // Example of partial or non-matching string + ]; + + foreach ($invalidMethods as $method) { + $this->assertFalse( + $this->validator->validate($method), + "Expected false for invalid payment method: $method" + ); + } + } +} diff --git a/tests/Unit/Service/SavedPayment/SavedPaymentSessionServiceTest.php b/tests/Unit/Service/SavedPayment/SavedPaymentSessionServiceTest.php new file mode 100644 index 00000000..ebefbaba --- /dev/null +++ b/tests/Unit/Service/SavedPayment/SavedPaymentSessionServiceTest.php @@ -0,0 +1,86 @@ +sessionMock = $this->createMock(Session::class); + $this->requestServiceMock = $this->createMock(RequestService::class); + + $this->savedPaymentSessionService = new SavedPaymentSessionService( + $this->sessionMock, + $this->requestServiceMock + ); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentSessionService::isSavedPayment + */ + public function testIsSavedPaymentReturnsTrueWhenSessionVariableIsTrue() + { + $sessionVariableName = SavedPaymentSessionService::class . '_userClickedSavePaymentCheckbox'; + $this->sessionMock->method('getVariable') + ->with($sessionVariableName) + ->willReturn(true); + + $result = $this->savedPaymentSessionService->isSavedPayment(); + + $this->assertTrue($result); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentSessionService::isSavedPayment + */ + public function testIsSavedPaymentReturnsFalseWhenSessionVariableIsFalse() + { + $sessionVariableName = SavedPaymentSessionService::class . '_userClickedSavePaymentCheckbox'; + $this->sessionMock->method('getVariable') + ->with($sessionVariableName) + ->willReturn(false); + + $result = $this->savedPaymentSessionService->isSavedPayment(); + + $this->assertFalse($result); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentSessionService::setSavedPayment + */ + public function testSetSavedPaymentSetsSessionVariableCorrectly() + { + $sessionVariableName = SavedPaymentSessionService::class . '_userClickedSavePaymentCheckbox'; + $this->requestServiceMock->method('isSavePaymentSelectedByUserInRequest') + ->willReturn(true); + + $this->sessionMock->expects($this->once()) + ->method('setVariable') + ->with($sessionVariableName, true); + + $this->savedPaymentSessionService->setSavedPayment(); + } + + /** + * @covers \OxidSolutionCatalysts\Unzer\Service\SavedPayment\SavedPaymentSessionService::unsetSavedPayment + */ + public function testUnsetSavedPaymentDeletesSessionVariableCorrectly() + { + $sessionVariableName = SavedPaymentSessionService::class . '_userClickedSavePaymentCheckbox'; + + $this->sessionMock->expects($this->once()) + ->method('deleteVariable') + ->with($sessionVariableName); + + $this->savedPaymentSessionService->unsetSavedPayment(); + } +} diff --git a/tests/Unit/Service/SavedPayment/UserIdServiceTest.php b/tests/Unit/Service/SavedPayment/UserIdServiceTest.php new file mode 100644 index 00000000..7c97b9ea --- /dev/null +++ b/tests/Unit/Service/SavedPayment/UserIdServiceTest.php @@ -0,0 +1,79 @@ +createMock(Paypal::class); + $paypal->method('getEmail')->willReturn('test@example.com'); + + $userIdService = new UserIdService(); + $result = $userIdService->getUserIdByPaymentType($paypal); + + $this->assertSame('test@example.com', $result); + } + + public function testGetUserIdByPaypalWithNullEmail() + { + $paypal = $this->createMock(Paypal::class); + $paypal->method('getEmail')->willReturn(null); + + $userIdService = new UserIdService(); + $result = $userIdService->getUserIdByPaymentType($paypal); + + $this->assertSame('', $result); + } + + public function testGetUserIdByCard() + { + $card = $this->createMock(Card::class); + $card->method('getNumber')->willReturn('1234567890123456'); + $card->method('getExpiryDate')->willReturn('12/34'); + + $userIdService = new UserIdService(); + $result = $userIdService->getUserIdByPaymentType($card); + + $this->assertSame('1234567890123456|12/34', $result); + } + + public function testGetUserIdBySepaDirectDebit() + { + $sepa = $this->createMock(SepaDirectDebit::class); + $sepa->method('getIban')->willReturn('DE89370400440532013000'); + + $userIdService = new UserIdService(); + $result = $userIdService->getUserIdByPaymentType($sepa); + + $this->assertSame('DE89370400440532013000', $result); + } + + public function testGetUserIdBySepaDirectDebitWithNullIban() + { + $sepa = $this->createMock(SepaDirectDebit::class); + $sepa->method('getIban')->willReturn(null); + + $userIdService = new UserIdService(); + $result = $userIdService->getUserIdByPaymentType($sepa); + + $this->assertSame('', $result); + } + + public function testInvalidPaymentTypeReturnsEmptyString() + { + $invalidPaymentType = $this->createMock(BasePaymentType::class); + + $userIdService = new UserIdService(); + + $this->assertEmpty($userIdService->getUserIdByPaymentType($invalidPaymentType)); + } +} diff --git a/tests/Unit/Service/SavedPaymentLoadServiceTest.php b/tests/Unit/Service/SavedPaymentLoadServiceTest.php new file mode 100644 index 00000000..202ec0c3 --- /dev/null +++ b/tests/Unit/Service/SavedPaymentLoadServiceTest.php @@ -0,0 +1,211 @@ +queryBuilder = $this->createMock(QueryBuilder::class); + $this->queryBuilderFactory = $this->createMock(QueryBuilderFactoryInterface::class); + $this->queryBuilderFactory->method('create')->willReturn($this->queryBuilder); + + $this->savedPaymentMethodValidator = $this->createMock(SavedPaymentMethodValidator::class); + $this->savedPaymentLoadFilterService = $this->createMock(SavedPaymentLoadFilterService::class); + $this->savedPaymentLoadGroupService = $this->createMock(SavedPaymentLoadGroupService::class); + + $this->savedPaymentLoadService = new SavedPaymentLoadService( + $this->queryBuilderFactory, + $this->savedPaymentMethodValidator, + $this->savedPaymentLoadFilterService, + $this->savedPaymentLoadGroupService + ); + } + + public function testGetSavedPaymentTransactionsValidMethod() + { + $oxUserId = 'user123'; + $savedPaymentMethod = SavedPaymentLoadService::SAVED_PAYMENT_CREDIT_CARD; + + $this->savedPaymentMethodValidator + ->expects($this->once()) + ->method('validate') + ->with($savedPaymentMethod) + ->willReturn(true); + + $this->savedPaymentLoadFilterService + ->expects($this->once()) + ->method('getPaymentTypeIdLikeExpression') + ->with($savedPaymentMethod) + ->willReturn("transactionAfterOrder.PAYMENTTYPEID LIKE 's-crd%'"); + + $this->queryBuilder + ->expects($this->once()) + ->method('select') + ->with('*') + ->willReturnSelf(); + + $this->queryBuilder + ->expects($this->once()) + ->method('from') + ->with('transactionAfterOrder') + ->willReturnSelf(); + + $this->queryBuilder + ->expects($this->once()) + ->method('where') + ->with('OXUSERID = :oxuserid') + ->willReturnSelf(); + + $this->queryBuilder + ->expects($this->once()) + ->method('setParameter') + ->with('oxuserid', $oxUserId) + ->willReturnSelf(); + + $this->queryBuilder + ->expects($this->once()) + ->method('andWhere') + ->with("transactionAfterOrder.PAYMENTTYPEID LIKE 's-crd%'") + ->willReturnSelf(); + + $this->queryBuilder + ->expects($this->once()) + ->method('orderBy') + ->with('OXACTIONDATE') + ->willReturnSelf(); + + $statement = $this->createMock(Result::class); + $statement->expects($this->once()) + ->method('fetchAllAssociative') + ->willReturn([ + [ + 'OXORDERID' => 'order1', + 'OXID' => 'txn1', + 'PAYMENTTYPEID' => 's-crd-123', + 'CURRENCY' => 'USD', + 'CUSTOMERTYPE' => 'B2C', + 'OXPAYMENTTYPE' => 'creditcard', + 'OXACTIONDATE' => '2024-08-01', + 'SAVEPAYMENT' => 1 + ] + ]); + + $this->queryBuilder + ->expects($this->once()) + ->method('executeQuery') + ->willReturn($statement); + + $this->savedPaymentLoadGroupService + ->expects($this->once()) + ->method('groupByPaymentTypeId') + ->willReturn([ + [ + 'OXORDERID' => 'order1', + 'OXID' => 'txn1', + 'PAYMENTTYPEID' => 's-crd-123', + 'CURRENCY' => 'USD', + 'CUSTOMERTYPE' => 'B2C', + 'OXPAYMENTTYPE' => 'creditcard', + 'OXACTIONDATE' => '2024-08-01', + 'SAVEPAYMENT' => 1 + ] + ]); + + $result = $this->savedPaymentLoadService->getSavedPaymentTransactions($oxUserId, $savedPaymentMethod); + + $expected = [ + [ + 'OXORDERID' => 'order1', + 'OXID' => 'txn1', + 'PAYMENTTYPEID' => 's-crd-123', + 'CURRENCY' => 'USD', + 'CUSTOMERTYPE' => 'B2C', + 'OXPAYMENTTYPE' => 'creditcard', + 'OXACTIONDATE' => '2024-08-01', + 'SAVEPAYMENT' => 1 + ] + ]; + + $this->assertEquals($expected, $result); + } + + public function testGetSavedPaymentTransactionsInvalidMethod() + { + $oxUserId = 'user123'; + $savedPaymentMethod = 'invalid'; + + $this->savedPaymentMethodValidator + ->expects($this->once()) + ->method('validate') + ->with($savedPaymentMethod) + ->willReturn(false); + + $this->expectException(\InvalidArgumentException::class); + + $this->savedPaymentLoadService->getSavedPaymentTransactions($oxUserId, $savedPaymentMethod); + } + + public function testGetSavedPaymentTransactionsByUserId() + { + $savedPaymentUserId = 'user123'; + + $this->queryBuilder + ->expects($this->once()) + ->method('select') + ->with('OXID') + ->willReturnSelf(); + + $this->queryBuilder + ->expects($this->once()) + ->method('from') + ->with('transactionAfterOrder') + ->willReturnSelf(); + + $this->queryBuilder + ->expects($this->once()) + ->method('where') + ->with('OXUSERID = :savedPaymentUserId') + ->willReturnSelf(); + + $this->queryBuilder + ->expects($this->once()) + ->method('setParameter') + ->with('savedPaymentUserId', $savedPaymentUserId) + ->willReturnSelf(); + + $statement = $this->createMock(Result::class); + $statement->expects($this->once()) + ->method('fetchAllAssociative') + ->willReturn([ + ['OXID' => 'txn1'], + ['OXID' => 'txn2'] + ]); + + $this->queryBuilder + ->expects($this->once()) + ->method('executeQuery') + ->willReturn($statement); + + $result = $this->savedPaymentLoadService->getSavedPaymentTransactionsByUserId($savedPaymentUserId); + + $this->assertEquals(['txn1', 'txn2'], $result); + } +} diff --git a/tests/Unit/Service/SavedPaymentSaveServiceTest.php b/tests/Unit/Service/SavedPaymentSaveServiceTest.php new file mode 100644 index 00000000..fa888ec5 --- /dev/null +++ b/tests/Unit/Service/SavedPaymentSaveServiceTest.php @@ -0,0 +1,125 @@ +queryBuilderMock = $this->getMockBuilder(QueryBuilder::class) + ->disableOriginalConstructor() + ->onlyMethods([ + 'update', + 'set', + 'where', + 'setParameter', + 'executeStatement', + ]) + ->getMock(); + + $this->queryBuilderFactoryMock = $this->createMock(QueryBuilderFactoryInterface::class); + $this->queryBuilderFactoryMock->method('create')->willReturn($this->queryBuilderMock); + + $this->userIdServiceMock = $this->createMock(UserIdService::class); + $this->sessionServiceMock = $this->createMock(SavedPaymentSessionService::class); + $this->resultMock = $this->createMock(Result::class); + + $this->savedPaymentSaveService = new SavedPaymentSaveService( + $this->queryBuilderFactoryMock, + $this->userIdServiceMock, + $this->sessionServiceMock + ); + } + + public function testGetTransactionParametersWhenSavedPaymentIsTrue(): void + { + $paymentMock = $this->createMock(Payment::class); + $paymentTypeMock = $this->createMock(BasePaymentType::class); + + $this->sessionServiceMock->method('isSavedPayment')->willReturn(true); + $paymentMock->method('getPaymentType')->willReturn($paymentTypeMock); + $this->userIdServiceMock->method('getUserIdByPaymentType')->with($paymentTypeMock)->willReturn('user123'); + + $result = $this->savedPaymentSaveService->getTransactionParameters($paymentMock); + + $this->assertSame([ + 'savepaymentuserid' => 'user123', + 'savepayment' => '1', + ], $result); + } + + public function testGetTransactionParametersWhenSavedPaymentIsFalse(): void + { + $paymentMock = $this->createMock(Payment::class); + + $this->sessionServiceMock->method('isSavedPayment')->willReturn(false); + + $result = $this->savedPaymentSaveService->getTransactionParameters($paymentMock); + + $this->assertSame([], $result); + } + + public function testUnsetSavedPayments(): void + { + $transactionIds = ['tx1', 'tx2', 'tx3']; + + $this->queryBuilderMock->expects($this->once()) + ->method('update') + ->with('oscunzertransaction') + ->willReturnSelf(); + + $this->queryBuilderMock->expects($this->once()) + ->method('set') + ->with('SAVEPAYMENT', 0) + ->willReturnSelf(); + + $this->queryBuilderMock->expects($this->once()) + ->method('where') + ->willReturnSelf(); + + $this->queryBuilderMock->expects($this->once()) + ->method('setParameter') + ->with('transactionIds', $transactionIds, \Doctrine\DBAL\Connection::PARAM_STR_ARRAY) + ->willReturnSelf(); + + $this->queryBuilderMock->expects($this->once()) + ->method('executeStatement') + ->willReturn(3); + + $result = $this->savedPaymentSaveService->unsetSavedPayments($transactionIds); + + $this->assertTrue($result); + } + + public function testUnsetSavedPaymentsReturnsFalseWhenNoRowsAffected(): void + { + $transactionIds = ['tx1', 'tx2', 'tx3']; + + $this->queryBuilderMock->expects($this->once()) + ->method('executeStatement') + ->willReturn(0); + + $result = $this->savedPaymentSaveService->unsetSavedPayments($transactionIds); + + $this->assertFalse($result); + } +}