AmazonAuthCommand.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Amazon\Payment\Gateway\Command;
  7. use Magento\Payment\Gateway\CommandInterface;
  8. use Magento\Payment\Gateway\ErrorMapper\ErrorMessageMapperInterface;
  9. use Magento\Payment\Gateway\Http\ClientInterface;
  10. use Magento\Payment\Gateway\Http\TransferFactoryInterface;
  11. use Magento\Payment\Gateway\Request\BuilderInterface;
  12. use Magento\Payment\Gateway\Response\HandlerInterface;
  13. use Magento\Payment\Gateway\Validator\ResultInterface;
  14. use Magento\Payment\Gateway\Validator\ValidatorInterface;
  15. use Psr\Log\LoggerInterface;
  16. use Magento\Framework\Exception\LocalizedException;
  17. use Magento\Framework\Event\ManagerInterface;
  18. use Amazon\Core\Exception\AmazonWebapiException;
  19. use Amazon\Payment\Gateway\Config\Config;
  20. /**
  21. * Class AmazonAuthCommand
  22. *
  23. * Enables customized error handling for Amazon Payment
  24. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  25. */
  26. class AmazonAuthCommand implements CommandInterface
  27. {
  28. /**
  29. * @var BuilderInterface
  30. */
  31. private $requestBuilder;
  32. /**
  33. * @var TransferFactoryInterface
  34. */
  35. private $transferFactory;
  36. /**
  37. * @var ClientInterface
  38. */
  39. private $client;
  40. /**
  41. * @var HandlerInterface
  42. */
  43. private $handler;
  44. /**
  45. * @var ValidatorInterface
  46. */
  47. private $validator;
  48. /**
  49. * @var LoggerInterface
  50. */
  51. private $logger;
  52. /**
  53. * @var ErrorMessageMapperInterface
  54. */
  55. private $errorMessageMapper;
  56. /**
  57. * @var Config
  58. */
  59. private $config;
  60. /**
  61. * @param BuilderInterface $requestBuilder
  62. * @param TransferFactoryInterface $transferFactory
  63. * @param ClientInterface $client
  64. * @param LoggerInterface $logger
  65. * @param HandlerInterface $handler
  66. * @param ValidatorInterface $validator
  67. * @param ErrorMessageMapperInterface|null $errorMessageMapper
  68. * @param Config $config
  69. */
  70. public function __construct(
  71. BuilderInterface $requestBuilder,
  72. TransferFactoryInterface $transferFactory,
  73. ClientInterface $client,
  74. LoggerInterface $logger,
  75. HandlerInterface $handler = null,
  76. ValidatorInterface $validator = null,
  77. ErrorMessageMapperInterface $errorMessageMapper = null,
  78. Config $config
  79. ) {
  80. $this->requestBuilder = $requestBuilder;
  81. $this->transferFactory = $transferFactory;
  82. $this->client = $client;
  83. $this->handler = $handler;
  84. $this->validator = $validator;
  85. $this->logger = $logger;
  86. $this->errorMessageMapper = $errorMessageMapper;
  87. $this->config = $config;
  88. }
  89. /**
  90. * Executes command basing on business object
  91. *
  92. * @param array $commandSubject
  93. * @return \Magento\Payment\Gateway\Command\ResultInterface|null|void
  94. * @throws AmazonWebapiException
  95. * @throws \Magento\Payment\Gateway\Http\ClientException
  96. * @throws \Magento\Payment\Gateway\Http\ConverterException
  97. */
  98. public function execute(array $commandSubject)
  99. {
  100. $isTimeout = 0;
  101. $transferO = $this->transferFactory->create(
  102. $this->requestBuilder->build($commandSubject)
  103. );
  104. $response = $this->client->placeRequest($transferO);
  105. if ($this->validator !== null) {
  106. $result = $this->validator->validate(
  107. array_merge($commandSubject, ['response' => $response])
  108. );
  109. if (!$result->isValid()) {
  110. // when Amazon Pay is set to receive asynchronous calls, we need to allow timeouts to pass validation and
  111. // flag the handler to save the order for later processing.
  112. $auth_mode = '';
  113. if (isset($response['auth_mode'])) {
  114. $auth_mode = $response['auth_mode'];
  115. }
  116. $isTimeout = $this->processErrors($result, $auth_mode);
  117. }
  118. }
  119. $response['timeout'] = $isTimeout;
  120. if ($isTimeout) {
  121. $response['status'] = true;
  122. }
  123. if ($this->handler) {
  124. $this->handler->handle(
  125. $commandSubject,
  126. $response
  127. );
  128. }
  129. }
  130. /**
  131. * Tries to map error messages from validation result and logs processed message.
  132. * Throws an exception with mapped message or default error.
  133. *
  134. * @throws AmazonWebapiException
  135. */
  136. private function processErrors(ResultInterface $result, $mode = '')
  137. {
  138. $isDecline = false;
  139. $isTimeout = false;
  140. $code = false;
  141. $messages = [];
  142. foreach ($result->getFailsDescription() as $failPhrase) {
  143. $message = (string)$failPhrase;
  144. if ($this->errorMessageMapper !== null) {
  145. $mapped = (string)$this->errorMessageMapper->getMessage($message);
  146. if (!empty($mapped) && !in_array($mapped, $messages)) {
  147. $messages[] = $mapped;
  148. }
  149. }
  150. $this->logger->critical('Payment Error: ' . $message . ': ' . $mapped);
  151. if ($message == 'AmazonRejected' || $message == 'TransactionTimedOut') {
  152. $code = (int)$this->config->getValue('hard_decline_code');
  153. $isDecline = true;
  154. } elseif ($message == 'InvalidPaymentMethod' || $message == 'Declined') {
  155. $code = (int)$this->config->getValue('soft_decline_code');
  156. }
  157. if ($mode == 'synchronous_possible' && $message == 'TransactionTimedOut') {
  158. $isTimeout = true;
  159. $isDecline = false;
  160. }
  161. }
  162. if ($isDecline) {
  163. $messages[] = __("You will be redirected to the cart shortly.");
  164. }
  165. if ($isTimeout) {
  166. return true;
  167. }
  168. throw new AmazonWebapiException(
  169. !empty($messages)
  170. ? __(implode(PHP_EOL, $messages))
  171. : __('Transaction has been declined. Please try again later.'),
  172. $code
  173. );
  174. return $false;
  175. }
  176. }