/**
		* send cmpi_lookup request
		* @param postData the posted creditcard details
		*/
		private function _doLookupRequest($postData, $manualPayment)
		{
			$ccnum = $postData['ccno'];
			$ccexpm = str_pad($postData['ccexpm'], 2, '0', STR_PAD_LEFT);
			$ccexpy = $postData['ccexpy']+2000;
			$cccvd = $postData['cccvd'];

			foreach ($postData as $key => $value) {
				if($key == 'ccno') {
					$value = $this->_CCEncrypt($postData['ccno']);
				}
				$_SESSION['CHECKOUT']['CardDetails'][$key] = $value;
			}

			$currency = GetCurrencyCodeByID(GetConfig('DefaultCurrencyID'));
			$currencyCode = $this->getCurrencyNumericCode($currency);
			$orders = $this->GetOrders();
			$order = current($orders);
			$orderIds = '#'.implode(', #', array_keys($orders));
			$orderdesc = sprintf(GetLang('YourOrderFrom'), $GLOBALS['StoreName']).' ('.$orderIds.')';

			$gatewayAmountCents = $this->GetGatewayAmount() * 100;
			$gatewayAmountCents = number_format($gatewayAmountCents, 0, '', '');

			require(dirname(__FILE__).'/lib/CentinelClient.php');
			$centinelClient = new CentinelClient;

			$centinelClient->Add("MsgType", "cmpi_lookup");
			$centinelClient->Add("Version", "1.7");
			$centinelClient->Add("ProcessorId", $this->GetValue('cardinalprocessorid'));
			$centinelClient->Add("MerchantId", $this->GetValue('cardinalmerchantid'));
			$centinelClient->Add("TransactionPwd", $this->GetValue('cardinaltransactionpwd'));
			$centinelClient->Add("OrderNumber", $orderIds);
			$centinelClient->Add("TransactionType", 'C');
			$centinelClient->Add("Amount", $gatewayAmountCents);

			$centinelClient->Add("CurrencyCode", $currencyCode);
			$centinelClient->Add("OrderDescription", $orderdesc);

			$centinelClient->Add("CardNumber", $ccnum);
			$centinelClient->Add("CardExpMonth", $ccexpm);
			$centinelClient->Add("CardExpYear", $ccexpy);


			$this->_testmode = $this->GetValue("testmode") == "YES";

			if ($this->_testmode) {
				$transactionURL = $this->_cardinalTestTransactionURL;
			}
			else {
				$transactionURL = $this->_cardinalLiveTransactionURL;
			}

			$centinelClient->sendHTTP($transactionURL, "30", "30");


			if($centinelClient->getValue("ErrorNo") == '0') {
				//if Cardholder not enrolled
				if($centinelClient->getValue("Enrolled") != 'Y') {
					$DPFields = array (
						'AUTHSTATUS3DS'	=> '',
						'MPIVENDOR3DS'	=> $centinelClient->getValue("Enrolled"),
						'CAVV'			=> '',
						'ECI'			=> $centinelClient->getValue("EciFlag"),
						'XID'			=> '',
					);

					return $this->_doDirectPayment($postData, $DPFields,$manualPayment);
				}

				//we are still here, card holder is enrolled

				//if the payment is a manual payment from control panel, 3D secure transactions are not supported, so finish the payment with error here.
				if($manualPayment) {
					$this->SetError(GetLang('PayPal3DManualPaymentError'));
					return false;
				}

				$result['ACSUrl'] = $centinelClient->getValue("ACSUrl");
				$result['Payload'] = $centinelClient->getValue("Payload");
				$result['TransactionId'] = $centinelClient->getValue("TransactionId");

			} else {
				$this->SetError($centinelClient->getValue("ErrorDesc"));
				return false;
			}


			$_SESSION['CHECKOUT']['CardinalEnrolled'] = $centinelClient->getValue("Enrolled");
			$_SESSION['CHECKOUT']['CardinalTransactionId'] = $result['TransactionId'];
			$_SESSION['CHECKOUT']['ACSUrl'] = $result['ACSUrl'];
			$_SESSION['CHECKOUT']['Payload'] = $result['Payload'];

			$this->_redirect3DTransacitons();
			exit;
		}
		public function DoRefund($order, &$message = '', $amt = 0)
		{
			if($amt == 0) {
				$message = GetLang('RefundIncorrectAmount');
				return false;
			}


			$originalTransId = $order['ordpayproviderid'];
			$orderId = $order['orderid'];

			$orderAmount = number_format($order['total_inc_tax'],2,'.','');
			$amt = number_format($amt,2,'.','');
			$TotalRefundedAmt = number_format($amt+$order['ordrefundedamount'],2,'.','');

			$extraFields = array();
			if($orderAmount == $amt) {
				$extraFields = array('REFUNDTYPE' => 'Full',
									'TRANSACTIONID' => $originalTransId);
			}
			elseif ($orderAmount > $amt) {
				$extraFields = array(
									'REFUNDTYPE' => 'Partial',
									'AMT' => $amt,
									'CURRENCYCODE' => GetCurrencyCodeByID(GetConfig('DefaultCurrencyID')),
									'TRANSACTIONID' => $originalTransId,
								);
			}

			$nvpArray = $this->GetResponseFromProvider('RefundTransaction', $extraFields);
			if(empty($nvpArray)) {
				$message = GetLang('ErrorConnectToPaypal');
				return false;
			}

			$transactionId = '';
			if (isset($nvpArray['REFUNDTRANSACTIONID'])) {
				$transactionId = isc_html_escape($nvpArray['REFUNDTRANSACTIONID']);
			}

			if (strtolower($nvpArray['ACK']) == 'success') {
				$message = GetLang('RefundSuccess');

				//if total refunded is less than the order total amount
				if($TotalRefundedAmt < $orderAmount) {
					$paymentStatus = 'partially refunded';
				} else {
					$paymentStatus = 'refunded';
				}


				$updatedOrder = array(
					'ordpaymentstatus' => $paymentStatus,
					'ordrefundedamount'	=> $TotalRefundedAmt,
				);
				$GLOBALS['ISC_CLASS_DB']->UpdateQuery('orders', $updatedOrder, "orderid='".(int)$orderId."'");


				$refundSuccess = sprintf(GetLang('RefundSuccessLog'), $orderId, $transactionId);
				$GLOBALS['ISC_CLASS_LOG']->LogSystemSuccess(array('payment',  $this->GetName()), $refundSuccess, $message);
				return true;


			} else {
				$errorMsg = '';
				if(isset($nvpArray['L_LONGMESSAGE0'])) {
					$errorMsg = isc_html_escape($nvpArray['L_LONGMESSAGE0']);
				}

				$message = sprintf(GetLang('RefundFailed'), $errorMsg);

				$refundError = sprintf(GetLang('RefundError'), $orderId);
				$GLOBALS['ISC_CLASS_LOG']->LogSystemError(array('payment', $this->GetName()), $refundError, $errorMsg);
				return false;
			}
		}
 /**
  * final stage, Sends the order details together with shipping quotes, taxes and handling cost to Paypal to process
  *
  */
 public function DoExpressCheckoutPayment()
 {
     if (isset($_COOKIE['SHOP_ORDER_TOKEN'])) {
         $orders = $this->GetOrders();
         $order = current($orders);
         $orderIds = '#' . implode(', #', array_keys($orders));
         $merchant = $this->GetMerchantSettings();
         if ($merchant['testmode'] == 'YES') {
             $transactionURL = $this->_testTransactionURL;
             $transactionURI = $this->_testTransactionURI;
         } else {
             $transactionURL = $this->_liveTransactionURL;
             $transactionURI = $this->_liveTransactionURI;
         }
         $response = $_SESSION['CHECKOUT']['PayPalExpressCheckout'];
         // unset PayPalPaymentsPro response in session
         unset($_SESSION['CHECKOUT']['PayPalExpressCheckout']);
         $currency = GetCurrencyCodeByID(GetConfig('DefaultCurrencyID'));
         $pp_array = array('USER' => $merchant['userid'], 'PWD' => $merchant['password'], 'VENDOR' => $merchant['vendorid'], 'PARTNER' => $merchant['partnerid'], 'ACTION' => 'D', 'TENDER' => 'P', 'TRXTYPE' => $merchant['transactionType'], 'TOKEN' => $response['TOKEN'], 'PAYERID' => $response['PAYERID'], 'AMT' => number_format($order['ordgatewayamount'], 2), 'CURRENCY' => $currency);
         $paypal_query = '';
         foreach ($pp_array as $key => $value) {
             $paypal_query .= $key . '[' . strlen($value) . ']=' . $value . '&';
         }
         $paypal_query = rtrim($paypal_query, '&');
         $result = $this->_ConnectToProvider($transactionURL, $transactionURI, $paypal_query, $orderIds);
         $nvpArray = $this->_DecodePaypalResult($result);
         $_SESSION['PayPalPaymentsProResponse'] = $nvpArray;
         @ob_end_clean();
         $token = md5(GetConfig('EncryptionToken') . $_COOKIE['SHOP_ORDER_TOKEN']);
         header(sprintf("Location:%s/finishorder.php?o=%s", $GLOBALS['ShopPathSSL'], $token));
     } else {
         // Invalid PayPalPaymentsPro response
         $this->SetError(GetLang('PayPalPaymentsProInvalidOrder'));
         return false;
     }
 }
	/**
	* Refunds a transaction
	*
	* @param mixed $order
	* @param mixed $message
	* @param mixed $amt
	*/
	public function DoRefund($order, &$message = '', $amount = 0)
	{
		$orderId = $order['orderid'];
		$orderAmount = $order['total_inc_tax'];
		$totalRefundedAmount = $amount + $order['ordrefundedamount'];

		$extraInfo = @unserialize($order['extrainfo']);
		if (!is_array($extraInfo) || empty($extraInfo['CyberSourceRequestToken']) || empty($extraInfo['CyberSourceRequestID'])) {
			$message = GetLang('CyberSourceTransactionDetailsMissing');
			return false;
		}

		$request = array(
			'merchantID' => $this->GetValue('merchantid'),
			'merchantReferenceCode' => $orderId,
			'ccCreditService' => array(
				'captureRequestID'	=> $extraInfo['CyberSourceRequestID'],
				'run' 				=> 'true',
			),
			'orderRequestToken' => $extraInfo['CyberSourceRequestToken'],
			'purchaseTotals' => array(
				'currency' 			=> GetCurrencyCodeByID($order['ordcurrencyid']),
				'grandTotalAmount' 	=> number_format($amount, 2, '.', ''),
			),
		);

		$response = $this->runTransaction($request);

		if (!isset($response['decision'])) {
			$message = GetLang('CyberSourceInvalidRequest');
			return false;
		}

		$decision = $response['decision'];
		$reasonCode = $response['reasonCode'];
		$requestID = $response['requestID'];
		$requestToken = $response['requestToken'];

		$transactionType = GetLang('CyberSourceTransactionTypeRefund');

		if ($decision == 'ACCEPT') {
			$message = GetLang('CyberSourcePaymentRefunded');

			//if total refunded is less than the order total amount
			if($totalRefundedAmount < $orderAmount) {
				$paymentStatus = 'partially refunded';
			} else {
				$paymentStatus = 'refunded';
			}

			// update the order payment status and refund amount
			$updatedOrder = array(
				'ordpaymentstatus' => $paymentStatus,
				'ordrefundedamount'	=> $totalRefundedAmount,
			);

			$GLOBALS['ISC_CLASS_DB']->UpdateQuery('orders', $updatedOrder, "orderid='".(int)$orderId."'");

			$reconciliationID = '';
			if (!isset($response['ccCreditReply']['reconciliationID'])) {
				$reconciliationID = $response['ccCreditReply']['reconciliationID'];
			}

			$refundAmount = $response['ccCreditReply']['amount'];

			// Log the transaction in store logs
			$logMessage = GetLang('CyberSourcePaymentRefundedLogMsg', array('orderId' => $orderId));

			$logDetails = GetLang('CyberSourcePaymentRefundedLogDetails', array(
				'decision' 			=> $decision,
				'reasonCode' 		=> $reasonCode,
				'requestID' 		=> $requestID,
				'reconciliationID'	=> $reconciliationID,
				'amount'			=> $refundAmount,
				'transactionType'	=> $transactionType,
			));

			$GLOBALS['ISC_CLASS_LOG']->LogSystemSuccess(array('payment', $this->GetName()), $logMessage, $logDetails);

			return true;
		}
		else {
			$message = GetLang('CyberSourceRefundFailed');

			// any missing fields?
			$missingFieldsString = '';
			if (isset($response['missingField'])) {
				$missingFields = $response['missingField'];
				if (!is_array($missingFields)) {
					$missingFields = array($missingFields);
				}

				$missingFieldsString = implode(', ', $missingFields);
			}

			//any invalid fields?
			$invalidFieldsString = '';
			if (isset($response['invalidField'])) {
				$invalidFields = $response['invalidField'];
				if (!is_array($invalidFields)) {
					$invalidFields = array($invalidFields);
				}

				$invalidFieldsString = implode(', ', $invalidFields);
			}

			$logMessage = GetLang('CyberSourceRefundFailedLogMsg', array('orderId' => $orderId));

			$logDetails = GetLang('CyberSourceFailureDetails', array(
				'decision' 			=> $decision,
				'reasonCode' 		=> $reasonCode,
				'requestID' 		=> $requestID,
				'transactionType'	=> $transactionType,
				'missingFields'		=> $missingFieldsString,
				'invalidFields'		=> $invalidFieldsString,
			));

			$GLOBALS['ISC_CLASS_LOG']->LogSystemError(array('payment', $this->GetName()), $logMessage, $logDetails);
			return false;
		}

	}