/**
		 * Process the PayPal IPN ping back.
		 */
		public function ProcessGatewayPing()
		{
			//make it only work for echeck pings
			if($_POST['payment_type'] != 'echeck' || $_POST['payment_status']== 'Pending') {
				exit;
			}

			if(!isset($_POST['custom'])) {
				exit;
			}

			$sessionToken = explode('_', $_REQUEST['custom'], 2);

			$this->SetOrderData(LoadPendingOrdersByToken($sessionToken[0]));

			$amount = number_format($this->GetGatewayAmount(), 2, '.', '');

			if($amount == 0) {
				exit;
			}

			// Perform a post back to PayPal with exactly what we received in order to validate the request
			$queryString = array();
			$queryString[] = "cmd=_notify-validate";
			foreach($_POST as $k => $v) {
				$queryString[] = $k."=".urlencode($v);
			}
			$queryString = implode('&', $queryString);

			$testMode = $this->GetValue('testmode');
			if($testMode == 'YES') {
				$verifyURL = 'http://www.sandbox.paypal.com/cgi-bin/webscr';
			}
			else {
				$verifyURL = 'http://www.paypal.com/cgi-bin/webscr';
			}

			$response = PostToRemoteFileAndGetResponse($verifyURL, $queryString);

			// This pingback was not valid
			if($response != "VERIFIED") {
				// Bad order details
				$GLOBALS['ISC_CLASS_LOG']->LogSystemError(array('payment', $this->GetName()), GetLang('PayPalErrorInvalid'), "RESPONSE : "  .$response);
				return false;
			}

			// If we're still here, the ping back was valid, so we check the payment status and everything else match up


			$paypalEmail = $this->GetValue('email');

			if(!isset($_POST['receiver_email']) || !isset($_POST['mc_gross']) || !isset($_POST['payment_status'])) {
				// Bad order details
				$GLOBALS['ISC_CLASS_LOG']->LogSystemError(array('payment', $this->GetName()), GetLang('PayPalErrorInvalid'), print_r($_POST, true));
				return false;
			}

			// The values passed don't match what we expected
			if(($_POST['mc_gross'] != $amount && !in_array($_POST['payment_status'], array('Reversed', 'Refunded', 'Canceled_Reversed')))) {
				$errorMsg = sprintf(GetLang('PayPalErrorInvalidMsg'), $_POST['mc_gross'], $amount, $_POST['receiver_email'], $paypalEmail, $_POST['payment_status']);
				$GLOBALS['ISC_CLASS_LOG']->LogSystemError(array('payment', $this->GetName()), GetLang('PayPalErrorInvalid'), $errorMsg);
				return false;
			}

			$currency = GetDefaultCurrency();

			if($_POST['mc_currency'] != $currency['currencycode']) {
				$errorMsg = sprintf(GetLang('PayPalErrorInvalidMsg3'), $currency['currencycode'], $_POST['mc_currency']);
				$GLOBALS['ISC_CLASS_LOG']->LogSystemError(array('payment', $this->GetName()), GetLang('PayPalErrorInvalid'), $errorMsg);
				return false;
			}

			// Has the transaction been processed before? If so, we can't process it again
			$transaction = GetClass('ISC_TRANSACTION');

			$newTransaction = array(
				'providerid' => $this->GetId(),
				'transactiondate' => time(),
				'transactionid' => $_POST['txn_id'],
				'orderid' => array_keys($this->GetOrders()),
				'message' => '',
				'status' => '',
				'amount' => $_POST['mc_gross'],
				'extrainfo' => array()
			);

			$orderPaymentStatus = '';
			switch($_POST['payment_status']) {
				case "Completed":
					$orderPaymentStatus = 'captured';
					$newTransaction['status'] = TRANS_STATUS_COMPLETED;
					$newOrderStatus = ORDER_STATUS_AWAITING_FULFILLMENT;
					break;
				case "Pending":
					if($_POST['payment_type'] != 'echeck') {
						$orderPaymentStatus = 'authorized';
					}
					$newTransaction['status'] = TRANS_STATUS_PENDING;
					$newOrderStatus = ORDER_STATUS_AWAITING_PAYMENT;
					$newTransaction['extrainfo']['reason'] = $_POST['pending_reason'];
					break;
				case "Denied":
					$newTransaction['status'] = TRANS_STATUS_DECLINED;
					$newOrderStatus = ORDER_STATUS_DECLINED;
					break;
				case "Failed":
					$newTransaction['status'] = TRANS_STATUS_FAILED;
					$newOrderStatus = ORDER_STATUS_DECLINED;
					break;
				case "Refunded":
					$newTransaction['status'] = TRANS_STATUS_REFUND;
					$newOrderStatus = ORDER_STATUS_REFUNDED;
					break;
				case "Reversed":
					$newTransaction['status'] = TRANS_STATUS_CHARGEBACK;
					$newOrderStatus = ORDER_STATUS_REFUNDED;
					break;
				case "Canceled_Reversal":
					$newTransaction['status'] = TRANS_STATUS_CANCELLED_REVERSAL;
					$newOrderStatus = ORDER_STATUS_REFUNDED;
					break;
			}


			$previousTransaction = $transaction->LoadByTransactionId($_POST['txn_id'], $this->GetId());

			// Already processed before, HALT and log error
			if(is_array($previousTransaction) && $previousTransaction['transactionid'] && $previousTransaction['status'] == $newTransaction['status']) {
				$GLOBALS['ISC_CLASS_LOG']->LogSystemError(array('payment', $this->GetName()), sprintf(GetLang('PayPalTransactionAlreadyProcessed'), $_POST['txn_id']));
				return false;
			}


			$newTransaction['message'] = $this->GetPayPalTransactionMessage($_POST);

			$transactionId = $transaction->Create($newTransaction);

			$oldOrderStatus = $this->GetOrderStatus();
			// If the order was previously incomplete, we need to do some extra work
			if($oldOrderStatus == ORDER_STATUS_INCOMPLETE) {
				// If a customer doesn't return to the store from PayPal, their cart will never be
				// emptied. So what we do here, is if we can, load up the existing customers session
				// and empty the cart and kill the checkout process. When they next visit the store,
				// everything should be "hunky-dory."
				session_write_close();
				$session = new ISC_SESSION($sessionToken[1]);
				EmptyCartAndKillCheckout();
			}

			// Update the status for all orders that we've just received the payment for
			foreach($this->GetOrders() as $orderId => $order) {
				$status = $newOrderStatus;
				// If it's a digital order & awaiting fulfillment, automatically complete it
				if($order['ordisdigital'] && $status == ORDER_STATUS_AWAITING_FULFILLMENT) {
					$status = ORDER_STATUS_COMPLETED;
				}
				UpdateOrderStatus($orderId, $status);
			}

			$updatedOrder = array(
				'ordpaymentstatus' => $orderPaymentStatus,
			);

			$this->UpdateOrders($updatedOrder);

			// This was a successful order
			$oldStatus = GetOrderStatusById($oldOrderStatus);
			if(!$oldStatus) {
				$oldStatus = 'Incomplete';
			}
			$newStatus = GetOrderStatusById($newOrderStatus);

			$extra = sprintf(GetLang('PayPalSuccessDetails'), implode(', ', array_keys($this->GetOrders())), $amount, '', $_POST['txn_id'], $_POST['payment_status'], $newStatus, $oldStatus);

			$successMsg = sprintf(GetLang('PayPalPaymentsProSuccess'), implode(', ', array_keys($this->GetOrders())));

			$GLOBALS['ISC_CLASS_LOG']->LogSystemSuccess(array('payment', $this->GetName()), $successMsg, $extra);
			return true;
		}
