Cc.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Payment\Model\Method;
  7. use Magento\Framework\DataObject;
  8. use Magento\Quote\Api\Data\PaymentInterface;
  9. use Magento\Quote\Model\Quote\Payment;
  10. /**
  11. * @method \Magento\Quote\Api\Data\PaymentMethodExtensionInterface getExtensionAttributes()
  12. * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  13. * @deprecated 100.0.8
  14. */
  15. class Cc extends \Magento\Payment\Model\Method\AbstractMethod
  16. {
  17. /**
  18. * @var string
  19. */
  20. protected $_formBlockType = \Magento\Payment\Block\Form\Cc::class;
  21. /**
  22. * @var string
  23. */
  24. protected $_infoBlockType = \Magento\Payment\Block\Info\Cc::class;
  25. /**
  26. * @var bool
  27. */
  28. protected $_canSaveCc = false;
  29. /**
  30. * @var \Magento\Framework\Module\ModuleListInterface
  31. */
  32. protected $_moduleList;
  33. /**
  34. * @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface
  35. */
  36. protected $_localeDate;
  37. /**
  38. * @param \Magento\Framework\Model\Context $context
  39. * @param \Magento\Framework\Registry $registry
  40. * @param \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory
  41. * @param \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory
  42. * @param \Magento\Payment\Helper\Data $paymentData
  43. * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
  44. * @param Logger $logger
  45. * @param \Magento\Framework\Module\ModuleListInterface $moduleList
  46. * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate
  47. * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource
  48. * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection
  49. * @param array $data
  50. * @SuppressWarnings(PHPMD.ExcessiveParameterList)
  51. */
  52. public function __construct(
  53. \Magento\Framework\Model\Context $context,
  54. \Magento\Framework\Registry $registry,
  55. \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,
  56. \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory,
  57. \Magento\Payment\Helper\Data $paymentData,
  58. \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
  59. \Magento\Payment\Model\Method\Logger $logger,
  60. \Magento\Framework\Module\ModuleListInterface $moduleList,
  61. \Magento\Framework\Stdlib\DateTime\TimezoneInterface $localeDate,
  62. \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
  63. \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
  64. array $data = []
  65. ) {
  66. parent::__construct(
  67. $context,
  68. $registry,
  69. $extensionFactory,
  70. $customAttributeFactory,
  71. $paymentData,
  72. $scopeConfig,
  73. $logger,
  74. $resource,
  75. $resourceCollection,
  76. $data
  77. );
  78. $this->_moduleList = $moduleList;
  79. $this->_localeDate = $localeDate;
  80. }
  81. /**
  82. * Validate payment method information object
  83. *
  84. * @return $this
  85. * @throws \Magento\Framework\Exception\LocalizedException
  86. * @SuppressWarnings(PHPMD.CyclomaticComplexity)
  87. * @SuppressWarnings(PHPMD.NPathComplexity)
  88. */
  89. public function validate()
  90. {
  91. /*
  92. * calling parent validate function
  93. */
  94. parent::validate();
  95. $info = $this->getInfoInstance();
  96. $errorMsg = false;
  97. $availableTypes = explode(',', $this->getConfigData('cctypes'));
  98. $ccNumber = $info->getCcNumber();
  99. // remove credit card number delimiters such as "-" and space
  100. $ccNumber = preg_replace('/[\-\s]+/', '', $ccNumber);
  101. $info->setCcNumber($ccNumber);
  102. $ccType = '';
  103. if (in_array($info->getCcType(), $availableTypes)) {
  104. if ($this->validateCcNum(
  105. $ccNumber
  106. ) || $this->otherCcType(
  107. $info->getCcType()
  108. ) && $this->validateCcNumOther(
  109. // Other credit card type number validation
  110. $ccNumber
  111. )
  112. ) {
  113. $ccTypeRegExpList = [
  114. //Solo, Switch or Maestro. International safe
  115. 'SO' => '/(^(6334)[5-9](\d{11}$|\d{13,14}$))|(^(6767)(\d{12}$|\d{14,15}$))/',
  116. 'SM' => '/(^(5[0678])\d{11,18}$)|(^(6[^05])\d{11,18}$)|(^(601)[^1]\d{9,16}$)|(^(6011)\d{9,11}$)' .
  117. '|(^(6011)\d{13,16}$)|(^(65)\d{11,13}$)|(^(65)\d{15,18}$)' .
  118. '|(^(49030)[2-9](\d{10}$|\d{12,13}$))|(^(49033)[5-9](\d{10}$|\d{12,13}$))' .
  119. '|(^(49110)[1-2](\d{10}$|\d{12,13}$))|(^(49117)[4-9](\d{10}$|\d{12,13}$))' .
  120. '|(^(49118)[0-2](\d{10}$|\d{12,13}$))|(^(4936)(\d{12}$|\d{14,15}$))/',
  121. // Visa
  122. 'VI' => '/^4[0-9]{12}([0-9]{3})?$/',
  123. // Master Card
  124. '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}$/',
  125. // American Express
  126. 'AE' => '/^3[47][0-9]{13}$/',
  127. // Discover
  128. '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}|' .
  129. '5[0-9]{14,17}))/',
  130. 'DN' => '/^3(0[0-5][0-9]{13,16}|095[0-9]{12,15}|(6|[8-9])[0-9]{14,17})/',
  131. // UnionPay
  132. '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}|' .
  133. '2[0-5][0-9]{10,13}))|62[4-6][0-9]{13,16}|628[2-8][0-9]{12,15}/',
  134. // JCB
  135. 'JCB' => '/^35(2[8-9][0-9]{12,15}|[3-8][0-9]{13,16})/',
  136. 'MI' => '/^(5(0|[6-9])|63|67(?!59|6770|6774))\d*$/',
  137. 'MD' => '/^(6759(?!24|38|40|6[3-9]|70|76)|676770|676774)\d*$/',
  138. ];
  139. $ccNumAndTypeMatches = isset(
  140. $ccTypeRegExpList[$info->getCcType()]
  141. ) && preg_match(
  142. $ccTypeRegExpList[$info->getCcType()],
  143. $ccNumber
  144. );
  145. $ccType = $ccNumAndTypeMatches ? $info->getCcType() : 'OT';
  146. if (!$ccNumAndTypeMatches && !$this->otherCcType($info->getCcType())) {
  147. $errorMsg = __('The credit card number doesn\'t match the credit card type.');
  148. }
  149. } else {
  150. $errorMsg = __('Invalid Credit Card Number');
  151. }
  152. } else {
  153. $errorMsg = __('This credit card type is not allowed for this payment method.');
  154. }
  155. //validate credit card verification number
  156. if ($errorMsg === false && $this->hasVerification()) {
  157. $verifcationRegEx = $this->getVerificationRegEx();
  158. $regExp = isset($verifcationRegEx[$info->getCcType()]) ? $verifcationRegEx[$info->getCcType()] : '';
  159. if (!$info->getCcCid() || !$regExp || !preg_match($regExp, $info->getCcCid())) {
  160. $errorMsg = __('Please enter a valid credit card verification number.');
  161. }
  162. }
  163. if ($ccType != 'SS' && !$this->_validateExpDate($info->getCcExpYear(), $info->getCcExpMonth())) {
  164. $errorMsg = __('Please enter a valid credit card expiration date.');
  165. }
  166. if ($errorMsg) {
  167. throw new \Magento\Framework\Exception\LocalizedException($errorMsg);
  168. }
  169. return $this;
  170. }
  171. /**
  172. * @return bool
  173. * @api
  174. */
  175. public function hasVerification()
  176. {
  177. $configData = $this->getConfigData('useccv');
  178. if ($configData === null) {
  179. return true;
  180. }
  181. return (bool)$configData;
  182. }
  183. /**
  184. * @return array
  185. * @api
  186. */
  187. public function getVerificationRegEx()
  188. {
  189. $verificationExpList = [
  190. 'VI' => '/^[0-9]{3}$/',
  191. 'MC' => '/^[0-9]{3}$/',
  192. 'AE' => '/^[0-9]{4}$/',
  193. 'DI' => '/^[0-9]{3}$/',
  194. 'DN' => '/^[0-9]{3}$/',
  195. 'UN' => '/^[0-9]{3}$/',
  196. 'SS' => '/^[0-9]{3,4}$/',
  197. 'SM' => '/^[0-9]{3,4}$/',
  198. 'SO' => '/^[0-9]{3,4}$/',
  199. 'OT' => '/^[0-9]{3,4}$/',
  200. 'JCB' => '/^[0-9]{3,4}$/',
  201. 'MI' => '/^[0-9]{3}$/',
  202. 'MD' => '/^[0-9]{3}$/',
  203. ];
  204. return $verificationExpList;
  205. }
  206. /**
  207. * @param string $expYear
  208. * @param string $expMonth
  209. * @return bool
  210. */
  211. protected function _validateExpDate($expYear, $expMonth)
  212. {
  213. $date = new \DateTime();
  214. if (!$expYear || !$expMonth || (int)$date->format('Y') > $expYear
  215. || (int)$date->format('Y') == $expYear && (int)$date->format('m') > $expMonth
  216. ) {
  217. return false;
  218. }
  219. return true;
  220. }
  221. /**
  222. * Assign data to info model instance
  223. *
  224. * @param \Magento\Framework\DataObject|mixed $data
  225. * @return $this
  226. * @throws \Magento\Framework\Exception\LocalizedException
  227. */
  228. public function assignData(\Magento\Framework\DataObject $data)
  229. {
  230. $additionalData = $data->getData(PaymentInterface::KEY_ADDITIONAL_DATA);
  231. if (!is_object($additionalData)) {
  232. $additionalData = new DataObject($additionalData ?: []);
  233. }
  234. /** @var DataObject $info */
  235. $info = $this->getInfoInstance();
  236. $info->addData(
  237. [
  238. 'cc_type' => $additionalData->getCcType(),
  239. 'cc_owner' => $additionalData->getCcOwner(),
  240. 'cc_last_4' => substr($additionalData->getCcNumber(), -4),
  241. 'cc_number' => $additionalData->getCcNumber(),
  242. 'cc_cid' => $additionalData->getCcCid(),
  243. 'cc_exp_month' => $additionalData->getCcExpMonth(),
  244. 'cc_exp_year' => $additionalData->getCcExpYear(),
  245. 'cc_ss_issue' => $additionalData->getCcSsIssue(),
  246. 'cc_ss_start_month' => $additionalData->getCcSsStartMonth(),
  247. 'cc_ss_start_year' => $additionalData->getCcSsStartYear()
  248. ]
  249. );
  250. return $this;
  251. }
  252. /**
  253. * @param string $type
  254. * @return bool
  255. * @api
  256. */
  257. public function otherCcType($type)
  258. {
  259. return $type == 'OT';
  260. }
  261. /**
  262. * Validate credit card number
  263. *
  264. * @param string $ccNumber
  265. * @return bool
  266. * @api
  267. */
  268. public function validateCcNum($ccNumber)
  269. {
  270. $cardNumber = strrev($ccNumber);
  271. $numSum = 0;
  272. for ($i = 0; $i < strlen($cardNumber); $i++) {
  273. $currentNum = substr($cardNumber, $i, 1);
  274. /**
  275. * Double every second digit
  276. */
  277. if ($i % 2 == 1) {
  278. $currentNum *= 2;
  279. }
  280. /**
  281. * Add digits of 2-digit numbers together
  282. */
  283. if ($currentNum > 9) {
  284. $firstNum = $currentNum % 10;
  285. $secondNum = ($currentNum - $firstNum) / 10;
  286. $currentNum = $firstNum + $secondNum;
  287. }
  288. $numSum += $currentNum;
  289. }
  290. /**
  291. * If the total has no remainder it's OK
  292. */
  293. return $numSum % 10 == 0;
  294. }
  295. /**
  296. * Other credit cart type number validation
  297. *
  298. * @param string $ccNumber
  299. * @return bool
  300. * @api
  301. */
  302. public function validateCcNumOther($ccNumber)
  303. {
  304. return preg_match('/^\\d+$/', $ccNumber);
  305. }
  306. /**
  307. * Check whether there are CC types set in configuration
  308. *
  309. * @param \Magento\Quote\Api\Data\CartInterface|null $quote
  310. * @return bool
  311. */
  312. public function isAvailable(\Magento\Quote\Api\Data\CartInterface $quote = null)
  313. {
  314. return $this->getConfigData('cctypes', $quote ? $quote->getStoreId() : null) && parent::isAvailable($quote);
  315. }
  316. }