TransactionResponseValidator.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. declare(strict_types=1);
  7. namespace Magento\AuthorizenetAcceptjs\Gateway\Validator;
  8. use Magento\AuthorizenetAcceptjs\Gateway\SubjectReader;
  9. use Magento\Payment\Gateway\Validator\AbstractValidator;
  10. use Magento\Payment\Gateway\Validator\ResultInterface;
  11. use Magento\Payment\Gateway\Validator\ResultInterfaceFactory;
  12. /**
  13. * Validates the status of an attempted transaction
  14. */
  15. class TransactionResponseValidator extends AbstractValidator
  16. {
  17. private const RESPONSE_CODE_APPROVED = 1;
  18. private const RESPONSE_CODE_HELD = 4;
  19. private const RESPONSE_REASON_CODE_APPROVED = 1;
  20. private const RESPONSE_REASON_CODE_PENDING_REVIEW_AUTHORIZED = 252;
  21. private const RESPONSE_REASON_CODE_PENDING_REVIEW = 253;
  22. /**
  23. * @var SubjectReader
  24. */
  25. private $subjectReader;
  26. /**
  27. * @param ResultInterfaceFactory $resultFactory
  28. * @param SubjectReader $subjectReader
  29. */
  30. public function __construct(ResultInterfaceFactory $resultFactory, SubjectReader $subjectReader)
  31. {
  32. parent::__construct($resultFactory);
  33. $this->subjectReader = $subjectReader;
  34. }
  35. /**
  36. * @inheritdoc
  37. */
  38. public function validate(array $validationSubject): ResultInterface
  39. {
  40. $response = $this->subjectReader->readResponse($validationSubject);
  41. $transactionResponse = $response['transactionResponse'];
  42. if ($this->isResponseCodeAnError($transactionResponse)) {
  43. $errorCodes = [];
  44. $errorMessages = [];
  45. if (isset($transactionResponse['messages']['message']['code'])) {
  46. $errorCodes[] = $transactionResponse['messages']['message']['code'];
  47. $errorMessages[] = $transactionResponse['messages']['message']['text'];
  48. } elseif ($transactionResponse['messages']['message']) {
  49. foreach ($transactionResponse['messages']['message'] as $message) {
  50. $errorCodes[] = $message['code'];
  51. $errorMessages[] = $message['description'];
  52. }
  53. } elseif (isset($transactionResponse['errors'])) {
  54. foreach ($transactionResponse['errors'] as $message) {
  55. $errorCodes[] = $message['errorCode'];
  56. $errorMessages[] = $message['errorCode'];
  57. }
  58. }
  59. return $this->createResult(false, $errorMessages, $errorCodes);
  60. }
  61. return $this->createResult(true);
  62. }
  63. /**
  64. * Determines if the response code is actually an error
  65. *
  66. * @param array $transactionResponse
  67. * @return bool
  68. */
  69. private function isResponseCodeAnError(array $transactionResponse): bool
  70. {
  71. $code = $transactionResponse['messages']['message']['code']
  72. ?? $transactionResponse['messages']['message'][0]['code']
  73. ?? $transactionResponse['errors'][0]['errorCode']
  74. ?? null;
  75. return in_array($transactionResponse['responseCode'], [self::RESPONSE_CODE_APPROVED, self::RESPONSE_CODE_HELD])
  76. && $code
  77. && !in_array(
  78. $code,
  79. [
  80. self::RESPONSE_REASON_CODE_APPROVED,
  81. self::RESPONSE_REASON_CODE_PENDING_REVIEW,
  82. self::RESPONSE_REASON_CODE_PENDING_REVIEW_AUTHORIZED
  83. ]
  84. );
  85. }
  86. }