Skip to content

Commit

Permalink
Merge pull request #904 from magento-mpi/MAGETWO-63638
Browse files Browse the repository at this point in the history
[MPI] S86
  • Loading branch information
kandy authored Mar 15, 2017
2 parents b47cb1f + 80ae35e commit aa93ea8
Show file tree
Hide file tree
Showing 23 changed files with 1,105 additions and 5 deletions.
71 changes: 71 additions & 0 deletions app/code/Magento/Braintree/Model/AvsEmsCodeMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php
/**
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Braintree\Model;

use Magento\Braintree\Model\Ui\ConfigProvider;
use Magento\Braintree\Gateway\Response\PaymentDetailsHandler;
use Magento\Payment\Api\PaymentVerificationInterface;
use Magento\Sales\Api\Data\OrderPaymentInterface;

/**
* Processes AVS codes mapping from Braintree transaction to
* electronic merchant systems standard.
*
* @see https://developers.braintreepayments.com/reference/response/transaction
* @see http://www.emsecommerce.net/avs_cvv2_response_codes.htm
*/
class AvsEmsCodeMapper implements PaymentVerificationInterface
{
/**
* Default code for mismatching mapping.
*
* @var string
*/
private static $unavailableCode = 'U';

/**
* List of mapping AVS codes
*
* @var array
*/
private static $avsMap = [
'MM' => 'Y',
'NM' => 'A',
'MN' => 'Z',
'NN' => 'N',
'UU' => 'U',
'II' => 'U',
'AA' => 'E'
];

/**
* Gets payment AVS verification code.
*
* @param OrderPaymentInterface $orderPayment
* @return string
* @throws \InvalidArgumentException If specified order payment has different payment method code.
*/
public function getCode(OrderPaymentInterface $orderPayment)
{
if ($orderPayment->getMethod() !== ConfigProvider::CODE) {
throw new \InvalidArgumentException(
'The "' . $orderPayment->getMethod() . '" does not supported by Braintree AVS mapper.'
);
}

$additionalInfo = $orderPayment->getAdditionalInformation();
if (empty($additionalInfo[PaymentDetailsHandler::AVS_POSTAL_RESPONSE_CODE]) ||
empty($additionalInfo[PaymentDetailsHandler::AVS_STREET_ADDRESS_RESPONSE_CODE])
) {
return self::$unavailableCode;
}

$streetCode = $additionalInfo[PaymentDetailsHandler::AVS_STREET_ADDRESS_RESPONSE_CODE];
$zipCode = $additionalInfo[PaymentDetailsHandler::AVS_POSTAL_RESPONSE_CODE];
$key = $zipCode . $streetCode;
return isset(self::$avsMap[$key]) ? self::$avsMap[$key] : self::$unavailableCode;
}
}
66 changes: 66 additions & 0 deletions app/code/Magento/Braintree/Model/CvvEmsCodeMapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
/**
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Braintree\Model;

use Magento\Braintree\Gateway\Response\PaymentDetailsHandler;
use Magento\Braintree\Model\Ui\ConfigProvider;
use Magento\Payment\Api\PaymentVerificationInterface;
use Magento\Sales\Api\Data\OrderPaymentInterface;

/**
* Processes CVV codes mapping from Braintree transaction to
* electronic merchant systems standard.
*
* @see https://developers.braintreepayments.com/reference/response/transaction
* @see http://www.emsecommerce.net/avs_cvv2_response_codes.htm
*/
class CvvEmsCodeMapper implements PaymentVerificationInterface
{
/**
* Default code for mismatch mapping
*
* @var string
*/
private static $notProvidedCode = 'P';

/**
* List of mapping CVV codes
*
* @var array
*/
private static $cvvMap = [
'M' => 'M',
'N' => 'N',
'U' => 'P',
'I' => 'P',
'S' => 'S',
'A' => ''
];

/**
* Gets payment CVV verification code.
*
* @param OrderPaymentInterface $orderPayment
* @return string
* @throws \InvalidArgumentException If specified order payment has different payment method code.
*/
public function getCode(OrderPaymentInterface $orderPayment)
{
if ($orderPayment->getMethod() !== ConfigProvider::CODE) {
throw new \InvalidArgumentException(
'The "' . $orderPayment->getMethod() . '" does not supported by Braintree CVV mapper.'
);
}

$additionalInfo = $orderPayment->getAdditionalInformation();
if (empty($additionalInfo[PaymentDetailsHandler::CVV_RESPONSE_CODE])) {
return self::$notProvidedCode;
}

$cvv = $additionalInfo[PaymentDetailsHandler::CVV_RESPONSE_CODE];
return isset(self::$cvvMap[$cvv]) ? self::$cvvMap[$cvv] : self::$notProvidedCode;
}
}
101 changes: 101 additions & 0 deletions app/code/Magento/Braintree/Test/Unit/Model/AvsEmsCodeMapperTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<?php
/**
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Braintree\Test\Unit\Model;

use Magento\Braintree\Model\AvsEmsCodeMapper;
use Magento\Braintree\Model\Ui\ConfigProvider;
use Magento\Sales\Api\Data\OrderPaymentInterface;
use PHPUnit_Framework_MockObject_MockObject as MockObject;

class AvsEmsCodeMapperTest extends \PHPUnit_Framework_TestCase
{
/**
* @var AvsEmsCodeMapper
*/
private $mapper;

