Skip to content

Commit

Permalink
Merge pull request #4199 from magento-tango/PR-2.2-ALL
Browse files Browse the repository at this point in the history
[TANGO] PR-2.2-ALL
  • Loading branch information
dhorytskyi authored May 15, 2019
2 parents 0175f09 + ba0c6d7 commit 5efaca9
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 17 deletions.
22 changes: 20 additions & 2 deletions app/code/Magento/Paypal/Model/Express.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
use Magento\Store\Model\ScopeInterface;

/**
* PayPal Express Module
* PayPal Express Module.
*
* @method \Magento\Quote\Api\Data\PaymentMethodExtensionInterface getExtensionAttributes()
* @SuppressWarnings(PHPMD.TooManyFields)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
*/
class Express extends \Magento\Payment\Model\Method\AbstractMethod
{
Expand Down Expand Up @@ -179,6 +181,11 @@ class Express extends \Magento\Payment\Model\Method\AbstractMethod
*/
protected $transactionBuilder;

/**
* @var string
*/
private static $authorizationExpiredCode = 10601;

/**
* @param \Magento\Framework\Model\Context $context
* @param \Magento\Framework\Registry $registry
Expand Down Expand Up @@ -269,6 +276,7 @@ protected function _setApiProcessableErrors()
ApiProcessableException::API_MAXIMUM_AMOUNT_FILTER_DECLINE,
ApiProcessableException::API_OTHER_FILTER_DECLINE,
ApiProcessableException::API_ADDRESS_MATCH_FAIL,
self::$authorizationExpiredCode
]
);
}
Expand Down Expand Up @@ -538,7 +546,17 @@ public function refund(\Magento\Payment\Model\InfoInterface $payment, $amount)
*/
public function cancel(\Magento\Payment\Model\InfoInterface $payment)
{
$this->void($payment);
try {
$this->void($payment);
} catch (ApiProcessableException $e) {
if ((int)$e->getCode() === self::$authorizationExpiredCode) {
$payment->setTransactionId(null);
$payment->setIsTransactionClosed(true);
$payment->setShouldCloseParentTransaction(true);
} else {
throw $e;
}
}

return $this;
}
Expand Down
22 changes: 13 additions & 9 deletions app/code/Magento/Paypal/Model/Pro.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@

use Magento\Paypal\Model\Api\AbstractApi;
use Magento\Sales\Api\TransactionRepositoryInterface;
use Magento\Paypal\Model\Info;

/**
* PayPal Website Payments Pro implementation for payment method instances
* PayPal Website Payments Pro implementation for payment method instances.
*
* This model was created because right now PayPal Direct and PayPal Express payment methods cannot have same abstract
*/
class Pro
Expand Down Expand Up @@ -149,7 +149,8 @@ public function getConfig()
}

