<?php
/*
  $Id: qbms.php,v 1.9a 2009/05/18  $

  Released under the GNU General Public License

  Copyright (c) 2009 Kali Systems LLC - http://www.kalisystems.com
  Copyright (c) 2007 International Council for Gender Studies - http://www.fiveaspects.com

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
*/

class qbms extends base {

  var $code, $title, $description, $enabled;
  
  // class constructor
  function qbms() {
    global $order;

    $this->code = 'qbms';
    $this->title = MODULE_PAYMENT_QBMS_TEXT_TITLE;
    $this->public_title = MODULE_PAYMENT_QBMS_TEXT_PUBLIC_TITLE;
    $this->description = MODULE_PAYMENT_QBMS_TEXT_DESCRIPTION;
    $this->sort_order = MODULE_PAYMENT_QBMS_SORT_ORDER;
    $this->enabled = ((MODULE_PAYMENT_QBMS_STATUS == 'True') ? true : false);
	
	if ((int)MODULE_PAYMENT_QBMS_ORDER_STATUS_ID > 0) {
	  $this->order_status = MODULE_PAYMENT_QBMS_ORDER_STATUS_ID;
      }
	  
	if (is_object($order)) $this->update_status();
  }

  
  // class methods
  // function update_status: Purpose it so check whether this payment module is available during runtime with an order.
  function update_status() {
      global $order, $db;

      if ( ($this->enabled == true) && ((int)MODULE_PAYMENT_QBMS_ZONE > 0) ) {
        $check_flag = false;
        $check = $db->Execute("select zone_id from " . TABLE_ZONES_TO_GEO_ZONES . " where geo_zone_id = '" . MODULE_PAYMENT_QBMS_ZONE . "' and zone_country_id = '" . $order->billing['country']['id'] . "' order by zone_id");
        while (!$check->EOF) {
          if ($check->fields['zone_id'] < 1) {
            $check_flag = true;
            break;
          } elseif ($check->fields['zone_id'] == $order->billing['zone_id']) {
            $check_flag = true;
            break;
          }
        	
 	 $check->MoveNext();
        }

        if ($check_flag == false) {
          $this->enabled = false;
        }
      }
    }