/**
* @inheritdoc
*/
protected function setUp()
{
$this->mapper = new AvsEmsCodeMapper();
}

/**
* Checks different variations for AVS codes mapping.
*
* @covers \Magento\Braintree\Model\AvsEmsCodeMapper::getCode
* @param string $avsZip
* @param string $avsStreet
* @param string $expected
* @dataProvider getCodeDataProvider
*/
public function testGetCode($avsZip, $avsStreet, $expected)
{
/** @var OrderPaymentInterface|MockObject $orderPayment */
$orderPayment = $this->getMockBuilder(OrderPaymentInterface::class)
->disableOriginalConstructor()
->getMock();

$orderPayment->expects(self::once())
->method('getMethod')
->willReturn(ConfigProvider::CODE);

$orderPayment->expects(self::once())
->method('getAdditionalInformation')
->willReturn([
'avsPostalCodeResponseCode' => $avsZip,
'avsStreetAddressResponseCode' => $avsStreet
]);

self::assertEquals($expected, $this->mapper->getCode($orderPayment));
}

/**
* Checks a test case, when payment order is not Braintree payment method.
*
* @covers \Magento\Braintree\Model\AvsEmsCodeMapper::getCode
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The "some_payment" does not supported by Braintree AVS mapper.
*/
public function testGetCodeWithException()
{
/** @var OrderPaymentInterface|MockObject $orderPayment */
$orderPayment = $this->getMockBuilder(OrderPaymentInterface::class)
->disableOriginalConstructor()
->getMock();

$orderPayment->expects(self::exactly(2))
->method('getMethod')
->willReturn('some_payment');

$this->mapper->getCode($orderPayment);
}

