Index: uc_moneris.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/uc_moneris/uc_moneris.module,v
retrieving revision 1.3
diff -u -p -r1.3 uc_moneris.module
--- uc_moneris.module	30 Apr 2009 20:58:11 -0000	1.3
+++ uc_moneris.module	11 Jun 2009 16:29:03 -0000
@@ -59,7 +59,13 @@ function uc_moneris_form_alter($form_id,
     }
   }
 }
-
+
+/*
+ * Return the currently configured transaction type (purchase, or us_purchase)
+ */
+function uc_moneris_transaction_type() {
+  return variable_get('moneris_api_version', '') . variable_get('moneris_transaction_type', 'purchase'); 
+}
 /**
 * @desc Initial check for all Visa cards so that we can determine if they are enrolled or not in VBV
 */
@@ -228,6 +234,16 @@ function uc_moneris_settings_form() {
   $form['moneris_settings'] = array(
     '#type' => 'fieldset',
     '#title' => t('Moneris.com settings'),
+  );
+  $form['moneris_settings']['moneris_api_version'] = array(
+    '#type' => 'select',
+    '#title' => t('API Version'),
+    '#description'=> t('The Moneris API differs slightly between the US and Canadian versions.'),
+    '#default_value' => variable_get('moneris_api_version', ''),
+    '#options' => array(
+      '' => t('Canada'),
+      'us_' => t('United States'),
+    ),
   );
   $form['moneris_settings']['moneris_store_id'] = array(
     '#type' => 'textfield',
@@ -241,12 +257,15 @@ function uc_moneris_settings_form() {
     '#default_value' => variable_get('moneris_api_token', ''),
     '#description' => t('Your API Token key for sending data.'),
   );
-  $form['moneris_settings']['moneris_transaction_type'] = array(
-    '#type' => 'select',
-    '#title' => t('Transaction type to use'),
-    '#options' => array('purchase' => 'Purchase', 'preauth' => 'PreAuth'),
-    '#default_value' => variable_get('moneris_transaction_type', 'purchase'),
-    '#description' => t('Use purchase to charge the card immediately after authentication. Use PreAuth to lock the funds at authentication time and then Capture the funds at a later time.'),
+  $form['moneris_settings']['moneris_transaction_type'] = array(
+    '#type' => 'select',
+    '#title' => t('Transaction type to use'),
+    '#options' => array(
+      'purchase' => 'Purchase (PreAuth if Necessary)',
+      'preauth' => 'PreAuth Only'
+    ),
+    '#default_value' => variable_get('moneris_transaction_type', 'purchase'),
+    '#description' => t('Use purchase to charge the card immediately after authentication. When CVV/CVD or Address Verification is enabled, a PreAuth will be perofrmed automatically. Use PreAuth Only to lock the funds at authentication time and then Capture the funds at a later time.'),
   );
 
   $form['moneris_settings']['moneris_cvv_enable'] = array(
@@ -255,7 +274,19 @@ function uc_moneris_settings_form() {
     '#options' => array('disabled' => 'Not Required', 'enabled' => 'Required'),
     '#default_value' => variable_get('moneris_cvv_enable', 'disabled'),
     '#description' => t('eFraud must be enabled on your Moneris account.'),
-  );
+  );
+  
+  $form['moneris_settings']['moneris_avs_enable'] = array(
+    '#type' => 'select',
+    '#title' => t('Use Address Verification (AVS)'),
+    '#options' => array(
+      'disabled' => t('Disabled'),
+      'enabled' => t('Enabled'),
+    ),
+    '#default_value' => variable_get('moneris_avs_enable', 'disabled'),
+    '#description' => t('eFraud must be enabled on your Moneris account.'),
+  );
+
   $form['moneris_settings']['moneris_vbv_enable'] = array(
     '#type' => 'select',
     '#title' => t('Enable VBV (Verified by VISA)'),
@@ -300,8 +331,10 @@ function uc_moneris_charge($order_id, $a
   /**************************** Request Variables *******************************/
   $store_id   = variable_get('moneris_store_id', '');
   $api_token  = variable_get('moneris_api_token', '');
-  $use_cvv    = variable_get('moneris_cvv_enable', 'disabled');
-  $txn_type    = variable_get('moneris_transaction_type', 'purchase');
+  $use_cvv    = variable_get('moneris_cvv_enable', 'disabled');
+  $use_avs    = variable_get('moneris_avs_enable', 'disabled');
+  $txn_type    = uc_moneris_transaction_type();
+  drupal_set_message("txn type is $txn_type");
   // Use the MonthDayHoursMinutesSeconds as the unique prefix
   $xid = 'cs'. date("mdHis", time()) . str_pad($order->order_id, 8, '0', STR_PAD_LEFT);    // Must be 20 Alpha/Numeric Chars exactly
 
@@ -367,10 +400,32 @@ function uc_moneris_charge($order_id, $a
   }
 
   // This is either a PreAuth or a Purchase transaction
-  if (!$txn_number) {
+  if (!$txn_number) {
+    $this_trans_type = $txnType;
+    if($use_cvv == 'enabled'){
+      $cvdTemplate = array(
+        'cvd_indicator' => '1', // 0 = No merchant supplied field, 1 = CVV required, 2 = Field required, but number on card is illegible, 9 = Cardholder states there is no CVD on card
+        'cvd_value' => $order->payment_details['cc_cvv'],
+      );
+      $mpgCvdInfo   = new mpgCvdInfo($cvdTemplate);
+      $this_trans_type = 'us_preauth';
+    }
+
+    if ($use_avs == 'enabled') {
+      $street_number = explode(' ', $order->billing_street1);
+      $street_number = $street_number[0];
+      $street_name = substr($order->billing_street1, strlen($street_number) + 1);
+      $avsTemplate = array(        
+        'avs_street_number' => $street_number,
+        'avs_street_name' => $street_name,
+        'avs_zipcode' => $order->billing_postal_code,
+      );
+      $this_trans_type = 'us_preauth';
+      $mpgAvsInfo = new mpgAvsInfo($avsTemplate);
+    }
     /*********************** Transactional Associative Array **********************/
     $txn_array = array(
-      'type'        => $txn_type,
+      'type'        => $this_trans_type,
       'order_id'    => $xid,
       'cust_id'     => $order->uid,
       'amount'      => number_format($amount, 2, '.', ''),
@@ -386,19 +441,84 @@ function uc_moneris_charge($order_id, $a
     $mpgTxn       = new mpgTransaction($txn_array);
     /****************************** Add the CVD/CVV ******************************/
     if ($use_cvv == 'enabled') {
-      $cvdTemplate = array(
-        'cvd_indicator' => '1', // 0 = No merchant supplied field, 1 = CVV required, 2 = Field required, but number on card is illegible, 9 = Cardholder states there is no CVD on card
-        'cvd_value' => $order->payment_details['cc_cvv'],
-      );
-      $mpgCvdInfo   = new mpgCvdInfo($cvdTemplate);
       $mpgTxn->setCvdInfo($mpgCvdInfo);
+    }
+    if ($use_avs == 'enabled') {
+      $mpgTxn->setAvsInfo($mpgAvsInfo);
     }
     /****************************** Request Object *******************************/
     $mpgRequest   = new mpgRequest($mpgTxn);
     /***************************** HTTPS Post Object *****************************/
     $mpgHttpPost  = new mpgHttpsPost($store_id, $api_token, $mpgRequest);
     /******************************* Response ************************************/
-    $mpgResponse  = $mpgHttpPost->getMpgResponse();
+    $mpgResponse  = $mpgHttpPost->getMpgResponse();
+    $response_code = $mpgResponse->getResponseCode();
+    $txn_number    = $mpgResponse->getTxnNumber();
+    $completed = $mpgResponse->getComplete();
+    //watchdog('uc_moneris', 'preauth mpgResponse is <pre> '. print_r($mpgResponse, TRUE) . '</pre>');
+    //Check the CVD?
+    if ($use_cvv == 'enabled') {
+      $cvd_response = $mpgResponse->getCvdResultCode();
+      if (substr($cvd_response, 1, 1) != 'M') {
+        $result = array(
+          'success' => FALSE,
+          'comment' => t('CVV Verification failed with Moneris code @code', array('@code' => $cvd_response)),
+          'message' => t('CVV Verification failed with Moneris code @code', array('@code' => $cvd_response)),
+          'uid' => $user->uid,
+        );
+        uc_order_save($order);
+        uc_order_comment_save($order_id, $user->uid, $message, 'admin');
+        $_SESSION['uc_moneris'] = null;
+       unset($_SESSION['uc_moneris']);
+       //We use an ambiguous error message because cvv verification fails when other card information, such as the expiration date
+       //is in correct, and can therefore confuse users about what's wrong with the information they entered.
+       drupal_set_message(t("Unable to verify card information"));
+       return $result;
+      } 
+    }
+    if ($use_avs == 'enabled') {
+      $avs_response = $mpgResponse->getAvsResultCode();
+      $avs_accept = array();
+      if ($order->billing_country == 840) {
+        $avs_accept = array('Z', 'Y', 'P', 'D', 'M');
+      }
+      else {
+        $avs_accept = array('A', 'B', 'D', 'M', 'P', 'Y', 'Z'); 
+      }
+      if (!in_array($avs_response, $avs_accept)) {
+        $message = t('AVS Verification failed with Moneris code @code', array('@code' => $avs_response));
+        $result = array(
+          'success' => FALSE,
+          'comment' => $message,
+          'message' => $message,
+          'uid' => $user->uid,
+        );
+        uc_order_save($order);
+        uc_order_comment_save($order_id, $user->uid, $message, 'admin');
+        $_SESSION['uc_moneris'] = null;
+        unset($_SESSION['uc_moneris']);
+        drupal_set_message(t("Unable to verify billing address."));
+        return $result;
+      }
+    }
+
+    if (($this_trans_type == 'us_preauth' && $txnType == 'us_purchase') && intval($response_code) < 49 || $completed == 'TRUE') {
+      //The previous transaction was a preauth before a capture. Run the transaction again in Capture mode.
+      $txnArray = array(
+        'type'        => 'us_completion', 
+        'txn_number'  => $txn_number, 
+        'order_id'    => $xid, 
+        'comp_amount' => number_format($amount, 2, '.', ''), 
+        'crypt_type'  => '7',
+      );
+      $mpgTxn       = new mpgTransaction($txnArray); 
+      $mpgRequest   = new mpgRequest($mpgTxn); 
+      $mpgHttpPost  = new mpgHttpsPost($store_id, $api_token, $mpgRequest); 
+      $mpgResponse  = $mpgHttpPost->getMpgResponse(); 
+      //watchdog('uc_moneris', 'preauth sucessfull, running capture');
+      //watchdog('uc_moneris', 'capture request <pre> ' . print_r($mpgRequest, TRUE) . '</pre>');
+      //watchdog('uc_moneris', 'capture response <pre>'. print_r($mpgResponse, TRUE) . '</pre>');
+    }
   }
   // This is a Completion called by a manager/clerk after a PreAuth
   else{