  // function javascript_validation: Validates the submitted payment details.
  function javascript_validation() {
      $js = '  if (payment_value == "' . $this->code . '") {' . "\n" .   
            '    var cc_owner = document.checkout_payment.qbms_cc_owner.value;' . "\n" .
            '    var cc_number = document.checkout_payment.qbms_cc_number.value;' . "\n" .
            '    if (cc_owner == "" || cc_owner.length < ' . CC_OWNER_MIN_LENGTH . ') {' . "\n" .
            '      error_message = error_message + "' . MODULE_PAYMENT_QBMS_TEXT_JS_CC_OWNER . '";' . "\n" .
            '      error = 1;' . "\n" .
            '    }' . "\n" .
            '    if (cc_number == "" || cc_number.length < ' . CC_NUMBER_MIN_LENGTH . ') {' . "\n" .
            '      error_message = error_message + "' . MODULE_PAYMENT_QBMS_TEXT_JS_CC_NUMBER . '";' . "\n" .
            '      error = 1;' . "\n" .
            '    }' . "\n";
                 if (MODULE_PAYMENT_QBMS_VERIFY_WITH_CVV2 == 'True') {
     $js .= '    var cc_cvv2 = document.checkout_payment.qbms_cc_cvv2.value;' . "\n" .
            '    if (cc_cvv2 == "" || cc_cvv2.length < ' . 3 . ') {' . "\n" .
            '      error_message = error_message + "' . MODULE_PAYMENT_QBMS_TEXT_JS_CC_CVV2 . '";' . "\n" .
            '      error = 1;' . "\n" .
            '    }' . "\n";
           }
     $js .= '  }' . "\n";
     return $js;
  }
	
	
  // function selection: Provides a set of form information when this module is selected by the customer.  Allows him to enter the credit card owner, number, and expiration date.
      function selection() {
      global $order;

      for ($i=1; $i<13; $i++) {
        $expires_month[] = array('id' => sprintf('%02d', $i), 'text' => strftime('%B',mktime(0,0,0,$i,1,2000)));
      }

      $today = getdate(); 
      for ($i=$today['year']; $i < $today['year']+10; $i++) {
        $expires_year[] = array('id' => strftime('%y',mktime(0,0,0,1,1,$i)), 'text' => strftime('%Y',mktime(0,0,0,1,1,$i)));
      }
	  if (MODULE_PAYMENT_QBMS_VERIFY_WITH_CVV2 == 'True') {
        $selection = array('id' => $this->code,
                           'module' => $this->title,
                           'fields' => array(array('title' => MODULE_PAYMENT_QBMS_TEXT_CREDIT_CARD_OWNER,
                                                   'field' => zen_draw_input_field('qbms_cc_owner', $order->billing['firstname'] . ' ' . $order->billing['lastname'], 'maxlength="30"')),
                                             array('title' => MODULE_PAYMENT_QBMS_TEXT_CREDIT_CARD_NUMBER,
                                                   'field' => zen_draw_input_field('qbms_cc_number', '', 'maxlength="16"')),
                                             array('title' => MODULE_PAYMENT_QBMS_TEXT_CREDIT_CARD_EXPIRES,
                                                   'field' => zen_draw_pull_down_menu('qbms_cc_expires_month', $expires_month) . '&nbsp;' . zen_draw_pull_down_menu('qbms_cc_expires_year', $expires_year)),
						   array('title' => MODULE_PAYMENT_QBMS_TEXT_CREDIT_CARD_CVV2,
						         'field' => zen_draw_input_field('qbms_cc_cvv2', '', 'size="4" maxlength="4"')))); 
      } else {
		$selection = array('id' => $this->code,
                           'module' => $this->title,
                           'fields' => array(array('title' => MODULE_PAYMENT_QBMS_TEXT_CREDIT_CARD_OWNER,
                                                   'field' => zen_draw_input_field('qbms_cc_owner', $order->billing['firstname'] . ' ' . $order->billing['lastname'], 'maxlength="30"')),
                                             array('title' => MODULE_PAYMENT_QBMS_TEXT_CREDIT_CARD_NUMBER,
                                                   'field' => zen_draw_input_field('qbms_cc_number', '', 'maxlength="16"')),
                                             array('title' => MODULE_PAYMENT_QBMS_TEXT_CREDIT_CARD_EXPIRES,
                                                   'field' => zen_draw_pull_down_menu('qbms_cc_expires_month', $expires_month) . '&nbsp;' . zen_draw_pull_down_menu('qbms_cc_expires_year', $expires_year))));}

      return $selection;
    }


