CancelResponseValidator.php 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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\Braintree\Gateway\Validator;
  8. use Braintree\Error\ErrorCollection;
  9. use Braintree\Error\Validation;
  10. use Magento\Payment\Gateway\Validator\AbstractValidator;
  11. use Magento\Payment\Gateway\Validator\ResultInterface;
  12. use Magento\Payment\Gateway\Validator\ResultInterfaceFactory;
  13. use Magento\Braintree\Gateway\SubjectReader;
  14. /**
  15. * Decorates the general response validator to handle specific cases.
  16. *
  17. * This validator decorates the general response validator to handle specific cases like
  18. * an expired or already voided on Braintree side authorization transaction.
  19. */
  20. class CancelResponseValidator extends AbstractValidator
  21. {
  22. /**
  23. * @var int
  24. */
  25. private static $acceptableTransactionCode = 91504;
  26. /**
  27. * @var GeneralResponseValidator
  28. */
  29. private $generalResponseValidator;
  30. /**
  31. * @var SubjectReader
  32. */
  33. private $subjectReader;
  34. /**
  35. * @param ResultInterfaceFactory $resultFactory
  36. * @param GeneralResponseValidator $generalResponseValidator
  37. * @param SubjectReader $subjectReader
  38. */
  39. public function __construct(
  40. ResultInterfaceFactory $resultFactory,
  41. GeneralResponseValidator $generalResponseValidator,
  42. SubjectReader $subjectReader
  43. ) {
  44. parent::__construct($resultFactory);
  45. $this->generalResponseValidator = $generalResponseValidator;
  46. $this->subjectReader = $subjectReader;
  47. }
  48. /**
  49. * @inheritdoc
  50. */
  51. public function validate(array $validationSubject): ResultInterface
  52. {
  53. $result = $this->generalResponseValidator->validate($validationSubject);
  54. if (!$result->isValid()) {
  55. $response = $this->subjectReader->readResponseObject($validationSubject);
  56. if ($this->isErrorAcceptable($response->errors)) {
  57. $result = $this->createResult(true, [__('Transaction is cancelled offline.')]);
  58. }
  59. }
  60. return $result;
  61. }
  62. /**
  63. * Checks if error collection has an acceptable error code.
  64. *
  65. * @param ErrorCollection $errorCollection
  66. * @return bool
  67. */
  68. private function isErrorAcceptable(ErrorCollection $errorCollection): bool
  69. {
  70. $errors = $errorCollection->deepAll();
  71. // there is should be only one acceptable error
  72. if (count($errors) > 1) {
  73. return false;
  74. }
  75. /** @var Validation $error */
  76. $error = array_pop($errors);
  77. return (int)$error->code === self::$acceptableTransactionCode;
  78. }
  79. }