1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26:
27:
28: class Mage_Payment_Model_Method_Cc extends Mage_Payment_Model_Method_Abstract
29: {
30: protected $_formBlockType = 'payment/form_cc';
31: protected $_infoBlockType = 'payment/info_cc';
32: protected $_canSaveCc = false;
33:
34: 35: 36: 37: 38: 39:
40: public function assignData($data)
41: {
42: if (!($data instanceof Varien_Object)) {
43: $data = new Varien_Object($data);
44: }
45: $info = $this->getInfoInstance();
46: $info->setCcType($data->getCcType())
47: ->setCcOwner($data->getCcOwner())
48: ->setCcLast4(substr($data->getCcNumber(), -4))
49: ->setCcNumber($data->getCcNumber())
50: ->setCcCid($data->getCcCid())
51: ->setCcExpMonth($data->getCcExpMonth())
52: ->setCcExpYear($data->getCcExpYear())
53: ->setCcSsIssue($data->getCcSsIssue())
54: ->setCcSsStartMonth($data->getCcSsStartMonth())
55: ->setCcSsStartYear($data->getCcSsStartYear())
56: ;
57: return $this;
58: }
59:
60: 61: 62: 63: 64:
65: public function prepareSave()
66: {
67: $info = $this->getInfoInstance();
68: if ($this->_canSaveCc) {
69: $info->setCcNumberEnc($info->encrypt($info->getCcNumber()));
70: }
71:
72: $info->setCcNumber(null)
73: ->setCcCid(null);
74: return $this;
75: }
76:
77: 78: 79: 80: 81: 82:
83: public function validate()
84: {
85: 86: 87:
88: parent::validate();
89:
90: $info = $this->getInfoInstance();
91: $errorMsg = false;
92: $availableTypes = explode(',',$this->getConfigData('cctypes'));
93:
94: $ccNumber = $info->getCcNumber();
95:
96:
97: $ccNumber = preg_replace('/[\-\s]+/', '', $ccNumber);
98: $info->setCcNumber($ccNumber);
99:
100: $ccType = '';
101:
102: if (in_array($info->getCcType(), $availableTypes)){
103: if ($this->validateCcNum($ccNumber)
104:
105: || ($this->OtherCcType($info->getCcType()) && $this->validateCcNumOther($ccNumber))) {
106:
107: $ccType = 'OT';
108: $ccTypeRegExpList = array(
109:
110: 111: 112: 113: 114: 115:
116:
117: 'SO' => '/(^(6334)[5-9](\d{11}$|\d{13,14}$))|(^(6767)(\d{12}$|\d{14,15}$))/',
118: 'SM' => '/(^(5[0678])\d{11,18}$)|(^(6[^05])\d{11,18}$)|(^(601)[^1]\d{9,16}$)|(^(6011)\d{9,11}$)'
119: . '|(^(6011)\d{13,16}$)|(^(65)\d{11,13}$)|(^(65)\d{15,18}$)'
120: . '|(^(49030)[2-9](\d{10}$|\d{12,13}$))|(^(49033)[5-9](\d{10}$|\d{12,13}$))'
121: . '|(^(49110)[1-2](\d{10}$|\d{12,13}$))|(^(49117)[4-9](\d{10}$|\d{12,13}$))'
122: . '|(^(49118)[0-2](\d{10}$|\d{12,13}$))|(^(4936)(\d{12}$|\d{14,15}$))/',
123:
124: 'VI' => '/^4[0-9]{12}([0-9]{3})?$/',
125:
126: 'MC' => '/^5[1-5][0-9]{14}$/',
127:
128: 'AE' => '/^3[47][0-9]{13}$/',
129:
130: 'DI' => '/^6011[0-9]{12}$/',
131:
132: 'JCB' => '/^(3[0-9]{15}|(2131|1800)[0-9]{11})$/'
133: );
134:
135: foreach ($ccTypeRegExpList as $ccTypeMatch=>$ccTypeRegExp) {
136: if (preg_match($ccTypeRegExp, $ccNumber)) {
137: $ccType = $ccTypeMatch;
138: break;
139: }
140: }
141:
142: if (!$this->OtherCcType($info->getCcType()) && $ccType!=$info->getCcType()) {
143: $errorMsg = Mage::helper('payment')->__('Credit card number mismatch with credit card type.');
144: }
145: }
146: else {
147: $errorMsg = Mage::helper('payment')->__('Invalid Credit Card Number');
148: }
149:
150: }
151: else {
152: $errorMsg = Mage::helper('payment')->__('Credit card type is not allowed for this payment method.');
153: }
154:
155:
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 = Mage::helper('payment')->__('Please enter a valid credit card verification number.');
161: }
162: }
163:
164: if ($ccType != 'SS' && !$this->_validateExpDate($info->getCcExpYear(), $info->getCcExpMonth())) {
165: $errorMsg = Mage::helper('payment')->__('Incorrect credit card expiration date.');
166: }
167:
168: if($errorMsg){
169: Mage::throwException($errorMsg);
170: }
171:
172:
173: if ($this->getIsCentinelValidationEnabled()) {
174: $this->getCentinelValidator()->validate($this->getCentinelValidationData());
175: }
176:
177: return $this;
178: }
179:
180: public function hasVerification()
181: {
182: $configData = $this->getConfigData('useccv');
183: if(is_null($configData)){
184: return true;
185: }
186: return (bool) $configData;
187: }
188:
189: public function getVerificationRegEx()
190: {
191: $verificationExpList = array(
192: 'VI' => '/^[0-9]{3}$/',
193: 'MC' => '/^[0-9]{3}$/',
194: 'AE' => '/^[0-9]{4}$/',
195: 'DI' => '/^[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: );
202: return $verificationExpList;
203: }
204:
205: protected function _validateExpDate($expYear, $expMonth)
206: {
207: $date = Mage::app()->getLocale()->date();
208: if (!$expYear || !$expMonth || ($date->compareYear($expYear) == 1)
209: || ($date->compareYear($expYear) == 0 && ($date->compareMonth($expMonth) == 1))
210: ) {
211: return false;
212: }
213: return true;
214: }
215:
216: public function OtherCcType($type)
217: {
218: return $type=='OT';
219: }
220:
221: 222: 223: 224: 225: 226:
227: public function validateCcNum($ccNumber)
228: {
229: $cardNumber = strrev($ccNumber);
230: $numSum = 0;
231:
232: for ($i=0; $i<strlen($cardNumber); $i++) {
233: $currentNum = substr($cardNumber, $i, 1);
234:
235: 236: 237:
238: if ($i % 2 == 1) {
239: $currentNum *= 2;
240: }
241:
242: 243: 244:
245: if ($currentNum > 9) {
246: $firstNum = $currentNum % 10;
247: $secondNum = ($currentNum - $firstNum) / 10;
248: $currentNum = $firstNum + $secondNum;
249: }
250:
251: $numSum += $currentNum;
252: }
253:
254: 255: 256:
257: return ($numSum % 10 == 0);
258: }
259:
260: 261: 262: 263: 264: 265:
266: public function validateCcNumOther($ccNumber)
267: {
268: return preg_match('/^\\d+$/', $ccNumber);
269: }
270:
271: 272: 273: 274: 275: 276:
277: public function isAvailable($quote = null)
278: {
279: return $this->getConfigData('cctypes', ($quote ? $quote->getStoreId() : null))
280: && parent::isAvailable($quote);
281: }
282:
283: 284: 285: 286: 287:
288: public function getIsCentinelValidationEnabled()
289: {
290: return false !== Mage::getConfig()->getNode('modules/Mage_Centinel') && 1 == $this->getConfigData('centinel');
291: }
292:
293: 294: 295: 296: 297:
298: public function getCentinelValidator()
299: {
300: $validator = Mage::getSingleton('centinel/service');
301: $validator
302: ->setIsModeStrict($this->getConfigData('centinel_is_mode_strict'))
303: ->setCustomApiEndpointUrl($this->getConfigData('centinel_api_url'))
304: ->setStore($this->getStore())
305: ->setIsPlaceOrder($this->_isPlaceOrder());
306: return $validator;
307: }
308:
309: 310: 311: 312: 313:
314: public function getCentinelValidationData()
315: {
316: $info = $this->getInfoInstance();
317: $params = new Varien_Object();
318: $params
319: ->setPaymentMethodCode($this->getCode())
320: ->setCardType($info->getCcType())
321: ->setCardNumber($info->getCcNumber())
322: ->setCardExpMonth($info->getCcExpMonth())
323: ->setCardExpYear($info->getCcExpYear())
324: ->setAmount($this->_getAmount())
325: ->setCurrencyCode($this->_getCurrencyCode())
326: ->setOrderNumber($this->_getOrderId());
327: return $params;
328: }
329:
330: 331: 332: 333: 334:
335: private function _getOrderId()
336: {
337: $info = $this->getInfoInstance();
338:
339: if ($this->_isPlaceOrder()) {
340: return $info->getOrder()->getIncrementId();
341: } else {
342: if (!$info->getQuote()->getReservedOrderId()) {
343: $info->getQuote()->reserveOrderId();
344: }
345: return $info->getQuote()->getReservedOrderId();
346: }
347: }
348:
349: 350: 351: 352: 353:
354: private function _getAmount()
355: {
356: $info = $this->getInfoInstance();
357: if ($this->_isPlaceOrder()) {
358: return (double)$info->getOrder()->getQuoteBaseGrandTotal();
359: } else {
360: return (double)$info->getQuote()->getBaseGrandTotal();
361: }
362: }
363:
364: 365: 366: 367: 368:
369: private function _getCurrencyCode()
370: {
371: $info = $this->getInfoInstance();
372:
373: if ($this->_isPlaceOrder()) {
374: return $info->getOrder()->getBaseCurrencyCode();
375: } else {
376: return $info->getQuote()->getBaseCurrencyCode();
377: }
378: }
379:
380: 381: 382: 383: 384:
385: private function _isPlaceOrder()
386: {
387: $info = $this->getInfoInstance();
388: if ($info instanceof Mage_Sales_Model_Quote_Payment) {
389: return false;
390: } elseif ($info instanceof Mage_Sales_Model_Order_Payment) {
391: return true;
392: }
393: }
394: }
395: