Magento and Google Checkout behind a firewall

Advertisements

So I came across an issue recently when developing a copy of Magento locally, and having to test the Google Checkout functionality. There was one slight problem with that though: Google Checkout can’t see 192.168.1.x. Hmm.. how to get round that? Came up with a solution which let me do a lot of testing as though Google was calling in. The advantage to this is that if your Magento site is behind a firewall and for some reason GC can’t see the endpoint, you can use this.

// file: app/code/local/MyCompany/GoogleCheckout/Model/Observer.php

class MyCompany_GoogleCheckout_Model_Observer {
	private $_merchantId;
	private $_merchantKey;

	private $_continueToken;

	private $_debug = false;

	public function pollGoogleCheckoutApi() {

		$this->_merchantId = Mage::getStoreConfig('google/checkout/merchant_id');
		$this->_merchantKey = Mage::getStoreConfig('google/checkout/merchant_key');

		$this->_continueToken = Mage::getStoreConfig('google/checkout/continue_token');

		if (!$this->_continueToken || $this->_continueToken == "") {
			Mage::log('GooglePoll: No continue token set/defined.');
			return;
		}

		Mage::log('GooglePoll: Polling..');
		$this->_postToGoogle();
	}

	private function _updateContinueToken($token) {
		$_db = Mage::getSingleton('core/resource')->getConnection('core_write');
		$_db->query("UPDATE core_config_data SET value = '".$token."' WHERE path = 'google/checkout/continue_token'; ");
		$this->_continueToken = $token;
		return $this;
	}

	private function _postToGoogle() {
		$url = "https://checkout.google.com/api/checkout/v2/reports/Merchant/".$this->_merchantId;
		if (Mage::getStoreConfig('google/checkout/sandbox') == 1) {
			$url = "https://sandbox.google.com/checkout/api/checkout/v2/reports/Merchant/".$this->_merchantId;
		}

		$response = $this->_post($url,$this->_getNotificationDataRequestXml());

		$this->parseGoogleResponse($response);
	}

	private function parseGoogleResponse($response) {
		if (strlen($response) > 0) {
			// see if we have an error message returned instead of anything else.
			$is_error = preg_match('%(.*?)%',$response,$matches);
			if (!$is_error) {
				// parse out the next continue token
				preg_match('%(.*?)%',$response,$matches);
				$continue_token = $matches[1];

				// preg_match(_all) doesn't like new lines in what it's matching, so we replace them with an arbitary character
				// which we'll replace back to a new line later before sending it back to magento so we can do the regex..
				$response = str_replace("n","?",$response);

				$m = preg_match_all('%<([^?>s]*) serial-number="([0-9]{15}-[0-9]{5}-[0-9])">(.+?)%',$response,$matches);
				if ($m) {
					foreach ($matches[1] as $i =>; $tag) {
						$xmlchunk = "<".$tag." serial-number=".$matches[2][$i].">".str_replace("?","n",$matches[3][$i])."";
						$t = preg_match('%(.*)%',$xmlchunk,$t1);
						$g = preg_match('%(.*)%',$xmlchunk,$g1);
						Mage::log('GooglePoll: D/T: '.$t1[1].': (Google Order #: '.$g1[1].') Tag: '.$tag.' (Serial Number: '.$matches[2][$i].')');
						$this->_postToGoogleEndpoint($xmlchunk);
						// save going too fast, let magento keep up..
						sleep(1);
					}
				}

				// don't update the token until the end, incase this process crashes, we'll need to repeat the last call to get the
				// data we're missing.
				$this->_updateContinueToken($continue_token);
			}
			else {
				// log the error and leave. there's no point carrying on, and we have no more data to process anyway...
				Mage::log('GooglePoll: Error in response: '.$matches[1]);
				return;
			}
		}

		$matches = array();
		// parse out if there's more data to fetch. google polling api "paginates" the data into chunks to stop the response being too large.
		preg_match('%(.*?)%',$response,$matches);
		$more = $matches[1];

		// lather, rinse..
		if ($more == "true") {
			// repeat!
			sleep(5);
			$this->_postToGoogle();
		}
	}

	private function _getNotificationDataRequestXml() {
		return $this->_continueToken;
	}

	// post to magento.
	private function _postToGoogleEndpoint($xml) {
		$url = Mage::getBaseUrl()."googlecheckout/api/";
		$response = $this->_post($url,$xml);
		return $response;
	}

	// post. in general.
	private function _post($url,$data) {
		$session = curl_init($url);

		curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($session, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
		curl_setopt($session, CURLOPT_USERPWD, $this->_merchantId.':'.$this->_merchantKey);
		curl_setopt($session, CURLOPT_TIMEOUT, 60);
		curl_setopt($session, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($session, CURLOPT_POST, true);
		curl_setopt($session, CURLOPT_POSTFIELDS,$data);

		$response = curl_exec($session);
		if (curl_error($session)) {
			throw Exception(curl_error($session));
		}
		curl_close($session);
		return $response;
	}
}

And due to Magento’s multiple-file nature, now you have to tell it that it’s there, and what to do next.



	
		
			0.1
		
	
	
		
			
				MyCompany_GoogleCheckout_Model
			
		
	
	
		
			
				
					*/10 * * * *
				
				
					mycompany_googlecheckout/observer::pollGoogleCheckoutApi
				
			
		
	

Leave a comment

Your email address will not be published. Required fields are marked *