Skip to content

Commit cc90c55

Browse files
author
Karpenko, Oleksandr
committed
Merge branch 'develop' of github.com:magento/magento2ce into PR
2 parents e7dc3ce + 903dcbb commit cc90c55

File tree

112 files changed

+4679
-605
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+4679
-605
lines changed

app/code/Magento/Braintree/Gateway/Response/RiskDataHandler.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ class RiskDataHandler implements HandlerInterface
2424
*/
2525
const RISK_DATA_DECISION = 'riskDataDecision';
2626

27+
/**
28+
* Risk data Review status
29+
*/
30+
private static $statusReview = 'Review';
31+
2732
/**
2833
* @var SubjectReader
2934
*/
@@ -62,5 +67,10 @@ public function handle(array $handlingSubject, array $response)
6267

6368
$payment->setAdditionalInformation(self::RISK_DATA_ID, $transaction->riskData->id);
6469
$payment->setAdditionalInformation(self::RISK_DATA_DECISION, $transaction->riskData->decision);
70+
71+
// mark payment as fraud
72+
if ($transaction->riskData->decision === self::$statusReview) {
73+
$payment->setIsFraudDetected(true);
74+
}
6575
}
6676
}

app/code/Magento/Braintree/Test/Unit/Gateway/Response/RiskDataHandlerTest.php

Lines changed: 57 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
*/
66
namespace Magento\Braintree\Test\Unit\Gateway\Response;
77

8-
use Braintree\RiskData;
98
use Braintree\Transaction;
10-
use Magento\Sales\Model\Order\Payment;
119
use Magento\Braintree\Gateway\Helper\SubjectReader;
1210
use Magento\Braintree\Gateway\Response\RiskDataHandler;
1311
use Magento\Payment\Gateway\Data\PaymentDataObjectInterface;
12+
use Magento\Sales\Model\Order\Payment;
13+
use PHPUnit_Framework_MockObject_MockObject as MockObject;
1414

1515
/**
1616
* Class RiskDataHandlerTest
@@ -25,99 +25,95 @@ class RiskDataHandlerTest extends \PHPUnit_Framework_TestCase
2525
private $riskDataHandler;
2626

2727
/**
28-
* @var SubjectReader|\PHPUnit_Framework_MockObject_MockObject
28+
* @var SubjectReader|MockObject
2929
*/
30-
private $subjectReaderMock;
30+
private $subjectReader;
3131

3232
/**
3333
* Set up
3434
*/
3535
protected function setUp()
3636
{
37-
$this->subjectReaderMock = $this->getMockBuilder(SubjectReader::class)
37+
$this->subjectReader = $this->getMockBuilder(SubjectReader::class)
3838
->disableOriginalConstructor()
39+
->setMethods(['readPayment', 'readTransaction'])
3940
->getMock();
4041

41-
$this->riskDataHandler = new RiskDataHandler($this->subjectReaderMock);
42+
$this->riskDataHandler = new RiskDataHandler($this->subjectReader);
4243
}
4344