Пример #2
0
/**
 * Completes a pending order and marks it's status as whatever it should be next.
 * This function will process any payments, capture amounts from gateways, increase
 * # sold for each product in the order, etc.
 *
 * @param string The pending order token.
 * @param int The status to set the completed order to.
 * @return boolean True if successful, false on failure.
 */
function CompletePendingOrder($pendingOrderToken, $status, $sendInvoice=true)
{
	$orderData = LoadPendingOrdersByToken($pendingOrderToken, true);
	if($orderData === false) {
		return false;
	}

	$processedStoreCredit = false;
	$processedGiftCertificates = false;
	$orderStoreCredit = 0;
	$orderTotalAmount = 0;

	// Flag used to create the customer record but only if atleast one order was successful
	$createCustomer = false;

	// Sum up our total amount and store credit
	foreach ($orderData['orders'] as $order) {
		if ($order['ordstatus'] != 0) {
			continue;
		}

		$orderStoreCredit += $order['ordstorecreditamount'];
		$orderTotalAmount += $order['total_inc_tax'];
	}

	// flag to indicate if we should send notifications? only if the order was previously incomplete and the new status isn't declined/cancelled/refunded
	$sendNotifications = false;

	foreach($orderData['orders'] as $order) {
		$newStatus = $status;

		// Wait, was the order already complete? Then we don't do anything
		if($order['ordstatus'] != ORDER_STATUS_INCOMPLETE) {
			continue;
		}

		// If this order is digital, and the status is awaiting fulfillment, there's nothing
		// to actually fulfill, so set it to completed.
		if($order['ordisdigital'] && $newStatus == ORDER_STATUS_AWAITING_FULFILLMENT) {
			$newStatus = ORDER_STATUS_COMPLETED;
		}

		$extraInfo = @unserialize($order['extrainfo']);
		if(!is_array($extraInfo)) {
			$extraInfo = array();
		}

		// only email and update order data (coupons, certificates, store credit etc) if it's not a declined, cancelled or refunded order
		if($newStatus != ORDER_STATUS_DECLINED && $newStatus != ORDER_STATUS_CANCELLED && $newStatus != ORDER_STATUS_REFUNDED) {
			$createCustomer = true;
			$sendNotifications = true;

			if($sendInvoice && !EmailInvoiceToCustomer($order['orderid'], $newStatus)) {
				$GLOBALS['HideError'] = "";
				$GLOBALS['ErrorMessage'] = GetLang('ErroSendingInvoiceEmail');
				$GLOBALS['HideSuccess'] = "none";
			}

			// Are we updating the inventory levels when an order has been placed?
			if(GetConfig('UpdateInventoryLevels') == 1) {
				DecreaseInventoryFromOrder($order['orderid']);
			}

			// If this order now complete, we need to activate any gift certificates
			if(OrderIsComplete($newStatus)) {
				$GLOBALS['ISC_CLASS_GIFTCERTIFICATES'] = GetClass('ISC_GIFTCERTIFICATES');
				$GLOBALS['ISC_CLASS_GIFTCERTIFICATES']->ActivateGiftCertificates($order['orderid']);
			}

			// If we've had one or more coupons been applied to this order, we now need to increment the number of uses
			$couponIds = array();
			$query = "
				SELECT *
				FROM [|PREFIX|]order_coupons
				WHERE ordcouporderid='".(int)$order['orderid']."'
			";
			$result = $GLOBALS['ISC_CLASS_DB']->Query($query);
			while($coupon = $GLOBALS['ISC_CLASS_DB']->Fetch($result)) {
				$couponIds[] = $coupon['ordcouponid'];
			}
			if(!empty($couponIds)) {
				$couponsUsed = array_unique($couponIds);
				$couponList = implode(",", array_map("intval", $couponsUsed));
				$query = "
					UPDATE [|PREFIX|]coupons
					SET couponnumuses=couponnumuses+1
					WHERE couponid IN (".$couponList.")
				";
				$GLOBALS['ISC_CLASS_DB']->Query($query);

				foreach ($couponIds as $cid) {
					getclass('ISC_COUPON')->updatePerCustomerUsage($cid);
				}
			}

			// If we used store credit on this order, we now need to subtract it from the users account.
			if($order['ordstorecreditamount'] > 0 && $processedStoreCredit == false) {
				$GLOBALS['ISC_CLASS_CUSTOMER'] = GetClass('ISC_CUSTOMER');
				$currentCredit = $GLOBALS['ISC_CLASS_CUSTOMER']->GetCustomerStoreCredit($order['ordcustid']);
				$newCredit = $currentCredit - $orderStoreCredit;
				if($newCredit < 0) {
					$newCredit = 0;
				}
				$updatedCustomer = array(
					'custstorecredit' => $newCredit,
				);
				$GLOBALS['ISC_CLASS_DB']->UpdateQuery('customers', $updatedCustomer, "customerid='".(int)$order['ordcustid']."'");
				$processedStoreCredit = true;
			}

			// If one or more gift certificates were used we need to apply them to this order and subtract the total
			if($order['ordgiftcertificateamount'] > 0 && isset($extraInfo['giftcertificates']) && !empty($extraInfo['giftcertificates']) && $processedGiftCertificates == false) {
				$usedCertificates = array();
				$GLOBALS['ISC_CLASS_GIFT_CERTIFICATES'] = GetClass('ISC_GIFTCERTIFICATES');
				$GLOBALS['ISC_CLASS_GIFT_CERTIFICATES']->ApplyGiftCertificatesToOrder($order['orderid'], $orderTotalAmount + $order['ordgiftcertificateamount'], $extraInfo['giftcertificates'], $usedCertificates);
				unset($extraInfo['giftcertificates']);
				$processedGiftCertificates = true;
			}

			// If there are one or more digital products in this order then we need to create a record in the order_downloads table
			// for each of them and set the expiry dates
			$query = "
				SELECT ordprodid, ordprodqty
				FROM [|PREFIX|]order_products
				WHERE orderorderid='".$order['orderid']."' AND ordprodtype='digital'
			";
			$result = $GLOBALS['ISC_CLASS_DB']->Query($query);
			$digitalProductIds = array();
			while($digitalProduct = $GLOBALS['ISC_CLASS_DB']->Fetch($result)) {
				$digitalProductIds[$digitalProduct['ordprodid']] = $digitalProduct;
			}

			if(!empty($digitalProductIds)) {
				$query = "
					SELECT downloadid, productid, downexpiresafter, downmaxdownloads
					FROM [|PREFIX|]product_downloads
					WHERE productid IN (".implode(',', array_keys($digitalProductIds)).")
				";
				$result = $GLOBALS['ISC_CLASS_DB']->Query($query);
				while($digitalDownload = $GLOBALS['ISC_CLASS_DB']->Fetch($result)) {
					$expiryDate = 0;

					// If this download has an expiry date, set it to now + expiry time
					if($digitalDownload['downexpiresafter'] > 0) {
						$expiryDate = time() + $digitalDownload['downexpiresafter'];
					}

					// If they've purchased more than one, we need to give them max downloads X quantity downloads
					$quantity = $digitalProductIds[$digitalDownload['productid']]['ordprodqty'];

					$newDownload = array(
						'orderid' => $order['orderid'],
						'downloadid' => $digitalDownload['downloadid'],
						'numdownloads' => 0,
						'downloadexpires' => $expiryDate,
						'maxdownloads' => $digitalDownload['downmaxdownloads'] * $quantity
					);
					$GLOBALS['ISC_CLASS_DB']->InsertQuery('order_downloads', $newDownload);
				}
			}
		}

		// Does a customer account need to be created?
		if(!empty($extraInfo['createAccount'])) {
			createOrderCustomerAccount($order, $extraInfo['createAccount']);
			unset($extraInfo['createAccount']);
		}

		// Now update the order and set the status
		$updatedOrder = array(
			"ordstatus" => $newStatus,
			"extrainfo" => serialize($extraInfo)
		);
		$GLOBALS['ISC_CLASS_DB']->UpdateQuery("orders", $updatedOrder, "orderid='".$order['orderid']."'");
	}

	if($sendNotifications) {
		// Trigger all active new order notification methods
		SendOrderNotifications($pendingOrderToken);

		// Do we need to add them to a Interspire Email Marketer mailing list?
		SubscribeCustomerToLists($pendingOrderToken);

		// Update the current uses of each rule
		$quote = getCustomerQuote();
		$appliedRules = array_keys(getCustomerQuote()->getAppliedDiscountRules());
		if(!empty($appliedRules)) {
			require_once ISC_BASE_PATH.'/lib/rule.php';
			updateRuleUses($appliedRules);
		}
	}

	// Empty the users cart and kill the checkout process
	EmptyCartAndKillCheckout();

	return true;
}
Пример #3
0
	public function ProcessGatewayPing()
	{
		/*
		orderID Your order reference
		amount Order amount (not multiplied by 100)
		currency Currency of the order
		PM Payment method
		ACCEPTANCE Acceptance code returned by acquirer
		STATUS Transaction status
		CARDNO Masked card number
		PAYID Payment reference in our system
		NCERROR Error code
		BRAND Card brand (our system derives it from the card number) or similar information for other payment methods.
		SHASIGN SHA signature composed by our system, if SHA-out configured by you.
		*/

		if(!isset($_REQUEST['OrderToken'])) {
			exit;
		}

		if (!isset($_REQUEST['orderID']) || !isset($_REQUEST['amount']) || !isset($_REQUEST['currency']) || !isset($_REQUEST['STATUS'])) {
			// Bad order details
			$GLOBALS['ISC_CLASS_LOG']->LogSystemError(array('payment', $this->GetName()), GetLang('OgoneErrorInvalid'), print_r($_POST, true));
			return false;
		}

		// ogone response data
		$orderId = $_REQUEST['orderID'];
		$amount = $_REQUEST['amount'];
		$currency = $_REQUEST['currency'];
		$status = $_REQUEST['STATUS'];
		$transactionId = $_REQUEST['PAYID'];
		$errorCode = $_REQUEST['NCERROR'];

		$orderToken = $_REQUEST['OrderToken'];
		$sessionToken = $_REQUEST['SessionToken'];

		$this->SetOrderData(LoadPendingOrdersByToken($orderToken));

		// expected values
		$combinedOrderId = $this->GetCombinedOrderId();
		$gateway_amount = number_format($this->GetGatewayAmount(), 2, '.', '');
		$defaultcurrency = GetDefaultCurrency();

		// verify the SHA Sign
		$shaParamsToCheck = array(
			'AAVADDRESS', 'AAVCHECK', 'AAVZIP', 'ACCEPTANCE', 'ALIAS', 'AMOUNT', 'BRAND', 'CARDNO', 'CCCTY', 'CN', 'COMPLUS', 'CURRENCY', 'CVCCHECK',
			'DCC_COMMPERCENTAGE', 'DCC_CONVAMOUNT', 'DCC_CONVCCY', 'DCC_EXCHRATE', 'DCC_EXCHRATESOURCE', 'DCC_EXCHRATETS', 'DCC_INDICATOR', 'DCC_MARGINPERCENTAGE', 'DCC_VALIDHOUS',
			'DIGESTCARDNO', 'ECI', 'ED', 'ENCCARDNO', 'IP', 'IPCTY', 'NBREMAILUSAGE', 'NBRIPUSAGE', 'NBRIPUSAGE_ALLTX', 'NBRUSAGE', 'NCERROR',
			'ORDERID', 'PAYID', 'PM', 'SCO_CATEGORY', 'SCORING', 'STATUS', 'SUBSCRIPTION_ID', 'TRXDATE', 'VC',
		);

		$checkRequest = array_change_key_case($_REQUEST, CASE_UPPER);
		$signature = $this->GetValue("signature_out");
		$stringToHash = '';

		foreach ($shaParamsToCheck as $param) {
			if (!isset($checkRequest[$param]) || $checkRequest[$param] == '') {
				continue;
			}

			$stringToHash .= $param . '=' . $checkRequest[$param] . $signature;
		}

		$sha = strtoupper(sha1($stringToHash));

		if ($sha != $_REQUEST['SHASIGN']) {
			$GLOBALS['ISC_CLASS_LOG']->LogSystemError(array('payment', $this->GetName()), GetLang('OgoneErrorInvalid', array('orderId' => $orderId)), print_r($_POST, true));
			return false;
		}

		// The values passed don't match what we expected
		if($orderId != $combinedOrderId || $amount != $gateway_amount || $currency != $defaultcurrency['currencycode']) {
			$errorMsg = GetLang('OgoneErrorDetailsNoMatch', array(
				"total" => $amount,
				"expectedTotal" => $gateway_amount,
				"orderId" => $orderId,
				"expectedOrderId" => $combinedOrderId,
				"currency" => $currency,
				"expectedCurrency" => $defaultcurrency['currencycode'],
				"status" => $status
			));
			$GLOBALS['ISC_CLASS_LOG']->LogSystemError(array('payment', $this->GetName()), GetLang('OgoneErrorInvalid', array('orderId' => $orderId)), $errorMsg);
			return false;
		}

		$paymentStatus = '';
		$statusLang = $status;
		switch($status) {
			case '0': // incomplete
			case '1': // cancelled by customer
				$newOrderStatus = ORDER_STATUS_INCOMPLETE;
				break;
			case '2': // auth refused
				$newOrderStatus = ORDER_STATUS_DECLINED;
				break;
			case '5': // authorized
				$newOrderStatus = ORDER_STATUS_AWAITING_PAYMENT;
				break;
			case '51': // awaiting authorization
			case '52': // authorization unknown
				$newOrderStatus = ORDER_STATUS_PENDING;
				break;
			case '6': // authorized and cancelled
				$newOrderStatus = ORDER_STATUS_INCOMPLETE;
				break;
			case '7': // payment deleted
			case '74': // payment deleted
				$newOrderStatus = ORDER_STATUS_AWAITING_PAYMENT;
				break;
			case '8': // refund
				$newOrderStatus = ORDER_STATUS_REFUNDED;
				break;
			case '9': // payment authorized and captured
				$newOrderStatus = ORDER_STATUS_AWAITING_FULFILLMENT;
				break;
			case '91': // awaiting payment
			case '93': // payment refused (tech problem or expired auth)
				$newOrderStatus = ORDER_STATUS_AWAITING_PAYMENT;
				break;
			case '92': // unknown payment
				$newOrderStatus = ORDER_STATUS_PENDING;
				break;
			case '94': // payment declined by aquirer
				$newOrderStatus = ORDER_STATUS_DECLINED;
				break;
			default :
				$newOrderStatus = ORDER_STATUS_DECLINED;
				$statusLang = 'Unknown';
				break;
		}

		// if the order is currently incomplete and the new status isn't incomplete (ie. transaction cancelled by customer), then empty the cart
		if($this->GetOrderStatus() == ORDER_STATUS_INCOMPLETE && $newOrderStatus != ORDER_STATUS_INCOMPLETE) {
			session_write_close();
			$session = new ISC_SESSION($sessionToken);
			EmptyCartAndKillCheckout();
		}

		// update orders with the transaction id
		$updatedOrder = array(
			'ordpayproviderid' => $transactionId
		);

		// if captured then update pay status in order
		if ($newOrderStatus == ORDER_STATUS_AWAITING_FULFILLMENT) {
			$updatedOrder['ordpaymentstatus'] = 'captured';
		}

		$this->UpdateOrders($updatedOrder);

		// we only want to notify the customer of a successfull order
		$emailCustomer = false;
		if ($newOrderStatus != ORDER_STATUS_INCOMPLETE) {
			$emailCustomer = true;
		}

		// update order statuses
		foreach($this->GetOrders() as $orderId => $order) {
			// digital orders should complete right away if captured
			if($order['ordisdigital'] && $newOrderStatus == ORDER_STATUS_AWAITING_FULFILLMENT) {
				$newOrderStatus = ORDER_STATUS_COMPLETED;
			}

			UpdateOrderStatus($orderId, $newOrderStatus, $emailCustomer);
		}

		// Log this payment response
		$oldStatus = GetOrderStatusById($order['ordstatus']);
		if(!$oldStatus) {
			$oldStatus = 'Incomplete';
		}

		$newStatus = GetOrderStatusById($newOrderStatus);
		if (!$newStatus) {
			$newStatus = 'Incomplete';
		}

		$extra = GetLang('OgoneSuccessDetails', array(
			"orderId" => implode(', ', array_keys($this->GetOrders())),
			"amount" => $gateway_amount,
			"paymentId" => $transactionId,
			"paymentStatus" => $status,
			"paymentDesc" => GetLang('OgoneTransactionStatus' . $statusLang),
			"newStatus" => $newStatus,
			"oldStatus" => $oldStatus
		));
		$GLOBALS['ISC_CLASS_LOG']->LogSystemSuccess(array('payment', $this->_name), GetLang('OgoneSuccess', array('orderId' => $orderId)), $extra);

		return true;
	}
