<?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; /** * @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) */ 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*$/', ]; $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; } /** * @return bool * @api */ public function hasVerification() { $configData = $this->getConfigData('useccv'); if ($configData === null) { return true; } return (bool)$configData; } /** * @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; } /** * @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' => 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; } /** * @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 = strrev($ccNumber); $numSum = 0; for ($i = 0; $i < strlen($cardNumber); $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+$/', $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); } }