<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Payment\Model\Method;
use Magento\Framework\DataObject;
use Magento\Quote\Api\Data\PaymentInterface;
use Magento\Quote\Model\Quote\Payment;
/**
* Credit Card payment method legacy implementation.
*
* @method \Magento\Quote\Api\Data\PaymentMethodExtensionInterface getExtensionAttributes()
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @deprecated 100.0.8
*/
class Cc extends \Magento\Payment\Model\Method\AbstractMethod
{
/**
* @var string
*/
protected $_formBlockType = \Magento\Payment\Block\Form\Cc::class;
/**
* @var string
*/
protected $_infoBlockType = \Magento\Payment\Block\Info\Cc::class;
/**
* @var bool
*/
protected $_canSaveCc = false;
/**
* @var \Magento\Framework\Module\ModuleListInterface
*/
protected $_moduleList;
/**
* @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface
*/
protected $_localeDate;
/**
* @param \Magento\Framework\Model\Context $context
* @param \Magento\Framework\Registry $registry
* @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory
* @param \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory
* @param \Magento\Payment\Helper\Data $paymentData
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param Logger $logger
* @param \Magento\Framework\Module\ModuleListInterface $moduleList
* @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
* @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
* @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
* @param array $data
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
\Magento\Framework\Model\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,
\Magento\Framework\Api\AttributeValueFactory $customAttributeFactory,
\Magento\Payment\Helper\Data $paymentData,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Magento\Payment\Model\Method\Logger $logger,
\Magento\Framework\Module\ModuleListInterface $moduleList,
\Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
array $data = []
) {
parent::__construct(
$context,
$registry,
$extensionFactory,
$customAttributeFactory,
$paymentData,
$scopeConfig,
$logger,
$resource,
$resourceCollection,
$data
);
$this->_moduleList = $moduleList;
$this->_localeDate = $localeDate;
}
/**
* Validate payment method information object
*
* @return $this
* @throws \Magento\Framework\Exception\LocalizedException
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function validate()
{
/*
* calling parent validate function
*/
parent::validate();
$info = $this->getInfoInstance();
$errorMsg = false;
$availableTypes = explode(',', $this->getConfigData('cctypes') ?? '');
$ccNumber = $info->getCcNumber() ?? '';
// remove credit card number delimiters such as "-" and space
$ccNumber = preg_replace('/[\-\s]+/', '', $ccNumber);
$info->setCcNumber($ccNumber);
$ccType = '';
if (in_array($info->getCcType(), $availableTypes)) {
if ($this->validateCcNum(
$ccNumber
) || $this->otherCcType(
$info->getCcType()
) && $this->validateCcNumOther(
// Other credit card type number validation
$ccNumber
)
) {
$ccTypeRegExpList = [
//Solo, Switch or Maestro. International safe
'SO' => '/(^(6334)[5-9](\d{11}$|\d{13,14}$))|(^(6767)(\d{12}$|\d{14,15}$))/',
'SM' => '/(^(5[0678])\d{11,18}$)|(^(6[^05])\d{11,18}$)|(^(601)[^1]\d{9,16}$)|(^(6011)\d{9,11}$)' .
'|(^(6011)\d{13,16}$)|(^(65)\d{11,13}$)|(^(65)\d{15,18}$)' .
'|(^(49030)[2-9](\d{10}$|\d{12,13}$))|(^(49033)[5-9](\d{10}$|\d{12,13}$))' .
'|(^(49110)[1-2](\d{10}$|\d{12,13}$))|(^(49117)[4-9](\d{10}$|\d{12,13}$))' .
'|(^(49118)[0-2](\d{10}$|\d{12,13}$))|(^(4936)(\d{12}$|\d{14,15}$))/',
// Visa
'VI' => '/^4[0-9]{12}([0-9]{3})?$/',
// Master Card
'MC' => '/^(?:5[1-5][0-9]{2}|222[1-9]|22[3-9][0-9]|2[3-6][0-9]{2}|27[01][0-9]|2720)[0-9]{12}$/',
// American Express
'AE' => '/^3[47][0-9]{13}$/',
// Discover
'DI' => '/^(6011((0|9|[2-4])[0-9]{11,14}|(74|7[7-9]|8[6-9])[0-9]{10,13})|6(4[4-9][0-9]{13,16}|' .
'5[0-9]{14,17}))/',
'DN' => '/^3(0[0-5][0-9]{13,16}|095[0-9]{12,15}|(6|[8-9])[0-9]{14,17})/',
// UnionPay
'UN' => '/^622(1(2[6-9][0-9]{10,13}|[3-9][0-9]{11,14})|[3-8][0-9]{12,15}|9([[0-1][0-9]{11,14}|' .
'2[0-5][0-9]{10,13}))|62[4-6][0-9]{13,16}|628[2-8][0-9]{12,15}/',
// JCB
'JCB' => '/^35(2[8-9][0-9]{12,15}|[3-8][0-9]{13,16})/',
'MI' => '/^(5(0|[6-9])|63|67(?!59|6770|6774))\d*$/',
'MD' => '/^(6759(?!24|38|40|6[3-9]|70|76)|676770|676774)\d*$/',
//Hipercard
'HC' => '/^((606282)|(637095)|(637568)|(637599)|(637609)|(637612))\d*$/',
//Elo
'ELO' => '/^((509091)|(636368)|(636297)|(504175)|(438935)|(40117[8-9])|(45763[1-2])|' .
'(457393)|(431274)|(50990[0-2])|(5099[7-9][0-9])|(50996[4-9])|(509[1-8][0-9][0-9])|' .
'(5090(0[0-2]|0[4-9]|1[2-9]|[24589][0-9]|3[1-9]|6[0-46-9]|7[0-24-9]))|' .
'(5067(0[0-24-8]|1[0-24-9]|2[014-9]|3[0-379]|4[0-9]|5[0-3]|6[0-5]|7[0-8]))|' .
'(6504(0[5-9]|1[0-9]|2[0-9]|3[0-9]))|' .
'(6504(8[5-9]|9[0-9])|6505(0[0-9]|1[0-9]|2[0-9]|3[0-8]))|' .
'(6505(4[1-9]|5[0-9]|6[0-9]|7[0-9]|8[0-9]|9[0-8]))|' .
'(6507(0[0-9]|1[0-8]))|(65072[0-7])|(6509(0[1-9]|1[0-9]|20))|' .
'(6516(5[2-9]|6[0-9]|7[0-9]))|(6550(0[0-9]|1[0-9]))|' .
'(6550(2[1-9]|3[0-9]|4[0-9]|5[0-8])))\d*$/',
//Aura
'AU' => '/^5078\d*$/'
];
$ccNumAndTypeMatches = isset(
$ccTypeRegExpList[$info->getCcType()]
) && preg_match(
$ccTypeRegExpList[$info->getCcType()],
$ccNumber
);
$ccType = $ccNumAndTypeMatches ? $info->getCcType() : 'OT';
if (!$ccNumAndTypeMatches && !$this->otherCcType($info->getCcType())) {
$errorMsg = __('The credit card number doesn\'t match the credit card type.');
}
} else {
$errorMsg = __('Invalid Credit Card Number');
}
} else {
$errorMsg = __('This credit card type is not allowed for this payment method.');
}
//validate credit card verification number
if ($errorMsg === false && $this->hasVerification()) {
$verifcationRegEx = $this->getVerificationRegEx();
$regExp = isset($verifcationRegEx[$info->getCcType()]) ? $verifcationRegEx[$info->getCcType()] : '';
if (!$info->getCcCid() || !$regExp || !preg_match($regExp, $info->getCcCid())) {
$errorMsg = __('Please enter a valid credit card verification number.');
}
}
if ($ccType != 'SS' && !$this->_validateExpDate($info->getCcExpYear(), $info->getCcExpMonth())) {
$errorMsg = __('Please enter a valid credit card expiration date.');
}
if ($errorMsg) {
throw new \Magento\Framework\Exception\LocalizedException($errorMsg);
}
return $this;
}
/**
* Check if verification should be used.
*
* @return bool
* @api
*/
public function hasVerification()
{
$configData = $this->getConfigData('useccv');
if ($configData === null) {
return true;
}
return (bool)$configData;
}
/**
* Get list of credit cards verification reg exp.
*
* @return array
* @api
*/
public function getVerificationRegEx()
{
$verificationExpList = [
'VI' => '/^[0-9]{3}$/',
'MC' => '/^[0-9]{3}$/',
'AE' => '/^[0-9]{4}$/',
'DI' => '/^[0-9]{3}$/',
'DN' => '/^[0-9]{3}$/',
'UN' => '/^[0-9]{3}$/',
'SS' => '/^[0-9]{3,4}$/',
'SM' => '/^[0-9]{3,4}$/',
'SO' => '/^[0-9]{3,4}$/',
'OT' => '/^[0-9]{3,4}$/',
'JCB' => '/^[0-9]{3,4}$/',
'MI' => '/^[0-9]{3}$/',
'MD' => '/^[0-9]{3}$/',
];
return $verificationExpList;
}
/**
* Validate expiration date
*
* @param string $expYear
* @param string $expMonth
* @return bool
*/
protected function _validateExpDate($expYear, $expMonth)
{
$date = new \DateTime();
if (!$expYear || !$expMonth || (int)$date->format('Y') > $expYear
|| (int)$date->format('Y') == $expYear && (int)$date->format('m') > $expMonth
) {
return false;
}
return true;
}
/**
* Assign data to info model instance
*
* @param \Magento\Framework\DataObject|mixed $data
* @return $this
* @throws \Magento\Framework\Exception\LocalizedException
*/
public function assignData(\Magento\Framework\DataObject $data)
{
$additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA);
if (!is_object($additionalData)) {
$additionalData = new DataObject($additionalData ?: []);
}
/** @var DataObject $info */
$info = $this->getInfoInstance();
$info->addData(
[
'cc_type' => $additionalData->getCcType(),
'cc_owner' => $additionalData->getCcOwner(),
'cc_last_4' => $additionalData->getCcNumber() !== null ?
substr($additionalData->getCcNumber(), -4) : '',
'cc_number' => $additionalData->getCcNumber(),
'cc_cid' => $additionalData->getCcCid(),
'cc_exp_month' => $additionalData->getCcExpMonth(),
'cc_exp_year' => $additionalData->getCcExpYear(),
'cc_ss_issue' => $additionalData->getCcSsIssue(),
'cc_ss_start_month' => $additionalData->getCcSsStartMonth(),
'cc_ss_start_year' => $additionalData->getCcSsStartYear()
]
);
return $this;
}
/**
* Get code for "other" credit cards.
*
* @param string $type
* @return bool
* @api
*/
public function otherCcType($type)
{
return $type == 'OT';
}
/**
* Validate credit card number
*
* @param string $ccNumber
* @return bool
* @api
*/
public function validateCcNum($ccNumber)
{
$cardNumber = $ccNumber !== null ? strrev($ccNumber) : '';
$numSum = 0;
$length = strlen($cardNumber);
for ($i = 0; $i < $length; $i++) {
$currentNum = substr($cardNumber, $i, 1);
/**
* Double every second digit
*/
if ($i % 2 == 1) {
$currentNum *= 2;
}
/**
* Add digits of 2-digit numbers together
*/
if ($currentNum > 9) {
$firstNum = $currentNum % 10;
$secondNum = ($currentNum - $firstNum) / 10;
$currentNum = $firstNum + $secondNum;
}
$numSum += $currentNum;
}
/**
* If the total has no remainder it's OK
*/
return $numSum % 10 == 0;
}
/**
* Other credit cart type number validation
*
* @param string $ccNumber
* @return bool
* @api
*/
public function validateCcNumOther($ccNumber)
{
return preg_match('/^\\d+$/', (string)$ccNumber);
}
/**
* Check whether there are CC types set in configuration
*
* @param \Magento\Quote\Api\Data\CartInterface|null $quote
* @return bool
*/
public function isAvailable(\Magento\Quote\Api\Data\CartInterface $quote = null)
{
return $this->getConfigData('cctypes', $quote ? $quote->getStoreId() : null) && parent::isAvailable($quote);
}
}
|