Пример #4
0
	/**
	 * Create a new order in ISC based on a new-order-notification from google
	 *
	 * @return void
	 **/
	private function CreateOrder()
	{
		if(!$this->LoadCart($this->module->cartid))
		{
			// Todo: What is the correct way to fail here?
			return;
		}

		// Ensure split shipping is disabled
		$this->quote->setIsSplitShipping(false);

		// Set the billing address for the order
		$billingAddress =
			$this->GetAddressFromResponse($this->response->data[$this->response->root]['buyer-billing-address']);
		$this->quote->getBillingAddress()
			->setAddressByArray($billingAddress);

		if(!$this->quote->isDigital()) {
			// Set the shipping address for the order
			$shippingAddress =
				$this->GetAddressFromResponse($this->response->data[$this->response->root]['buyer-shipping-address']);
			$this->quote->getShippingAddress()
				->setAddressByArray($shippingAddress);

			// Attempt to find shipping costs in the response from Google
			if (isset($this->response->data[$this->response->root]['order-adjustment']['shipping']['merchant-calculated-shipping-adjustment'])) {
				$shipping = $this->response->data[$this->response->root]['order-adjustment']['shipping']['merchant-calculated-shipping-adjustment'];
			} else {
				$shipping = array (
					'shipping-cost' => array (
						'VALUE' => 0
					),
					'shipping-name' => array (
						'VALUE' => ''
					),
				);
			}

			$this->quote->getShippingAddress()
				->setShippingMethod(
					$shipping['shipping-cost']['VALUE'],
					$shipping['shipping-name']['VALUE'],
					$this->getShippingProviderModuleByName($shipping['shipping-name']['VALUE'])
				);
		}

		$this->handleNewOrderNotificationCouponAdjustment();
		$this->handleNewOrderNotificationGiftCertificateAdjustment();

		$selectedCurrency = getCurrencyById($GLOBALS['CurrentCurrency']);
		$newOrder = array(
			'orderpaymentmodule' => 'checkout_googlecheckout',
			'ordcurrencyid' => $selectedCurrency['currencyid'],
			'ordcurrencyexchangerate' => $selectedCurrency['currencyexchangerate'],
			'ordipaddress' => '',
			'extraInfo' => array(),

			'quote' => $this->quote,
		);

		$entity = new ISC_ENTITY_ORDER();
		$orderId = $entity->add($newOrder);

		// Failed to create the order
		if(!$orderId) {
			$GLOBALS['ISC_CLASS_LOG']->LogSystemError($this->logtype, sprintf(GetLang('GoogleCheckoutMissingCart'), isc_html_escape($this->module->cartid)));
			return;
		}

		$order = getOrder($orderId);

		$googleid = $this->response->data['new-order-notification']['google-order-number']['VALUE'];
		$this->SendGoogleNewOrderId($googleid, $order['orderid']);
		$updatedOrder = array(
			'ordpayproviderid' => $googleid,
		);

		$orderIds = array($order['orderid']);

		// Update the orders in the database
		$GLOBALS['ISC_CLASS_DB']->UpdateQuery('orders', $updatedOrder, "orderid IN (".implode(',', $orderIds).")");

		$completed = CompletePendingOrder($order['ordtoken'], ORDER_STATUS_PENDING, false);

		if ($this->response->data['new-order-notification']['buyer-marketing-preferences']['email-allowed']['VALUE'] == 'true') {
			$this->SubscribeCustomerToLists($order['orderid']);
		}

		if (!$completed) {
			$GLOBALS['ISC_CLASS_LOG']->LogSystemError($this->logtype, sprintf(GetLang('GoogleCheckoutCantCompleteOrder'), isc_html_escape($pendingToken), isc_html_escape(var_export($completed, true))));
			return;
		}

		EmptyCartAndKillCheckout();
		$GLOBALS['ISC_CLASS_LOG']->LogSystemSuccess($this->logtype, sprintf(GetLang('GoogleCheckoutOrderCreated'), (int) $order['orderid'], isc_html_escape($googleid)));
	}
