diff --git a/commerce_realex.module b/commerce_realex.module index e1b86a0..5135af1 100644 --- a/commerce_realex.module +++ b/commerce_realex.module @@ -150,17 +150,65 @@ function _commerce_realex_supported_card_types() { } /** + * Function to autodetect card type + */ +function _commerce_realex_autodetect_card_type($cardnumber) { + $type = ''; + + if(preg_match("/^5[1-5]/", $cardnumber)) { + $type = 'mastercard'; + } + elseif(preg_match("/^401179/", $cardnumber)) { + $type = 'delta'; + } + elseif(preg_match("/^(3713|3797|45443)/", $cardnumber)) { + $type = 'delta'; + } + elseif(preg_match("/^(6304|6706|6771|6709)/", $cardnumber)) { + $type = 'laser'; + } + elseif (preg_match("/^49/", $cardnumber)) { + $type = 'switch'; + } + elseif (preg_match("/^(564182|633110)/", $cardnumber)) { + $type = 'switch'; + } + elseif (preg_match("/^(6333|6759)/", $cardnumber)) { + $type = 'switch'; + } + elseif (preg_match("/^(6334|6767)/", $cardnumber)) { + $type = 'solo'; + } + elseif(preg_match("/^4/", $cardnumber)) { + $type = 'visa'; + } + elseif(preg_match("/^3[4-7]/", $cardnumber)) { + $type = 'amex'; + } + elseif(preg_match("/^67/", $cardnumber)) { + $type = 'maestro'; + } + elseif(preg_match("/^(300|305)/", $cardnumber) || + preg_match("/^3[68]/", $cardnumber)) { + $type = 'dc'; + } + + return $type ? $type : 'unknown'; +} + +/** * Parse the response XML and create and object. * * Code below is based on sample code provided by Realex at http://resource.realexpayments.com/m.php?ct=integration_oscode.php */ class RealexParser { - // Initialise variables. - var $parser; - var $record; - var $timestamp; - var $field_type; + // Initialise variables. + var $parser; + var $parentElements = array(); + var $currentElement = 0; + var $currentTSSCheck = ""; + var $record = array(); function RealexParser($response) { // Create and initialise XML parser @@ -169,62 +217,58 @@ class RealexParser { xml_set_element_handler($this->parser, 'startElement', 'endElement'); xml_set_character_data_handler($this->parser, 'cDataHandler'); - // 1 = single field, 2 = array field, 3 = record container - $this->field_type = array('response' =>1, - 'orderid' => 1, - 'authcode' => 1, - 'result' => 2, - 'message' => 1, - 'pasref' => 1, - 'batchid' => 1, - 'md5hash' => 1, - 'sha1hash' => 1, - 'cvnresult' => 1, - 'dccinfo' => 2, - 'cardholdercurrency' => 1, - 'cardholderamount' => 1, - 'cardholderrate' => 1, - 'merchantcurrency' => 1, - 'merchantamount' => 1, - ); - xml_parse($this->parser, $response); xml_parser_free($this->parser); } - /** - * The 'startElement()' function is called when an open element tag is found. - * It creates a variable on the fly contructed of all the parent elements - * joined together with an underscore. So the following xml: - * Owen - * would create two variables: $RESPONSE and $RESPONSE_SOMETHING - */ - function startElement($parser, $element, &$attrs) { - $element = strtolower($element); - $this->current_field = $element; + /* THe "startElement()" function is called when an open element tag is found. + It creates a variable on the fly contructed of all the parent elements + joined together with an underscore. So the following xml: + + Owen + would create two variables: + $RESPONSE and $RESPONSE_SOMETHING + */ + function startElement($parser, $name, $attrs) { + $name = strtolower($name); + array_push($this->parentElements, $name); + $this->currentElement = join("_", $this->parentElements); + + foreach ($attrs as $attr => $value) { + if ($this->currentElement == "response_tss_check" and $attr == "ID") { + $this->currentTSSCheck = $value; + } - if ($element == 'response' && $attrs['TIMESTAMP']) { - $this->record['timestamp'] = $attrs['TIMESTAMP']; + if ($this->currentElement == 'response' and $attr == "TIMESTAMP") { + $this->record['timestamp'] = $value; + } } + + // Clean up the element names to remove the response_ prefix. + $this->currentElement = str_replace('response_', '', $this->currentElement); } - function endElement($parser, $element) { - $element = strtolower($element); - // $this->current_field = ''; + /* The "cDataHandler()" function is called when the parser encounters any text that's + not an element. Simply places the text found in the variable that + was last created. So using the XML example above the text "Owen" + would be placed in the variable $RESPONSE_SOMETHING + */ + function cDataHandler($parser, $cdata) { + if ( trim ( $cdata ) ) { + if ($this->currentTSSCheck != 0) { + $this->record['tsschecks']["$this->currentTSSCheck"] = $cdata; + } + + $this->record[$this->currentElement] = $cdata; + } } - /** - * The 'cDataHandler()' function is called when the parser encounters any text that's - * not an element. Simply places the text found in the variable that - * was last created. So using the XML example above the text 'Owen' - * would be placed in the variable $RESPONSE_SOMETHING - */ - function cDataHandler($parser, $text) { - if ($text != ' ') { - if (!empty($this->current_field)) { - $this->record[$this->current_field] = $text; - } - } + // The "endElement()" function is called when the closing tag of an element is found. + // Just removes that element from the array of parent elements. + function endElement($parser, $name) { + $this->currentTSSCheck = 0; + array_pop($this->parentElements); } + } diff --git a/commerce_realex_remote.inc b/commerce_realex_remote.inc index 215ce3f..fdc85d6 100644 --- a/commerce_realex_remote.inc +++ b/commerce_realex_remote.inc @@ -86,6 +86,12 @@ function commerce_realex_remote_commerce_payment_method_settings_form($settings '#required' => TRUE, ); + $form['card_types_autodetect'] = array( + '#type' => 'checkbox', + '#title' => t('Autodetect card type'), + '#default_value' => isset($settings['card_types_autodetect']) ? $settings['card_types_autodetect'] : FALSE, + ); + $form['cctype_subaccounts_enabled'] = array( '#type' => 'checkbox', '#title' => t('Use separate accounts for each card type'), @@ -137,6 +143,11 @@ function commerce_realex_remote_commerce_payment_method_submit_form($payment_met 'code' => '', ); + //Add autodetect card. + if ($payment_method['settings']['card_types_autodetect']) { + unset($credit_card_settings['type']); + } + // Get credit card fields. $form = commerce_payment_credit_card_form($credit_card_settings); @@ -156,7 +167,12 @@ function commerce_realex_remote_commerce_payment_method_submit_form_validate($pa ); $prefix = implode('][', $settings['form_parents']) . ']['; - $card_type = $pane_values['credit_card']['type']; + if ($payment_method['settings']['card_types_autodetect']) { + $card_type = _commerce_realex_autodetect_card_type($pane_values['credit_card']['number']); + } + else { + $card_type = $pane_values['credit_card']['type']; + } if ($card_type == 'switch') { if (empty($pane_values['credit_card']['issue'])) { form_set_error($prefix . 'issue', t('Issue number field is required.')); @@ -203,13 +219,20 @@ function commerce_realex_remote_commerce_payment_method_submit_form_submit($paym //$request['dcc_provider'] = $payment_method['settings']['dcc_provider']; $request['chname'] = $pane_values['credit_card']['owner']; - $request['cctype'] = _commerce_realex_get_card_type($pane_values['credit_card']['type']); $request['ccnumber'] = $pane_values['credit_card']['number']; $request['cvn'] = isset($pane_values['credit_card']['code']) ? $pane_values['credit_card']['code'] : NULL; $request['issueno'] = isset($pane_values['credit_card']['issue']) ? $pane_values['credit_card']['issue'] : ''; $request['start_date'] = $start_date; $request['expiry_date'] = $expiry_date; + //Auto detect type + if ($payment_method['settings']['card_types_autodetect']) { + $request['cctype'] = _commerce_realex_get_card_type(_commerce_realex_autodetect_card_type($pane_values['credit_card']['number'])); + } + else { + $request['cctype'] = _commerce_realex_get_card_type($pane_values['credit_card']['type']); + } + // Sub-accounts can differ by card type if ($payment_method['settings']['cctype_subaccounts_enabled']) { $subaccount = $payment_method['settings']['cctype_accounts'][$pane_values['credit_card']['type']]; @@ -331,7 +354,13 @@ function commerce_realex_remote_get_dcc_offer($payment_method, $pane_values, &$o $request['dcc_provider'] = $payment_method['settings']['dcc_provider']; $request['chname'] = $pane_values['credit_card']['owner']; - $request['cctype'] = _commerce_realex_get_card_type($pane_values['credit_card']['type']); + //Auto detect type + if ($payment_method['settings']['card_types_autodetect']) { + $request['cctype'] = _commerce_realex_autodetect_card_type($pane_values['credit_card']['number']); + } + else { + $request['cctype'] = _commerce_realex_get_card_type($pane_values['credit_card']['type']); + } $request['ccnumber'] = $pane_values['credit_card']['number']; $request['cvn'] = isset($pane_values['credit_card']['code']) ? $pane_values['credit_card']['code'] : NULL; $request['issueno'] = isset($pane_values['credit_card']['issue']) ? $pane_values['credit_card']['issue'] : '';