4445
/**
45-
* Run test for handle method
46+
* Test for handle method
47+
* @covers \Magento\Braintree\Gateway\Response\RiskDataHandler::handle
48+
* @param string $riskDecision
49+
* @param boolean $isFraud
50+
* @dataProvider riskDataProvider
4651
*/
47-
public function testHandle()
52+
public function testHandle($riskDecision, $isFraud)
4853
{
49-
$paymentData = $this->getPaymentDataObjectMock();
50-
$transaction = $this->getBraintreeTransactionMock();
54+
/** @var Payment|MockObject $payment */
55+
$payment = $this->getMockBuilder(Payment::class)
56+
->disableOriginalConstructor()
57+
->setMethods(['setAdditionalInformation', 'setIsFraudDetected'])
58+
->getMock();
59+
/** @var PaymentDataObjectInterface|MockObject $paymentDO */
60+
$paymentDO = $this->getMock(PaymentDataObjectInterface::class);
61+
$paymentDO->expects(self::once())
62+
->method('getPayment')
63+
->willReturn($payment);
64+
65+
$transaction = Transaction::factory([
66+
'riskData' => [
67+
'id' => 'test-id',
68+
'decision' => $riskDecision
69+
]
70+
]);
5171

5272
$response = [
5373
'object' => $transaction
5474
];
5575
$handlingSubject = [
56-
'payment' =>$paymentData,
76+
'payment' => $paymentDO,
5777
];
5878

59-
$this->subjectReaderMock->expects(self::once())
79+
$this->subjectReader->expects(static::once())
6080
->method('readPayment')
6181
->with($handlingSubject)
62-
->willReturn($paymentData);
63-
$this->subjectReaderMock->expects(self::once())
82+
->willReturn($paymentDO);
83+
$this->subjectReader->expects(static::once())
6484
->method('readTransaction')
6585
->with($response)
6686
->willReturn($transaction);
6787

68-
$this->riskDataHandler->handle($handlingSubject, $response);
69-
}
70-
71-
/**
72-
* @return \PHPUnit_Framework_MockObject_MockObject
73-
*/
74-
private function getBraintreeTransactionMock()
75-
{
76-
$transaction = \Braintree\Transaction::factory([]);
77-
$transaction->_set(
78-
'riskData',
79-
RiskData::factory(
80-
[
81-
'id' => 'test-id',
82-
'decision' => 'test-decision',
83-
]
84-
)
85-
);
86-
87-
return $transaction;
88-
}
89-
90-
/**
91-
* @return \PHPUnit_Framework_MockObject_MockObject
92-
*/
93-
private function getPaymentDataObjectMock()
94-
{
95-
$mock = $this->getMockBuilder(PaymentDataObjectInterface::class)
96-
->getMockForAbstractClass();
88+
$payment->expects(static::at(0))
89+
->method('setAdditionalInformation')
90+
->with(RiskDataHandler::RISK_DATA_ID, 'test-id');
91+
$payment->expects(static::at(1))
92+
->method('setAdditionalInformation')
93+
->with(RiskDataHandler::RISK_DATA_DECISION, $riskDecision);
9794

98-
$mock->expects(static::once())
99-
->method('getPayment')
100-
->willReturn($this->getPaymentMock());
95+
if (!$isFraud) {
96+
$payment->expects(static::never())
97+
->method('setIsFraudDetected');
98+
} else {
99+
$payment->expects(static::once())
100+
->method('setIsFraudDetected')
101+
->with(true);
102+
}
101103

102-
return $mock;
104+
$this->riskDataHandler->handle($handlingSubject, $response);
103105
}
104106

105107
/**
106-
* @return \PHPUnit_Framework_MockObject_MockObject
108+
* Get list of variations to test fraud
109+
* @return array
107110
*/
108-
private function getPaymentMock()
111+
public function riskDataProvider()
109112
{
110-
$paymentMock = $this->getMockBuilder(Payment::class)
111-
->disableOriginalConstructor()
112-
->getMock();
113-
114-
$paymentMock->expects(self::at(0))
115-
->method('setAdditionalInformation')
116-
->with(RiskDataHandler::RISK_DATA_ID, 'test-id');
117-
$paymentMock->expects(self::at(1))
118-
->method('setAdditionalInformation')
119-
->with(RiskDataHandler::RISK_DATA_DECISION, 'test-decision');
120-
121-
return $paymentMock;
113+
return [
114+
['decision' => 'Not Evaluated', 'isFraud' => false],
115+
['decision' => 'Approve', 'isFraud' => false],
116+
['decision' => 'Review', 'isFraud' => true],
117+
];
122118
}
123119
}