Пример #5
0
		public function ProcessGatewayPing()
		{
			$pName = $_REQUEST['payer_name'];
			$pEmail = $_REQUEST['payer_email'];
			$qta = $_REQUEST['qta'];
			$thxId = $_REQUEST['thx_id'];

			$sessionToken = explode('_', $_REQUEST['custom'], 2);

			$payerId = $_REQUEST['payer_id'];
			$amount = $_REQUEST['amount'];

			$this->SetOrderData(LoadPendingOrdersByToken($sessionToken[0]));

			if($this->GetGatewayAmount() == 0) {
				exit;
			}

			if ($amount != $this->GetGatewayAmount()) {
				$GLOBALS['ISC_CLASS_LOG']->LogSystemError(array('payment', $this->GetName()), sprintf(GetLang($this->_languagePrefix.'AmountMismatch'), $this->GetGatewayAmount(), $amount));
				return false;
			}

			if (isset($_REQUEST['payer_email'])) {
				$updatedOrder = array(
					'ordpayproviderid' => $pEmail,
					'ordpaymentstatus' => 'captured',
				);

				$this->UpdateOrders($updatedOrder);
			}

			$GLOBALS['ISC_CLASS_LOG']->LogSystemSuccess(array('payment', $this->GetName()), GetLang($this->_languagePrefix.'Success'));

			// If the order was previously incomplete, we need to do some extra work
			if($this->GetOrderStatus() == ORDER_STATUS_INCOMPLETE) {
				// If a customer doesn't return to the store from PayPal, their cart will never be
				// emptied. So what we do here, is if we can, load up the existing customers session
				// and empty the cart and kill the checkout process. When they next visit the store,
				// everything should be "hunky-dory."
				session_write_close();
				$session = new ISC_SESSION($sessionToken[1]);
				EmptyCartAndKillCheckout();
			}

			// Update the status for all orders that we've just received the payment for
			foreach($this->GetOrders() as $orderId => $order) {
				$status = ORDER_STATUS_AWAITING_FULFILLMENT;
				// If it's a digital order & awaiting fulfillment, automatically complete it
				if($order['ordisdigital'] && ORDER_STATUS_AWAITING_FULFILLMENT) {
					$status = ORDER_STATUS_COMPLETED;
				}
				UpdateOrderStatus($orderId, $status);
			}

			return true;
		}