    // function pre_confirmation_check: Validates the details that have been submitted for the form created in selection() (see above).
    function pre_confirmation_check() {
      global $_POST;
      global $messageStack;

      include(DIR_WS_CLASSES . 'cc_validation.php');

      $cc_validation = new cc_validation();
      $result = $cc_validation->validate($_POST['qbms_cc_number'], $_POST['qbms_cc_expires_month'], $_POST['qbms_cc_expires_year']);
      $error = '';
      switch ($result) {
        case -1:
          $error = sprintf(TEXT_CCVAL_ERROR_UNKNOWN_CARD, substr($cc_validation->cc_number, 0, 4));
          break;
        case -2:
        case -3:
        case -4:
          $error = TEXT_CCVAL_ERROR_INVALID_DATE;
          break;
        case false:
          $error = TEXT_CCVAL_ERROR_INVALID_NUMBER;
          break;
      }

      if ( ($result == false) || ($result < 1) ) {

         $messageStack->add_session('checkout_payment', $error, 'error');
         zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, '', 'SSL', true, false));
      }

      $this->cc_card_type = $cc_validation->cc_type;
      $this->cc_card_number = $cc_validation->cc_number;
      $this->cc_expiry_month = $cc_validation->cc_expiry_month;
      $this->cc_expiry_year = $cc_validation->cc_expiry_year;

    }
	
      // function confirmation: Purpose is to confirm to the user the details that will be used to process the order. 
      // Once again this is in an array format that defines keys that will be read in on the confirmation page.
      function confirmation() {
      global $_POST;

      if (MODULE_PAYMENT_QBMS_VERIFY_WITH_CVV2 == 'True') {
	    $confirmation = array('title' => $this->title . ': ' . $this->cc_card_type,
                              'fields' => array(array('title' => MODULE_PAYMENT_QBMS_TEXT_CREDIT_CARD_OWNER,
                                                      'field' => $_POST['qbms_cc_owner']),
                                                array('title' => MODULE_PAYMENT_QBMS_TEXT_CREDIT_CARD_NUMBER,
                                                      'field' => substr($this->cc_card_number, 0, 4) . str_repeat('X', (strlen($this->cc_card_number) - 8)) . substr($this->cc_card_number, -4)),
                                                array('title' => MODULE_PAYMENT_QBMS_TEXT_CREDIT_CARD_EXPIRES,
                                                      'field' => strftime('%B, %Y', mktime(0,0,0,$_POST['qbms_cc_expires_month'], 1, '20' . $_POST['qbms_cc_expires_year']))),
						      array('title' => MODULE_PAYMENT_QBMS_TEXT_CREDIT_CARD_CVV2,
				       		     'field' => $_POST['qbms_cc_cvv2'])));
	  } else {
	    $confirmation = array('title' => $this->title . ': ' . $this->cc_card_type,
                              'fields' => array(array('title' => MODULE_PAYMENT_QBMS_TEXT_CREDIT_CARD_OWNER,
                                                      'field' => $_POST['qbms_cc_owner']),
                                                array('title' => MODULE_PAYMENT_QBMS_TEXT_CREDIT_CARD_NUMBER,
                                                      'field' => substr($this->cc_card_number, 0, 4) . str_repeat('X', (strlen($this->cc_card_number) - 8)) . substr($this->cc_card_number, -4)),
                                                array('title' => MODULE_PAYMENT_QBMS_TEXT_CREDIT_CARD_EXPIRES,
                                                      'field' => strftime('%B, %Y', mktime(0,0,0,$_POST['qbms_cc_expires_month'], 1, '20' . $_POST['qbms_cc_expires_year'])))));}

      return $confirmation;
    }
	
    // function process_button: This allows us to place in hidden form fields into the confirmation page. 
    // These are provided to you by your payment gateway. You will need to carefully verify which fields need 
    // to be placed here - as they are parsed through the request (only) to the next process:
    function process_button() {
    global $_POST, $order;
	  
	if (MODULE_PAYMENT_QBMS_VERIFY_WITH_CVV2 == 'True') {  
	  $process_button_string = zen_draw_hidden_field('CreditCardOwner', $_POST['qbms_cc_owner']) . 
	                           zen_draw_hidden_field('CreditCardNumber', $this->cc_card_number) . 
		    				   zen_draw_hidden_field('ExpirationMonth', $this->cc_expiry_month) . 
				        	   zen_draw_hidden_field('ExpirationYear', $this->cc_expiry_year) . 
							   zen_draw_hidden_field('Amount', number_format($order->info['total'], 2, '.', '')) . 
							   zen_draw_hidden_field('CreditCardAddress', substr($order->billing['street_address'],0,30)) . 
							   zen_draw_hidden_field('CreditCardPostalCode', substr($order->billing['postcode'],0,9)) .
							   zen_draw_hidden_field('CreditCardType', $this->cc_card_type) .
							   zen_draw_hidden_field('CardSecurityCode', $_POST['qbms_cc_cvv2']);

	} else {
	  $process_button_string = zen_draw_hidden_field('CreditCardOwner', $_POST['qbms_cc_owner']) . 
	                           zen_draw_hidden_field('CreditCardNumber', $this->cc_card_number) . 
		    				   zen_draw_hidden_field('ExpirationMonth', $this->cc_expiry_month) . 
				        	   zen_draw_hidden_field('ExpirationYear', $this->cc_expiry_year) . 
							   zen_draw_hidden_field('Amount', number_format($order->info['total'], 2, '.', '')) . 
							   zen_draw_hidden_field('CreditCardType', $this->cc_card_type) .
							   zen_draw_hidden_field('CreditCardAddress', substr($order->billing['street_address'],0,30)) . 
							   zen_draw_hidden_field('CreditCardPostalCode', substr($order->billing['postcode'],0,9));}
							 
	$process_button_string .= zen_draw_hidden_field(zen_session_name(), zen_session_id());

    return $process_button_string;
  }
	

  // function before_process: This function actually processes the credit card transaction through QBMS. 
  // If there is an error, for instance, if the credit card is declined, the order will not be processed 
  // and the user will be sent back to checkout_payment.php. (Removed $customer_id as useless)
  function before_process() {
    global $_POST, $db;
    global $messageStack;

      // Sets the application path either to the Testing or Production server also checking for hosted vs desktop.
      if(MODULE_PAYMENT_QBMS_HOSTEDORDESKTOP == 'Hosted') {
	 if(MODULE_PAYMENT_QBMS_TEST == 'True')
	   $QBMS_ApplicationPath = 'https://webmerchantaccount.ptc.quickbooks.com/j/AppGateway';
	 else
	   $QBMS_ApplicationPath = 'https://webmerchantaccount.quickbooks.com/j/AppGateway';
      }
      else {
        if(MODULE_PAYMENT_QBMS_TEST == 'True')
          $QBMS_ApplicationPath = 'https://merchantaccount.ptc.quickbooks.com/j/AppGateway';
        else
          $QBMS_ApplicationPath = 'https://merchantaccount.quickbooks.com/j/AppGateway';          
      }

	if(MODULE_PAYMENT_QBMS_HOSTEDORDESKTOP == 'Hosted') {
       // if Hosted, Get the Session Ticket
    	$QBMS_SessionTicket = $this->qbms_get_session_ticket($QBMS_ApplicationPath);
    	$QBMS_Auth = '
			<SignonTicketRq>
			<ClientDateTime>'.date('Y-m-d\TH:i:s').'</ClientDateTime>
			<SessionTicket>'.$QBMS_SessionTicket.'</SessionTicket>
			</SignonTicketRq>
    	';
	}
	else {
	    // else if Desktop, embed desktop request in the message
	    $QBMS_SessionTicket = '';
	    $QBMS_Auth = '
            <SignonDesktopRq>
                   <ClientDateTime>'.date('Y-m-d\TH:i:s').'0</ClientDateTime>
                   <ApplicationLogin>'.MODULE_PAYMENT_QBMS_APPLICATION_LOGIN.'</ApplicationLogin>
                   <ConnectionTicket>'.MODULE_PAYMENT_QBMS_CONNECTION_TICKET.'</ConnectionTicket>
                   <Language>English</Language>
                   <AppID>'.MODULE_PAYMENT_QBMS_APPID.'</AppID>
                   <AppVer>1.0</AppVer>
            </SignonDesktopRq>
	    ';

	}
	
	// Create a unique transaction id using the prefix ONLINE followed by 'customer id' followed by Order Amount
	// This prevents duplication of charges from the same customer within 15 minutes if it is the exact same $ amount.
	$transidamount = $_POST['Amount'] * 100;
	$QBMS_TransRequestID = $_SESSION['customer_id'] . 'ONLINE' . $transidamount;
  
	if (MODULE_PAYMENT_QBMS_VERIFY_WITH_CVV2 == 'True') {
	  $QBMS_XML_Credit_Card_Charge = '<?xml version="1.0"?>
	                                <?qbmsxml version="2.0"?>
		  							<QBMSXML>
			  						<SignonMsgsRq>'.$QBMS_Auth.'
									</SignonMsgsRq>
									<QBMSXMLMsgsRq>
									<CustomerCreditCardChargeRq>
									<TransRequestID>'.$QBMS_TransRequestID.'</TransRequestID>
									<CreditCardNumber>'.$_POST['CreditCardNumber'].'</CreditCardNumber>
									<ExpirationMonth>'.$_POST['ExpirationMonth'].'</ExpirationMonth>
									<ExpirationYear>'.$_POST['ExpirationYear'].'</ExpirationYear>
									<IsECommerce>true</IsECommerce>
									<Amount>'.$_POST['Amount'].'</Amount>
									<NameOnCard>'.$_POST['CreditCardOwner'].'</NameOnCard>
									<CreditCardAddress>'.$_POST['CreditCardAddress'].'</CreditCardAddress>
									<CreditCardPostalCode>'.$_POST['CreditCardPostalCode'].'</CreditCardPostalCode>
									<CardSecurityCode>'.$_POST['CardSecurityCode'].'</CardSecurityCode>
									</CustomerCreditCardChargeRq>
									</QBMSXMLMsgsRq>
									</QBMSXML>';
    } else {
	  $QBMS_XML_Credit_Card_Charge = '<?xml version="1.0"?>
	                                <?qbmsxml version="2.0"?>
									<QBMSXML>
									<SignonMsgsRq>'.$QBMS_Auth.'
									</SignonMsgsRq>
									<QBMSXMLMsgsRq>
									<CustomerCreditCardChargeRq>
									<TransRequestID>'.$QBMS_TransRequestID.'</TransRequestID>
									<CreditCardNumber>'.$_POST['CreditCardNumber'].'</CreditCardNumber>
									<ExpirationMonth>'.$_POST['ExpirationMonth'].'</ExpirationMonth>
									<ExpirationYear>'.$_POST['ExpirationYear'].'</ExpirationYear>
									<IsECommerce>true</IsECommerce>
									<Amount>'.$_POST['Amount'].'</Amount>
									<NameOnCard>'.$_POST['CreditCardOwner'].'</NameOnCard>
									<CreditCardAddress>'.$_POST['CreditCardAddress'].'</CreditCardAddress>
									<CreditCardPostalCode>'.$_POST['CreditCardPostalCode'].'</CreditCardPostalCode>
									</CustomerCreditCardChargeRq>
									</QBMSXMLMsgsRq>
									</QBMSXML>';}
									  
	$QBMS_chargeRq = $this->qbms_call($QBMS_ApplicationPath, $QBMS_XML_Credit_Card_Charge, MODULE_PAYMENT_QBMS_SSL_CERT);


	// Check for duplicates by capturing transaction ID and seeing if record exists already from a prior
	// transaction. Put up new error message if that is true.

	$qbmsidresult = 0;
	$TempString = strstr($QBMS_chargeRq, "<CreditCardTransID>");
	$EndLocation = strpos($TempString, "</CreditCardTransID>");
	$QBMS_CreditCardTransID = substr($TempString, 19, $EndLocation - 19);
	$sql = "select orders_id FROM " . TABLE_ORDERS_STATUS_HISTORY . " WHERE comments LIKE '%$QBMS_CreditCardTransID' LIMIT 0, 2";
	$qbmsidresult = $db->Execute($sql);
	$qbmsidresultnum = $qbmsidresult->RecordCount();

	// Get the statusCode
       $QBMS_ChargeRq_Status = 1;
       $posLeft  = strpos($QBMS_chargeRq, "<CustomerCreditCardChargeRs statusCode=\"")+strlen("<CustomerCreditCardChargeRs statusCode=\"");
       $posRight = strpos($QBMS_chargeRq, "\"", $posLeft+1);
       $QBMS_ChargeRq_Status = intval(substr($QBMS_chargeRq, $posLeft, $posRight-$posLeft));

	// If result is a duplicate - reset the ChargeRq_Status to 9999 and test case.

	if ($qbmsidresultnum != 0) {
		if ($QBMS_ChargeRq_Status == 0 OR $QBMS_ChargeRq_Status == 10100) {
		$QBMS_ChargeRq_Status = 9999;
		}
	}
	    
	// QBMS will return statusCode="0" or "10100" if charge was successful
	switch ($QBMS_ChargeRq_Status) {
	  case 9999:
		$error = MODULE_PAYMENT_QBMS_TEXT_DUPLICATE;
		break;
	  case 0:
	  case 10100:
		$this->qbms_charge_success($QBMS_chargeRq);
		return;
	  case 10301:
	  case 10400:
	  case 10401:
	  case 10402:
	  case 10404:
	  case 10407:
		$error = MODULE_PAYMENT_QBMS_TEXT_DECLINED;
		break;
	  case 10409:
		$error = MODULE_PAYMENT_QBMS_TEXT_VALIDATION;
		break;
	  default:
		$error = MODULE_PAYMENT_QBMS_TEXT_SYSTEM_ERROR;
		break;
      }
	
//      $payment_error_return = 'payment_error=' . $this->code . '&error=' . urlencode($error) . '&qbms_cc_owner=' . urlencode($_POST['CreditCardOwner']) . '&qbms_cc_expires_month=' . $_POST['ExpirationMonth'] . '&qbms_cc_expires_year=' . $_POST['ExpirationYear'];
//      zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, $payment_error_return, 'SSL', true, false));
      $messageStack->add_session('checkout_payment', $error, 'error');
      zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, '', 'SSL', true, false));

  }
	
	// function after_process: This is called after the order has been saved. I don’t usually have a need for this method.
       // This is used for appropriate QBMS cc details to be posted into admin order info and order history.
	function after_process() {
	  global $insert_id, $db, $order;
	  $sql = "insert into " . TABLE_ORDERS_STATUS_HISTORY . " (comments, orders_id, orders_status_id, date_added) values (:orderComments, :orderID, :orderStatus, now() )";
	  $sql = $db->bindVars($sql, ':orderComments', '[CC PMT] [' . $_POST['CreditCardType'] . ']  AUTH: ' . $this->auth_code . '  TransID: ' . $this->transaction_id, 'string');
	  $sql = $db->bindVars($sql, ':orderID', $insert_id, 'integer');
	  $sql = $db->bindVars($sql, ':orderStatus', $this->order_status, 'integer');
	  $db->Execute($sql);

	  $sql = "update " . TABLE_ORDERS . " SET cc_type=:qbcctype, cc_owner=:qbccowner, cc_number=:qbccnumber, cc_expires=:qbccexpires WHERE orders_id=:orderID";
	  $sql = $db->bindVars($sql, ':qbcctype', $_POST['CreditCardType'], 'string');
	  $sql = $db->bindVars($sql, ':qbccowner', $_POST['CreditCardOwner'], 'string');
	  $sql = $db->bindVars($sql, ':qbccnumber', str_repeat('*', (strlen($_POST['CreditCardNumber']) - 4)) . substr($_POST['CreditCardNumber'], -4), 'string');
	  $sql = $db->bindVars($sql, ':qbccexpires', $_POST['ExpirationMonth'] . substr($_POST['ExpirationYear'], -2), 'string');
	  $sql = $db->bindVars($sql, ':orderID', $insert_id, 'integer');
	  $db->Execute($sql);

	  return false;
	}

	
	// function get_error: Create an associative array to house the error.
	function get_error() {
	  global $_GET;

	  $error = array('title' => MODULE_PAYMENT_QBMS_TEXT_ERROR,
                        'error' => stripslashes(urldecode($_GET['error'])));

	  return $error;
	}
	
	
	// function check: Checks whether the payment has been installed through the admin panel.
	function check() {
	  global $db;	
	  if (!isset($this->_check)) {
         $check_query = $db->Execute("select configuration_value from " . TABLE_CONFIGURATION . " where configuration_key = 'MODULE_PAYMENT_QBMS_STATUS'");
         $this->_check = $check_query->RecordCount();
       }
       return $this->_check;
     }
	
	// function install: Installs the configuration keys into the database.
	function install() {
	global $db;
	  $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Enable Quickbooks Merchant Service Module', 'MODULE_PAYMENT_QBMS_STATUS', 'True', 'Do you want to accept Quickbooks Merchant Service payments?', '6', '0', 'zen_cfg_select_option(array(\'True\', \'False\'), ', now())");
	  $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Application Login', 'MODULE_PAYMENT_QBMS_APPLICATION_LOGIN', 'qbms.yoursite.com', 'The Application Login you chose when registering with QBMS', '6', '0', now())");
	  $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('App ID', 'MODULE_PAYMENT_QBMS_APPID', '111111111', 'The AppID provided by QBMS (only needed for -Desktop- security model)', '6', '0', now())");
	  $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Connection Ticket', 'MODULE_PAYMENT_QBMS_CONNECTION_TICKET', 'TGT-##############################', 'The connection ticket you should have received after establishing a connection with QBMS', '6', '0', now())");
	  $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('SSL Certificate', 'MODULE_PAYMENT_QBMS_SSL_CERT', '/path/to/intuit.pem', 'The absolute path to the pem file (must include certificate & key..only applies to -Hosted- security)', '6', '0', now())");
	  $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Testing', 'MODULE_PAYMENT_QBMS_TEST', 'True', 'Do you wish to use the testing server or not?', '6', '0', 'zen_cfg_select_option(array(\'True\', \'False\'), ', now())");
	  $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Hosted or Desktop', 'MODULE_PAYMENT_QBMS_HOSTEDORDESKTOP', 'Hosted', 'Use Hosted or Desktop Security?', '6', '0', 'zen_cfg_select_option(array(\'Hosted\', \'Desktop\'), ', now())");
	  $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, date_added) values ('Verify Credit Card with CVV2', 'MODULE_PAYMENT_QBMS_VERIFY_WITH_CVV2', 'False', 'Verify card with CVV2', '6', '0', 'zen_cfg_select_option(array(\'True\', \'False\'), ', now())");
	  $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('Sort order of display.', 'MODULE_PAYMENT_QBMS_SORT_ORDER', '0', 'Sort order of display. Lowest is displayed first.', '6', '0', now())");
	  $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, use_function, set_function, date_added) values ('Payment Zone', 'MODULE_PAYMENT_QBMS_ZONE', '0', 'If a zone is selected, only enable this payment method for that zone.', '6', '2', 'zen_get_zone_class_title', 'zen_cfg_pull_down_zone_classes(', now())");
	  $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, set_function, use_function, date_added) values ('Set Order Status', 'MODULE_PAYMENT_QBMS_ORDER_STATUS_ID', '0', 'Set the status of orders made with this payment module to this value', '6', '0', 'zen_cfg_pull_down_order_statuses(', 'zen_get_order_status_name', now())");
	  $db->Execute("insert into " . TABLE_CONFIGURATION . " (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added) values ('IP Address', 'MODULE_PAYMENT_QBMS_IP_ADDRESS', '', 'The IP Address of the local machine that will communicate with QBMS (only needed for -Hosted-)', '6', '0', now())");
	}
	
	// function remove: Removes the configuration keys from the database, called when they hit “remove” in the backend.
	function remove() {
	global $db;
	  $db->Execute("delete from " . TABLE_CONFIGURATION . " where configuration_key in ('" . implode("', '", $this->keys()) . "')");
	}
	
	// function keys: Defines an array containing the configuration key keys that are used by the payment module.
	function keys() {
       return array('MODULE_PAYMENT_QBMS_STATUS', 'MODULE_PAYMENT_QBMS_HOSTEDORDESKTOP', 'MODULE_PAYMENT_QBMS_APPID', 'MODULE_PAYMENT_QBMS_APPLICATION_LOGIN', 'MODULE_PAYMENT_QBMS_CONNECTION_TICKET', 'MODULE_PAYMENT_QBMS_SSL_CERT', 'MODULE_PAYMENT_QBMS_TEST', 'MODULE_PAYMENT_QBMS_VERIFY_WITH_CVV2', 'MODULE_PAYMENT_QBMS_SORT_ORDER', 'MODULE_PAYMENT_QBMS_ZONE', 'MODULE_PAYMENT_QBMS_ORDER_STATUS_ID', 'MODULE_PAYMENT_QBMS_IP_ADDRESS');
       }
	
    // function qbms_get_session_ticket: Gets the session ticket from QBMS servers
    // used only with "hosted" security model
    function qbms_get_session_ticket($QBMS_ApplicationPath) {
    global $_POST;
    global $messageStack;
	  
	// This request uses the merchant ticket to get the session ticket
	$QBMS_XML_TktRq = '<?xml version="1.0"?>
	                   <?qbmsxml version="2.0"?>
				       <QBMSXML>
				       <SignonMsgsRq>
				       <SignonAppCertRq>
				       <ClientDateTime>'.date('Y-m-d\TH:i:s').'</ClientDateTime>
				       <ApplicationLogin>'.MODULE_PAYMENT_QBMS_APPLICATION_LOGIN.'</ApplicationLogin>
				       <ConnectionTicket>'.MODULE_PAYMENT_QBMS_CONNECTION_TICKET.'</ConnectionTicket>
				       </SignonAppCertRq>
				       </SignonMsgsRq>
				       </QBMSXML>';
						 
	$QBMS_TktRq = $this->qbms_call($QBMS_ApplicationPath, $QBMS_XML_TktRq, MODULE_PAYMENT_QBMS_SSL_CERT);

    // Verify that the session ticket was successfully fetched from QBMS, otherwise return an error
	$QBMS_TktRq_Status = 1;
	$posLeft  = strpos($QBMS_TktRq, "<SignonAppCertRs statusCode=\"")+strlen("<SignonAppCertRs statusCode=\"");
	$posRight = strpos($QBMS_TktRq, "\"", $posLeft+1);
	$QBMS_TktRq_Status = intval(substr($QBMS_TktRq, $posLeft, $posRight-$posLeft));
	if ($QBMS_TktRq_Status != 0) {
	$error = MODULE_PAYMENT_QBMS_TEXT_SYSTEM_ERROR."<p>Could not get Connection Ticket</p>";

//	$payment_error_return = 'payment_error=' . $this->code . '&error=' . urlencode($error) . '&qbms_cc_owner=' . urlencode($_POST['CreditCardOwner']) . '&qbms_cc_expires_month=' . $_POST['ExpirationMonth'] . '&qbms_cc_expires_year=' . $_POST['ExpirationYear'];
//	zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, $payment_error_return, 'SSL', true, false));

	$messageStack->add_session('checkout_payment', $error, 'error');
	zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, '', 'SSL', true, false));
	}			
	
	//Find and pull the ticket from the data returned to $TktRq
	$TempString = strstr($QBMS_TktRq, "<SessionTicket>");
	$EndLocation = strpos($TempString, "</SessionTicket>");
	$QBMS_SessionTicket = substr($TempString, 15, $EndLocation - 15);
	
	return $QBMS_SessionTicket;
  }
  
  // function qbms_charge_success: Credit Card was successful & now we must store the transaction id and authorization code
     function qbms_charge_success($QBMS_ChargeRq) {
     global $order;
		
	//get CreditCardTransID
	$TempString = strstr($QBMS_ChargeRq, "<CreditCardTransID>");
	$EndLocation = strpos($TempString, "</CreditCardTransID>");
	$QBMS_CreditCardTransID = substr($TempString, 19, $EndLocation - 19);
	
	//get Authorization Code
	$TempString = strstr($QBMS_ChargeRq, "<AuthorizationCode>");
	$EndLocation = strpos($TempString, "</AuthorizationCode>");
	$QBMS_AuthorizationCode = substr($TempString, 19, $EndLocation - 19);
	
	//assign Authorization Code and TransID to order
//	$order->info['cc_authcode'] = $QBMS_AuthorizationCode;
//	$order->info['cc_transid'] = $QBMS_CreditCardTransID;
	$this->auth_code = $QBMS_AuthorizationCode;
	$this->transaction_id = $QBMS_CreditCardTransID;

  }
	
  // function qbms_call: Communicates with the QBMS server via cURL
  function qbms_call($qbmsURL, $qbmsRequest, $qbmsCert) {
    global $_POST;
    global $messageStack;
    $PHP_Header[] = "Content-type: application/x-qbmsxml";
    $PHP_Header[] = "Content-length: ".strlen($qbmsRequest);
	  
	$clientURL = curl_init();
	
	curl_setopt($clientURL, CURLOPT_POST, 1);
	curl_setopt($clientURL, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($clientURL, CURLOPT_CUSTOMREQUEST, 'POST');
	curl_setopt($clientURL, CURLOPT_URL, $qbmsURL);
	curl_setopt($clientURL, CURLOPT_TIMEOUT, 60);
	curl_setopt($clientURL, CURLOPT_HTTPHEADER, $PHP_Header);
	curl_setopt($clientURL, CURLOPT_POSTFIELDS, $qbmsRequest);
	curl_setopt($clientURL, CURLOPT_VERBOSE, 1);
	curl_setopt($clientURL, CURLOPT_SSL_VERIFYPEER, 1);
	if (MODULE_PAYMENT_QBMS_HOSTEDORDESKTOP == 'Hosted') {
	  curl_setopt($clientURL, CURLOPT_SSLCERT, $qbmsCert);
       }
       if (MODULE_PAYMENT_QBMS_IP_ADDRESS != '') {
         curl_setopt($clientURL, CURLOPT_INTERFACE, MODULE_PAYMENT_QBMS_IP_ADDRESS);
       }
	  
	$qbmsResponse = curl_exec($clientURL);	  
	  
	if ((curl_errno($clientURL)) || ($qbmsResponse == 1)) {

	$curlerrno = curl_errno($clientURL);
	$error = MODULE_PAYMENT_QBMS_TEXT_SYSTEM_ERROR;
//      $payment_error_return = 'payment_error=' . $this->code . '&error=' . urlencode($error) . '&qbms_cc_owner=' . urlencode($_POST['CreditCardOwner']) . '&qbms_cc_expires_month=' . $_POST['ExpirationMonth'] . '&qbms_cc_expires_year=' . $_POST['ExpirationYear'];
//      zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, $payment_error_return, 'SSL', true, false));	  
       $messageStack->add_session('checkout_payment', $error, 'error');
       zen_redirect(zen_href_link(FILENAME_CHECKOUT_PAYMENT, '', 'SSL', true, false));
	} else {
	  curl_close($clientURL);
	}
	 
	return $qbmsResponse;
  }
}
?>