app/code/Magento/Braintree/etc/adminhtml/system.xml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,14 @@
88
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
99
<system>
1010
<section id="payment">
11-
<group id="braintree_section" translate="label" type="text" sortOrder="2" showInDefault="1" showInWebsite="1" showInStore="1">
12-
<label>Braintree</label>
13-
<comment><![CDATA[Accept credit/debit cards and PayPal in your Magento store. No setup or monthly fees and your customers never leave your store to complete the purchase.]]></comment>
14-
<attribute type="expanded">1</attribute>
15-
<fieldset_css>complex braintree-section</fieldset_css>
16-
<frontend_model>Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Group</frontend_model>
17-
<group id="braintree" translate="label" type="text" sortOrder="25" showInDefault="1" showInWebsite="1" showInStore="1">
18-
<label><![CDATA[&nbsp;]]></label>
11+
<group id="braintree_section" sortOrder="6" showInDefault="0" showInWebsite="0" showInStore="0">
12+
<group id="braintree" translate="label comment" type="text" showInDefault="1" showInWebsite="1" showInStore="1">
13+
<label>Braintree</label>
14+
<comment><![CDATA[Accept credit/debit cards and PayPal in your Magento store.<br/>No setup or monthly fees and your customers never leave your store to complete the purchase.]]></comment>
15+
<fieldset_css>complex braintree-section</fieldset_css>
1916
<frontend_model>Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Payment</frontend_model>
2017
<attribute type="activity_path">payment/braintree/active</attribute>
21-
<more_url>https://articles.braintreepayments.com/guides/magento/configuration</more_url>
18+
<attribute type="displayIn">recommended_solutions</attribute>
2219
<field id="active" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0">
2320
<label>Enable this Solution</label>
2421
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
@@ -43,8 +40,11 @@
4340
<group id="braintree_required"/>
4441
</requires>
4542
</field>
43+
<group id="configuration_details" showInDefault="1" showInWebsite="1" showInStore="1" sortOrder="4">
44+
<comment>http://docs.magento.com/m2/ce/user_guide/payment/braintree.html</comment>
45+
<frontend_model>Magento\Paypal\Block\Adminhtml\System\Config\Fieldset\Hint</frontend_model>
46+
</group>
4647
<group id="braintree_required" translate="label" showInDefault="1" showInWebsite="1" sortOrder="5">
47-
<comment><![CDATA[<a href="https://www.braintreegateway.com/login" target="_blank">Click here to login to your existing Braintree account</a>. Or to setup a new account and accept payments on your website, <a href="https://apply.braintreegateway.com/signup/us" target="_blank">click here to signup for a Braintree account</a>.<br><br>Powered by <a href="https://www.braintreepayments.com/features/hosted-fields" target="_blank">Braintree v.zero with Hosted Fields</a> latest technology. Hosted Fields are small, transparent iframes that replace the sensitive credit card inputs in your checkout flow - helping you meet the latest data security requirements while ensuring your customization doesn't suffer. <a href="https://www.braintreepayments.com/features/hosted-fields" target="_blank">Find out more</a>.]]></comment>
4848
<label>Basic Braintree Settings</label>
4949
<attribute type="expanded">1</attribute>
5050
<frontend_model>Magento\Config\Block\System\Config\Form\Fieldset</frontend_model>

app/code/Magento/Braintree/etc/config.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
<can_void>1</can_void>
2727
<can_cancel>1</can_cancel>
2828
<can_edit>1</can_edit>
29+
<can_review_payment>1</can_review_payment>
30+
<can_deny_payment>1</can_deny_payment>
2931
<cctypes>AE,VI,MC,DI,JCB,CUP,DN,MI</cctypes>
3032
<useccv>1</useccv>
3133
<cctypes_braintree_mapper><![CDATA[{"american-express":"AE","discover":"DI","jcb":"JCB","mastercard":"MC","master-card":"MC","visa":"VI","maestro":"MI","diners-club":"DN","unionpay":"CUP"}]]></cctypes_braintree_mapper>

app/code/Magento/Braintree/etc/di.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
<item name="void" xsi:type="string">BraintreeVoidCommand</item>
134134
<item name="refund" xsi:type="string">BraintreeRefundCommand</item>
135135
<item name="cancel" xsi:type="string">BraintreeVoidCommand</item>
136+
<item name="deny_payment" xsi:type="string">BraintreeVoidCommand</item>
136137
</argument>
137138
</arguments>
138139
</virtualType>

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,5 @@ Debug,Debug
164164
"europe_bank_accout","Europe bank account"
165165
"credit_card","Credit card"
166166
"apple_pay_card","Apple pay card"
167-
"android_pay_card","Android pay card"
167+
"android_pay_card","Android pay card"
168+
"Accept credit/debit cards and PayPal in your Magento store.<br/>No setup or monthly fees and your customers never leave your store to complete the purchase.","Accept credit/debit cards and PayPal in your Magento store.<br/>No setup or monthly fees and your customers never leave your store to complete the purchase."

app/code/Magento/Braintree/view/adminhtml/web/styles.css

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
* See COPYING.txt for license details.
44
*/
55

6-
.braintree-section .entry-edit-head > .config-heading .heading strong {padding-left:150px;background:url(images/braintree_logo.png) no-repeat 0 0 / 145px auto;line-height:36px;}
7-
.braintree-section .entry-edit-head > .config-heading:before {background: url("images/braintree_allinone.png") no-repeat 0 0 / 100% auto;content: "";display: inline;float: right;height: 35px;width: 280px;}
6+
.braintree-section .heading {display: inline-block; background: url("images/braintree_logo.png") no-repeat 0 50% / 18rem auto; padding-left: 20rem;}
7+
.braintree-section .button-container {display: inline-block; float: right;}
8+
.braintree-section .config-alt {background: url("images/braintree_allinone.png") no-repeat scroll 0 0 / 100% auto; height: 28px; margin: 0.5rem 0 0; width: 230px;}

app/code/Magento/Catalog/Model/Product/TierPriceManagement.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use Magento\Customer\Api\GroupRepositoryInterface;
1313
use Magento\Framework\Exception\CouldNotSaveException;
1414
use Magento\Framework\Exception\InputException;
15+
use Magento\Framework\Exception\TemporaryStateExceptionInterface;
1516

1617
/**
1718
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -137,6 +138,10 @@ public function add($sku, $customerGroupId, $price, $qty)
137138
try {
138139
$this->productRepository->save($product);
139140
} catch (\Exception $e) {
141+
if ($e instanceof TemporaryStateExceptionInterface) {
142+
// temporary state exception must be already localized
143+
throw $e;
144+
}
140145
throw new CouldNotSaveException(__('Could not save group price'));
141146
}
142147
return true;

app/code/Magento/Catalog/Model/ProductRepository.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
use Magento\Framework\Api\ImageContentValidatorInterface;
1515
use Magento\Framework\Api\ImageProcessorInterface;
1616
use Magento\Framework\Api\SortOrder;
17+
use Magento\Framework\DB\Adapter\ConnectionException;
18+
use Magento\Framework\DB\Adapter\DeadlockException;
19+
use Magento\Framework\DB\Adapter\LockWaitException;
1720
use Magento\Framework\Exception\InputException;
1821
use Magento\Framework\Exception\LocalizedException;
1922
use Magento\Framework\Exception\NoSuchEntityException;
@@ -535,6 +538,24 @@ public function save(\Magento\Catalog\Api\Data\ProductInterface $product, $saveO
535538
unset($this->instances[$product->getSku()]);
536539
unset($this->instancesById[$product->getId()]);
537540
$this->resourceModel->save($product);
541+
} catch (ConnectionException $exception) {
542+
throw new \Magento\Framework\Exception\TemporaryState\CouldNotSaveException(
543+
__('Database connection error'),
544+
$exception,
545+
$exception->getCode()
546+
);
547+
} catch (DeadlockException $exception) {
548+
throw new \Magento\Framework\Exception\TemporaryState\CouldNotSaveException(
549+
__('Database deadlock found when trying to get lock'),
550+
$exception,
551+
$exception->getCode()
552+
);
553+
} catch (LockWaitException $exception) {
554+
throw new \Magento\Framework\Exception\TemporaryState\CouldNotSaveException(
555+
__('Database lock wait timeout exceeded'),
556+
$exception,
557+
$exception->getCode()
558+
);
538559
} catch (\Magento\Eav\Model\Entity\Attribute\Exception $exception) {
539560
throw \Magento\Framework\Exception\InputException::invalidFieldValue(
540561
$exception->getAttributeCode(),

app/code/Magento/Catalog/Test/Unit/Model/Product/TierPriceManagementTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
use Magento\Customer\Model\GroupManagement;
1414
use Magento\Framework\Exception\NoSuchEntityException;
15+
use Magento\Framework\Exception\TemporaryState\CouldNotSaveException;
1516

1617
/**
1718
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -393,6 +394,30 @@ public function testSetThrowsExceptionIfCantSave()
393394
$this->service->add('product_sku', 1, 100, 2);
394395
}
395396

397+
/**
398+
* @expectedException \Magento\Framework\Exception\TemporaryState\CouldNotSaveException
399+
*/
400+
public function testAddRethrowsTemporaryStateExceptionIfRecoverableErrorOccurred()
401+
{
402+
$group = $this->getMock(\Magento\Customer\Model\Data\Group::class, [], [], '', false);
403+
$group->expects($this->once())
404+
->method('getId')
405+
->willReturn(1);
406+
$this->productMock
407+
->expects($this->once())
408+
->method('getData')
409+
->with('tier_price')
410+
->will($this->returnValue([]));
411+
$this->groupRepositoryMock->expects($this->once())
412+
->method('getById')
413+
->willReturn($group);
414+
$this->repositoryMock->expects($this->once())
415+
->method('save')
416+
->willThrowException(new CouldNotSaveException(__('Lock wait timeout')));
417+
418+
$this->service->add('product_sku', 1, 100, 2);
419+
}
420+
396421
/**
397422
* @param string|int $price
398423
* @param string|float $qty

0 commit comments

Comments
 (0)