/**
* API instance getter
* API instance getter.
*
* Sets current store id to current config instance and passes it to API
*
* @return \Magento\Paypal\Model\Api\Nvp
Expand Down Expand Up @@ -231,19 +232,22 @@ public function importPaymentInfo(\Magento\Framework\DataObject $from, \Magento\
public function void(\Magento\Framework\DataObject $payment)
{
$authTransactionId = $this->_getParentTransactionId($payment);
if ($authTransactionId) {
$api = $this->getApi();
$api->setPayment($payment)->setAuthorizationId($authTransactionId)->callDoVoid();
$this->importPaymentInfo($api, $payment);
} else {
if (empty($authTransactionId)) {
throw new \Magento\Framework\Exception\LocalizedException(
__('You need an authorization transaction to void.')
);
}

$api = $this->getApi();
$api->setPayment($payment);
$api->setAuthorizationId($authTransactionId);
$api->callDoVoid();
$this->importPaymentInfo($api, $payment);
}

/**
* Attempt to capture payment
* Attempt to capture payment.
*
* Will return false if the payment is not supposed to be captured
*
* @param \Magento\Framework\DataObject $payment
Expand Down
52 changes: 47 additions & 5 deletions app/code/Magento/Paypal/Test/Unit/Model/ExpressTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,31 @@
use Magento\Payment\Model\InfoInterface;
use Magento\Payment\Observer\AbstractDataAssignObserver;
use Magento\Paypal\Model\Api\Nvp;
use Magento\Paypal\Model\Api\ProcessableException;
use Magento\Paypal\Model\Api\ProcessableException as ApiProcessableException;
use Magento\Paypal\Model\Express;
use Magento\Paypal\Model\Pro;
use Magento\Quote\Api\Data\PaymentInterface;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\Payment;
use Magento\Sales\Model\Order\Payment\Transaction\BuilderInterface;
use \PHPUnit_Framework_MockObject_MockObject as MockObject;
use PHPUnit_Framework_MockObject_MockObject as MockObject;

/**
* Class ExpressTest
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*/
class ExpressTest extends \PHPUnit\Framework\TestCase
{
/**
* @var string
*/
private static $authorizationExpiredCode = 10601;

/**
* @var array
*/
protected $errorCodes = [
private $errorCodes = [
ApiProcessableException::API_INTERNAL_ERROR,
ApiProcessableException::API_UNABLE_PROCESS_PAYMENT_ERROR_CODE,
ApiProcessableException::API_DO_EXPRESS_CHECKOUT_FAIL,
Expand All @@ -40,7 +46,7 @@ class ExpressTest extends \PHPUnit\Framework\TestCase
ApiProcessableException::API_COUNTRY_FILTER_DECLINE,
ApiProcessableException::API_MAXIMUM_AMOUNT_FILTER_DECLINE,
ApiProcessableException::API_OTHER_FILTER_DECLINE,
ApiProcessableException::API_ADDRESS_MATCH_FAIL
ApiProcessableException::API_ADDRESS_MATCH_FAIL,
];

/**
Expand Down Expand Up @@ -80,6 +86,7 @@ class ExpressTest extends \PHPUnit\Framework\TestCase

protected function setUp()
{
$this->errorCodes[] = self::$authorizationExpiredCode;
$this->checkoutSession = $this->createPartialMock(
Session::class,
['getPaypalTransactionData', 'setPaypalTransactionData']
Expand All @@ -104,16 +111,20 @@ protected function setUp()
);
$this->pro = $this->createPartialMock(
Pro::class,
['setMethod', 'getApi', 'importPaymentInfo', 'resetApi']
['setMethod', 'getApi', 'importPaymentInfo', 'resetApi', 'void']
);
$this->eventManager = $this->getMockBuilder(ManagerInterface::class)
->setMethods(['dispatch'])
->getMockForAbstractClass();

$this->pro->expects($this->any())->method('getApi')->will($this->returnValue($this->nvp));
$this->pro->method('getApi')
->willReturn($this->nvp);
$this->helper = new ObjectManager($this);
}

/**
* Tests setting the list of processable errors.
*/
public function testSetApiProcessableErrors()
{
$this->nvp->expects($this->once())->method('setProcessableErrors')->with($this->errorCodes);
Expand All @@ -128,6 +139,32 @@ public function testSetApiProcessableErrors()
);
}

/**
* Tests canceling order payment when expired authorization generates exception on a client.
*/
public function testCancelWithExpiredAuthorizationTransaction()
{
$this->pro->method('void')
->willThrowException(
new ProcessableException(__('PayPal gateway has rejected request.'), null, 10601)
);

$this->model = $this->helper->getObject(Express::class, ['data' => [$this->pro]]);
/** @var Payment|MockObject $paymentModel */
$paymentModel = $this->createMock(Payment::class);
$paymentModel->expects($this->once())
->method('setTransactionId')
->with(null);
$paymentModel->expects($this->once())
->method('setIsTransactionClosed')
->with(true);
$paymentModel->expects($this->once())
->method('setShouldCloseParentTransaction')
->with(true);

$this->model->cancel($paymentModel);
}

/**
* Tests order payment action.
*/
Expand Down Expand Up @@ -162,6 +199,11 @@ public function testOrder()
static::assertEquals($this->model, $this->model->order($paymentModel, 12.3));
}

/**
* Tests data assigning.
*
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function testAssignData()
{
$transportValue = 'something';
Expand Down
13 changes: 12 additions & 1 deletion lib/web/mage/trim-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,20 @@ define([
* @private
*/
_trimInput: function () {
var input = this._getInputValue().trim();
// Safari caret position workaround: storing carter position
var caretStart, caretEnd, input;

caretStart = this.options.cache.input.get(0).selectionStart;
caretEnd = this.options.cache.input.get(0).selectionEnd;

input = this._getInputValue().trim();

this.options.cache.input.val(input);

// Safari caret position workaround: setting caret position to previously stored values
if (caretStart !== null && caretEnd !== null) {
this.options.cache.input.get(0).setSelectionRange(caretStart, caretEnd);
}
},

/**
Expand Down

0 comments on commit 5efaca9

Please sign in to comment.