/**
* Gets list of AVS codes.
*
* @return array
*/
public function getCodeDataProvider()
{
return [
['avsZip' => null, 'avsStreet' => null, 'expected' => 'U'],
['avsZip' => null, 'avsStreet' => 'M', 'expected' => 'U'],
['avsZip' => 'M', 'avsStreet' => null, 'expected' => 'U'],
['avsZip' => 'M', 'avsStreet' => 'Unknown', 'expected' => 'U'],
['avsZip' => 'I', 'avsStreet' => 'A', 'expected' => 'U'],
['avsZip' => 'M', 'avsStreet' => 'M', 'expected' => 'Y'],
['avsZip' => 'N', 'avsStreet' => 'M', 'expected' => 'A'],
['avsZip' => 'M', 'avsStreet' => 'N', 'expected' => 'Z'],
['avsZip' => 'N', 'avsStreet' => 'N', 'expected' => 'N'],
['avsZip' => 'U', 'avsStreet' => 'U', 'expected' => 'U'],
['avsZip' => 'I', 'avsStreet' => 'I', 'expected' => 'U'],
['avsZip' => 'A', 'avsStreet' => 'A', 'expected' => 'E'],
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php
/**
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Braintree\Test\Unit\Model;

use Magento\Braintree\Model\CvvEmsCodeMapper;
use Magento\Braintree\Model\Ui\ConfigProvider;
use Magento\Sales\Api\Data\OrderPaymentInterface;
use PHPUnit_Framework_MockObject_MockObject as MockObject;

class CvvEmsCodeMapperTest extends \PHPUnit_Framework_TestCase
{
/**
* @var CvvEmsCodeMapper
*/
private $mapper;

/**
* @inheritdoc
*/
protected function setUp()
{
$this->mapper = new CvvEmsCodeMapper();
}

/**
* Checks different variations for cvv codes mapping.
*
* @covers \Magento\Braintree\Model\CvvEmsCodeMapper::getCode
* @param string $cvvCode
* @param string $expected
* @dataProvider getCodeDataProvider
*/
public function testGetCode($cvvCode, $expected)
{
/** @var OrderPaymentInterface|MockObject $orderPayment */
$orderPayment = $this->getMockBuilder(OrderPaymentInterface::class)
->disableOriginalConstructor()
->getMock();

$orderPayment->expects(self::once())
->method('getMethod')
->willReturn(ConfigProvider::CODE);

$orderPayment->expects(self::once())
->method('getAdditionalInformation')
->willReturn(['cvvResponseCode' => $cvvCode]);

self::assertEquals($expected, $this->mapper->getCode($orderPayment));
}

/**
* Checks a test case, when payment order is not Braintree payment method.
*
* @covers \Magento\Braintree\Model\CvvEmsCodeMapper::getCode
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The "some_payment" does not supported by Braintree CVV mapper.
*/
public function testGetCodeWithException()
{
/** @var OrderPaymentInterface|MockObject $orderPayment */
$orderPayment = $this->getMockBuilder(OrderPaymentInterface::class)
->disableOriginalConstructor()
->getMock();

$orderPayment->expects(self::exactly(2))
->method('getMethod')
->willReturn('some_payment');

$this->mapper->getCode($orderPayment);
}

/**
* Gets variations of cvv codes and expected mapping result.
*
* @return array
*/
public function getCodeDataProvider()
{
return [
['cvvCode' => '', 'expected' => 'P'],
['cvvCode' => null, 'expected' => 'P'],
['cvvCode' => 'Unknown', 'expected' => 'P'],
['cvvCode' => 'M', 'expected' => 'M'],
['cvvCode' => 'N', 'expected' => 'N'],
['cvvCode' => 'U', 'expected' => 'P'],
['cvvCode' => 'I', 'expected' => 'P'],
['cvvCode' => 'S', 'expected' => 'S'],
['cvvCode' => 'A', 'expected' => ''],
];
}
}
2 changes: 2 additions & 0 deletions app/code/Magento/Braintree/etc/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
<masked_fields>cvv,number</masked_fields>
<privateInfoKeys>avsPostalCodeResponseCode,avsStreetAddressResponseCode,cvvResponseCode,processorAuthorizationCode,processorResponseCode,processorResponseText,liabilityShifted,liabilityShiftPossible,riskDataId,riskDataDecision</privateInfoKeys>
<paymentInfoKeys>cc_type,cc_number,avsPostalCodeResponseCode,avsStreetAddressResponseCode,cvvResponseCode,processorAuthorizationCode,processorResponseCode,processorResponseText,liabilityShifted,liabilityShiftPossible,riskDataId,riskDataDecision</paymentInfoKeys>
<avs_ems_adapter>Magento\Braintree\Model\AvsEmsCodeMapper</avs_ems_adapter>
<cvv_ems_adapter>Magento\Braintree\Model\CvvEmsCodeMapper</cvv_ems_adapter>
</braintree>
<braintree_paypal>
<model>BraintreePayPalFacade</model>
Expand Down
34 changes: 34 additions & 0 deletions app/code/Magento/Payment/Api/PaymentVerificationInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
/**
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Payment\Api;

use Magento\Sales\Api\Data\OrderPaymentInterface;

/**
* Payment provider codes verification interface.
*
* Custom payment methods might implement this interface to provide
* specific mapping for payment methods, like AVS or CVV verification.
* The payment methods can map payment method info from internal sources,
* like additional information, to specific international codes.
*
* There are no default implementation of this interface, because code verification
* depends on payment method integration specifics.
*
* @api
*/
interface PaymentVerificationInterface
{
/**
* Gets payment provider verification code.
* Throws an exception if provided payment method is different to verification implementation.
*
* @param OrderPaymentInterface $orderPayment
* @return string
* @throws \InvalidArgumentException
*/
public function getCode(OrderPaymentInterface $orderPayment);
}
Loading

0 comments on commit aa93ea8

Please sign in to comment.