Пример #6
0
	/**
	 * Process the NAB pingback
	 */
	public function ProcessGatewayPing()
	{
		if(!isset($_REQUEST['payment_reference']) || !isset($_REQUEST['bank_reference']) || !isset($_REQUEST['orderToken']) || !isset($_REQUEST['signature'])) {
			exit;
		}

		$paymentReference = $_REQUEST['payment_reference'];
		$paymentAmount = number_format($_REQUEST['payment_amount'], 2, '.', '');
		$orderToken = $_REQUEST['orderToken'];
		$sessionToken = $_REQUEST['sessionToken'];
		$requestSignature = $_REQUEST['signature'];
		$transactionId = $_REQUEST['payment_number'];
		$bankReference = $_REQUEST['bank_reference'];

		$this->SetOrderData(LoadPendingOrdersByToken($orderToken));

		$orders = $this->GetOrders();
		list(,$order) = each($orders);
		$orderId = $order['orderid'];

		// GetGatewayAmount returns the amount from the order record, so $amount is that but formatted into #.##
		$amount = number_format($this->GetGatewayAmount(), 2, '.', '');

		// verify that the signature matches
		$verifySignature = md5($amount . $orderToken . $orderId . GetConfig('EncryptionToken'));

		if ($verifySignature != $requestSignature) {
			$errorMsg = GetLang('NabSignatureMismatchDetails', array('orderId' => $orderId, 'transactionId' => $transactionId));
			$GLOBALS['ISC_CLASS_LOG']->LogSystemError(array('payment', $this->GetName()), GetLang('NabSignatureMismatch'), $errorMsg);
			return false;
		}

		/** @var ISC_TRANSACTION */
		$transaction = GetClass('ISC_TRANSACTION');

		$previousTransaction = $transaction->LoadByTransactionId($transactionId, $this->GetId());

		if(is_array($previousTransaction) && $previousTransaction['transactionid']) {
			$GLOBALS['ISC_CLASS_LOG']->LogSystemError(array('payment', $this->GetName()), sprintf(GetLang('NabTransactionAlreadyProcessed'), $_REQUEST['payment_date']));
			return false;
		}

		// Need to finish the processing of the pingback
		$newTransaction = array(
			'providerid' => $this->GetId(),
			'transactiondate' => $_REQUEST['payment_date'],
			'transactionid' => $transactionId,
			'orderid' => $orderId,
			'message' => 'Completed',
			'status' => '',
			'amount' => $_REQUEST['payment_amount'],
			'extrainfo' => array()
		);

		$newTransaction['status'] = TRANS_STATUS_COMPLETED;
		$newOrderStatus = ORDER_STATUS_AWAITING_FULFILLMENT;

		$transaction->Create($newTransaction);

		// If the order was previously incomplete, empty the customers cart
		if($this->GetOrderStatus() == ORDER_STATUS_INCOMPLETE) {
			session_write_close();
			$session = new ISC_SESSION($sessionToken);
			EmptyCartAndKillCheckout();
		}

		$status = $newOrderStatus;
		// If it's a digital order & awaiting fulfillment, automatically complete it
		if($order['ordisdigital'] && $status == ORDER_STATUS_AWAITING_FULFILLMENT) {
			$status = ORDER_STATUS_COMPLETED;
		}
		UpdateOrderStatus($orderId, $status);

		$updatedOrder = array(
			'ordpayproviderid' => $_REQUEST['payment_number'],
			'ordpaymentstatus' => 'captured',
		);

		$this->UpdateOrders($updatedOrder);

		// This was a successful order
		$oldStatus = GetOrderStatusById($this->GetOrderStatus());

		if(!$oldStatus) {
			$oldStatus = 'Incomplete';
		}

		$newStatus = GetOrderStatusById($newOrderStatus);
		$extra = GetLang('NabSuccessDetails',
			array(
				'orderId' 			=> $orderId,
				'amount' 			=> $amount,
				'bankAuth' 			=> $bankReference,
				'transactionId' 	=> $transactionId,
				'paymentStatus' 	=> 'Captured',
				'newOrderStatus' 	=> $newStatus,
				'oldOrderStatus' 	=> $oldStatus,
			)
		);
		$GLOBALS['ISC_CLASS_LOG']->LogSystemSuccess(array('payment', $this->GetName()), GetLang('NabSuccess'), $extra);
		return true;
	}