Skip to content

Commit 65186a2

Browse files
committed
Merge pull request #468 from magento-mpi/MAGETWO-50309
[MPI] Bugfix
2 parents 0a8053d + 98e40a9 commit 65186a2

File tree

3 files changed

+165
-17
lines changed

3 files changed

+165
-17
lines changed

app/code/Magento/Braintree/Gateway/Command/CaptureStrategyCommand.php

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
*/
66
namespace Magento\Braintree\Gateway\Command;
77

8+
use Braintree\Transaction;
9+
use Magento\Braintree\Model\Adapter\BraintreeAdapter;
10+
use Magento\Braintree\Model\Adapter\BraintreeSearchAdapter;
811
use Magento\Framework\Api\FilterBuilder;
912
use Magento\Framework\Api\SearchCriteriaBuilder;
1013
use Magento\Payment\Gateway\Command;
@@ -18,6 +21,7 @@
1821

1922
/**
2023
* Class CaptureStrategyCommand
24+
* @SuppressWarnings(PHPMD)
2125
*/
2226
class CaptureStrategyCommand implements CommandInterface
2327
{
@@ -36,11 +40,6 @@ class CaptureStrategyCommand implements CommandInterface
3640
*/
3741
const VAULT_CAPTURE = 'vault_capture';
3842

39-
/**
40-
* Braintree clone transaction command
41-
*/
42-
const CLONE_TRANSACTION = 'clone';
43-
4443
/**
4544
* @var CommandPoolInterface
4645
*/
@@ -66,6 +65,16 @@ class CaptureStrategyCommand implements CommandInterface
6665
*/
6766
private $subjectReader;
6867

68+
/**
69+
* @var BraintreeAdapter
70+
*/
71+
private $braintreeAdapter;
72+
73+
/**
74+
* @var BraintreeSearchAdapter
75+
*/
76+
private $braintreeSearchAdapter;
77+
6978
/**
7079
* Constructor
7180
*
@@ -74,19 +83,25 @@ class CaptureStrategyCommand implements CommandInterface
7483
* @param FilterBuilder $filterBuilder
7584
* @param SearchCriteriaBuilder $searchCriteriaBuilder
7685
* @param SubjectReader $subjectReader
86+
* @param BraintreeAdapter $braintreeAdapter
87+
* @param BraintreeSearchAdapter $braintreeSearchAdapter
7788
*/
7889
public function __construct(
7990
CommandPoolInterface $commandPool,
8091
TransactionRepositoryInterface $repository,
8192
FilterBuilder $filterBuilder,
8293
SearchCriteriaBuilder $searchCriteriaBuilder,
83-
SubjectReader $subjectReader
94+
SubjectReader $subjectReader,
95+
BraintreeAdapter $braintreeAdapter,
96+
BraintreeSearchAdapter $braintreeSearchAdapter
8497
) {
8598
$this->commandPool = $commandPool;
8699
$this->transactionRepository = $repository;
87100
$this->filterBuilder = $filterBuilder;
88101
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
89102
$this->subjectReader = $subjectReader;
103+
$this->braintreeAdapter = $braintreeAdapter;
104+
$this->braintreeSearchAdapter = $braintreeSearchAdapter;
90105
}
91106

92107
/**
@@ -102,7 +117,7 @@ public function execute(array $commandSubject)
102117
ContextHelper::assertOrderPayment($paymentInfo);
103118

104119
$command = $this->getCommand($paymentInfo);
105-
return $this->commandPool->get($command)->execute($commandSubject);
120+
$this->commandPool->get($command)->execute($commandSubject);
106121
}
107122

108123
/**
@@ -119,14 +134,30 @@ private function getCommand(OrderPaymentInterface $payment)
119134
}
120135

121136
// do capture for authorization transaction
122-
if (!$existsCapture) {
137+
if (!$existsCapture && !$this->isExpiredAuthorization($payment)) {
123138
return self::CAPTURE;
124139
}
125140

126141
// process capture for payment via Vault
127142
return self::VAULT_CAPTURE;
128143
}
129144

145+
/**
146+
* @param OrderPaymentInterface $payment
147+
* @return boolean
148+
*/
149+
private function isExpiredAuthorization(OrderPaymentInterface $payment)
150+
{
151+
$collection = $this->braintreeAdapter->search(
152+
[
153+
$this->braintreeSearchAdapter->id()->is($payment->getLastTransId()),
154+
$this->braintreeSearchAdapter->status()->is(Transaction::AUTHORIZATION_EXPIRED)
155+
]
156+
);
157+
158+
return $collection->maximumCount() > 0;
159+
}
160+
130161
/**
131162
* Check if capture transaction already exists
132163
*

app/code/Magento/Braintree/Test/Unit/Gateway/Command/CaptureStrategyCommandTest.php

Lines changed: 125 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
*/
66
namespace Magento\Braintree\Test\Unit\Gateway\Command;
77

8+
use Braintree\IsNode;
9+
use Braintree\MultipleValueNode;
10+
use Braintree\TextNode;
811
use Magento\Braintree\Gateway\Command\CaptureStrategyCommand;
912
use Magento\Braintree\Gateway\Helper\SubjectReader;
1013
use Magento\Framework\Api\FilterBuilder;
@@ -18,6 +21,8 @@
1821
use Magento\Sales\Model\Order\Payment;
1922
use Magento\Sales\Model\Order\Payment\Transaction;
2023
use Magento\Sales\Model\ResourceModel\Order\Payment\Transaction\CollectionFactory;
24+
use Magento\Braintree\Model\Adapter\BraintreeAdapter;
25+
use Magento\Braintree\Model\Adapter\BraintreeSearchAdapter;
2126

2227
/**
2328
* Class CaptureStrategyCommandTest
@@ -27,37 +32,37 @@
2732
class CaptureStrategyCommandTest extends \PHPUnit_Framework_TestCase
2833
{
2934
/**
30-
* @var \Magento\Braintree\Gateway\Command\CaptureStrategyCommand
35+
* @var CaptureStrategyCommand
3136
*/
3237
private $strategyCommand;
3338

3439
/**
35-
* @var \Magento\Payment\Gateway\Command\CommandPoolInterface|\PHPUnit_Framework_MockObject_MockObject
40+
* @var CommandPoolInterface|\PHPUnit_Framework_MockObject_MockObject
3641
*/
3742
private $commandPool;
3843

3944
/**
40-
* @var \Magento\Sales\Api\TransactionRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
45+
* @var TransactionRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
4146
*/
4247
private $transactionRepository;
4348

4449
/**
45-
* @var \Magento\Framework\Api\FilterBuilder|\PHPUnit_Framework_MockObject_MockObject
50+
* @var FilterBuilder|\PHPUnit_Framework_MockObject_MockObject
4651
*/
4752
private $filterBuilder;
4853

4954
/**
50-
* @var \Magento\Framework\Api\SearchCriteriaBuilder|\PHPUnit_Framework_MockObject_MockObject
55+
* @var SearchCriteriaBuilder|\PHPUnit_Framework_MockObject_MockObject
5156
*/
5257
private $searchCriteriaBuilder;
5358

5459
/**
55-
* @var \Magento\Sales\Model\Order\Payment|\PHPUnit_Framework_MockObject_MockObject
60+
* @var Payment|\PHPUnit_Framework_MockObject_MockObject
5661
*/
5762
private $payment;
5863

5964
/**
60-
* @var \Magento\Payment\Gateway\Command\GatewayCommand|\PHPUnit_Framework_MockObject_MockObject
65+
* @var GatewayCommand|\PHPUnit_Framework_MockObject_MockObject
6166
*/
6267
private $command;
6368

@@ -66,6 +71,16 @@ class CaptureStrategyCommandTest extends \PHPUnit_Framework_TestCase
6671
*/
6772
private $subjectReaderMock;
6873

74+
/**
75+
* @var BraintreeAdapter|\PHPUnit_Framework_MockObject_MockObject
76+
*/
77+
private $braintreeAdapter;
78+
79+
/**
80+
* @var BraintreeSearchAdapter
81+
*/
82+
private $braintreeSearchAdapter;
83+
6984
protected function setUp()
7085
{
7186
$this->commandPool = $this->getMockBuilder(CommandPoolInterface::class)
@@ -82,12 +97,19 @@ protected function setUp()
8297
$this->initFilterBuilderMock();
8398
$this->initSearchCriteriaBuilderMock();
8499

100+
$this->braintreeAdapter = $this->getMockBuilder(BraintreeAdapter::class)
101+
->disableOriginalConstructor()
102+
->getMock();
103+
$this->braintreeSearchAdapter = new BraintreeSearchAdapter();
104+
85105
$this->strategyCommand = new CaptureStrategyCommand(
86106
$this->commandPool,
87107
$this->transactionRepository,
88108
$this->filterBuilder,
89109
$this->searchCriteriaBuilder,
90-
$this->subjectReaderMock
110+
$this->subjectReaderMock,
111+
$this->braintreeAdapter,
112+
$this->braintreeSearchAdapter
91113
);
92114
}
93115

@@ -133,6 +155,7 @@ public function testCaptureExecute()
133155
{
134156
$paymentData = $this->getPaymentDataObjectMock();
135157
$subject['payment'] = $paymentData;
158+
$lastTransId = 'txnds';
136159

137160
$this->subjectReaderMock->expects(self::once())
138161
->method('readPayment')
@@ -142,6 +165,9 @@ public function testCaptureExecute()
142165
$this->payment->expects(static::once())
143166
->method('getAuthorizationTransaction')
144167
->willReturn(true);
168+
$this->payment->expects(static::once())
169+
->method('getLastTransId')
170+
->willReturn($lastTransId);
145171

146172
$this->payment->expects(static::once())
147173
->method('getId')
@@ -153,6 +179,12 @@ public function testCaptureExecute()
153179
->method('getTotalCount')
154180
->willReturn(0);
155181

182+
// authorization transaction was not expired
183+
$collection = $this->getNotExpiredExpectedCollection($lastTransId);
184+
$collection->expects(static::once())
185+
->method('maximumCount')
186+
->willReturn(0);
187+
156188
$this->commandPool->expects(static::once())
157189
->method('get')
158190
->with(CaptureStrategyCommand::CAPTURE)
@@ -161,6 +193,91 @@ public function testCaptureExecute()
161193
$this->strategyCommand->execute($subject);
162194
}
163195

196+
/**
197+
* @param string $lastTransactionId
198+
* @return \Braintree\ResourceCollection|\PHPUnit_Framework_MockObject_MockObject
199+
*/
200+
private function getNotExpiredExpectedCollection($lastTransactionId)
201+
{
202+
$isExpectations = [
203+
'id' => ['is' => $lastTransactionId],
204+
'status' => [\Braintree\Transaction::AUTHORIZATION_EXPIRED]
205+
];
206+
207+
$collection = $this->getMockBuilder(\Braintree\ResourceCollection::class)
208+
->disableOriginalConstructor()
209+
->getMock();
210+
211+
$this->braintreeAdapter->expects(static::once())
212+
->method('search')
213+
->with(
214+
static::callback(
215+
function (array $filters) use ($isExpectations) {
216+
foreach ($filters as $filter) {
217+
/** @var IsNode $filter */
218+
if (!isset($isExpectations[$filter->name])) {
219+
return false;
220+
}
221+
222+
if ($isExpectations[$filter->name] !== $filter->toParam()) {
223+
return false;
224+
}
225+
}
226+
227+
return true;
228+
}
229+
)
230+
)
231+
->willReturn($collection);
232+
233+
return $collection;
234+
}
235+
236+
/**
237+
* @covers \Magento\Braintree\Gateway\Command\CaptureStrategyCommand::execute
238+
*/
239+
public function testExpiredAuthorizationPerformVaultCaptureExecute()
240+
{
241+
$paymentData = $this->getPaymentDataObjectMock();
242+
$subject['payment'] = $paymentData;
243+
$lastTransId = 'txnds';
244+
245+
$this->subjectReaderMock->expects(self::once())
246+
->method('readPayment')
247+
->with($subject)
248+
->willReturn($paymentData);
249+
250+
$this->payment->expects(static::once())
251+
->method('getAuthorizationTransaction')
252+
->willReturn(true);
253+
$this->payment->expects(static::once())
254+
->method('getLastTransId')
255+
->willReturn($lastTransId);
256+
257+
$this->payment->expects(static::once())
258+
->method('getId')
259+
->willReturn(1);
260+
261+
$this->buildSearchCriteria();
262+
263+
$this->transactionRepository->expects(static::once())
264+
->method('getTotalCount')
265+
->willReturn(0);
266+
267+
// authorization transaction was expired
268+
$collection = $this->getNotExpiredExpectedCollection($lastTransId);
269+
$collection->expects(static::once())
270+
->method('maximumCount')
271+
->willReturn(1);
272+
273+
$this->commandPool->expects(static::once())
274+
->method('get')
275+
->with(CaptureStrategyCommand::VAULT_CAPTURE)
276+
->willReturn($this->command);
277+
278+
$this->strategyCommand->execute($subject);
279+
}
280+
164281
/**
165282
* @covers \Magento\Braintree\Gateway\Command\CaptureStrategyCommand::execute
166283
*/
@@ -204,7 +321,6 @@ private function getPaymentDataObjectMock()
204321
{
205322
$this->payment = $this->getMockBuilder(Payment::class)
206323
->disableOriginalConstructor()
207-
->setMethods(['getAuthorizationTransaction', 'getId', 'getExtensionAttributes'])
208324
->getMock();
209325

210326
$mock = $this->getMockBuilder(PaymentDataObject::class)

app/code/Magento/Paypal/i18n/en_US.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,3 +677,4 @@ User,User
677677
The PayPal Advertising Program has been shown to generate additional purchases as well as increase consumer's average purchase sizes by 15%
678678
or more. <a href=""https:/financing.paypal.com/ppfinportal/content/forrester"" target=""_blank"">See Details</a>.
679679
"
680+
"payflowpro","Payflow Pro"

0 commit comments

Comments
 (0)