Lasso Soft Inc. > Home

[Google_Checkout]

LinkGoogle_Checkout
AuthorFletcher Sandbeck
CategoryUtility
Version8.5.x
LicensePublic Domain
Posted30 Jun 2006
Updated04 Jan 2008
More by this author...

Description

The [Google_Checkout] type allows for a simple integration of Google Checkout with Lasso. The type allows a shopping cart with multiple items to be formatted in the proper XML format for Google. The tag handles numerous features of the Google Checkout API including tax tables, flat-rate shipping, and many options. Complete descriptions of all the tags and parameters of the type are included within the source code itself.

This tag was originally published in the Tip of the Week for June 30, 2006:
http://www.omnipilot.com/TotW.1768.9158.lasso .

More information about the API which this tag implements can be found at this address: http://code.google.com/apis/checkout/developer/index.html and general information about Google Checkout can be found at http://checkout.google.com/.

Sample Usage

[Var: 'mycart' = (google_checkout: 
    -merchantid='1234567890', 
    -merchantkey='1234567890', 
    -editurl='http://www.example.com/edit',
    -continueurl='http://www.example.com/continue',
    -shippingname='Pony Express',
    -taxes=(array: '98366'=0.085, 'WA'=0.070, 'all'=0.0),
    -sandbox=true, 
    -expires=date->(add: -day=1) &)]

[$mycart->(additem: -name='My Widget', 
    -description='My patented widget. A true original.', 
    -price=159.99, 
    -quantity=2, 
    -shipping=10.00)]

[$mycart->(checkoutform: -Size='large')]

Source Code

Click the "Download" button below to retrieve a copy of this tag, including the complete documentation and sample usage shown on this page. Place the downloaded ".inc" file in your LassoStartup folder, restart Lasso, and you can begin using this tag immediately.

[
	// [Google_Checkout]
	// Copyright 2007 by LassoSoft, LLC.
	// Originally published in The June 30, 2006 Tip of the Week
	// Updated with new Google API addresses January 4, 2007
	// Introduction to Google Checkout
	// 
	//
	// Posted on TagSwap 
	//
	// Based on the Google Checkout API which can be found here
	// 
	// 
	// This type represents a shopping cart for the Google Checkout service
	// The type is used to create a shopping cart, add one or more items to it,
	// and then present either a checkout form to the site visitor or redirect
	// the visitor into the Google Checkout process.
	//
	// This type implements much of the non-interactive Google Checkout API including
	// both the direct form POST method and the alternative POST and redirect method,
	// flat-rate shipping for each item, a single sales tax table for US addresses,
	// many options including optional URLs, request for phone number, whether shipping
	// should be taxed, button size, and more.
	//
	// The tip of the week linked above should be consulted for details about how to get
	// started with this type.  The sandbox should always be used for full testing of this
	// type before it is used on a live server.  The type requires a Google Merchant Key and
	// Merchant ID.  
	//
	// Example
	//
	// 1 - Create a cart by entering the merchant ID and key provided by Google.  The edit URL
	// is shown on the cart.  The continue URL is shown after the visitor complets their purchase.
	// The shipping name is shown as the shipping method.  The taxes array sets a different tax rate
	// for a local zip code, Washington state, and the rest of the US.  The "sandbox" setting establishes
	// this as a test connection.  And, the expiration date means this cart must be checked out within 24
	// hours.
	//
	// [Var: 'mycart' = (google_checkout: 
	//     -merchantid='1234567890', 
	//     -merchantkey='1234567890', 
	//     -editurl='http://www.example.com/edit',
	//     -continueurl='http://www.example.com/continue',
	//     -shippingname='Pony Express',
	//     -taxes=(array: '98366'=0.085, 'WA'=0.070, 'all'=0.0),
	//     -sandbox=true, 
	//     -expires=date->(add: -day=1) &)]
	//
	// 2 - Add items to the cart.  Each item has a name, short description, price, quantity, and shipping cost. 
	// Note that the price and shipping cost are multipled by the quantity to get the totals.  Sales tax is added
	// later.  The amounts should be in the currency specified in the [Google_Checkout] tag (US dollars by default).
	//
	// [$mycart->(additem: -name='My Widget', 
	//     -description='My patented widget. A true original.', 
	//     -price=159.99, 
	//     -quantity=2, 
	//     -shipping=10.00)]
	//
	// 3 - Display a form for the visitor to check out.  The form will take the visitor to a Google page where they
	// can log into their Google account (or create one).  Once the checkout process is complete both the visitor and
	// you will be sent an email confirmation.  You can log in to your Google Checkout merchant account to fulfil the
	// order.
	//
	// [$mycart->(checkoutform: -Size='large')]
	//
	// 4 - Alternately, if you have your own checkout button you can use the following tag to post the cart data to
	// Google checkout and then redirect the user to the Google page where they can log into their Google account (as
	// above).  The following code shows a checkout image linked back to the current page.  The conditional posts the
	// form when the visitor clicks on the link.
	//
	// [$test->(checkoutimage: -size='large')]
	// [(action_param: 'action') >> 'post' ? $test->postcart]
	//

	Define_Type: 'Google_Checkout';
	
		Local: 'url' = '';
		Local: 'src' = '';
		Local: 'mkey' = '';
		Local: 'mid' = '';
		Local: 'currency' = '';
		Local: 'expires' = '';
		Local: 'continueurl' = '';
		Local: 'editurl' = '';
		Local: 'taxes' = '';
		Local: 'requestphone' = False;
		Local: 'taxshipping' = False;
		Local: 'shippingname' = '';
		Local: 'items' = Array;
		Local: 'cart' = '';
		Local: 'dirty' = False;
	
		// [Google_Checkout]
		// This tag is called when a new Google Checkout item is created.
		// The following options are possible
		// -MerchantKey='KEY' (Required, Provided by Google)
		// -MerchantID='ID' (Required, Provided by Google)
		// -Sandbox (If specified then the cart is in Sandbox mode for testing)
		// -EditURL='URL' (Allows the user to return to your site while they are viewing their cart) 
		// -ContinueURL='URL' (The URL for the user to return to your site after they checkout) 
		// -Taxes=(Array) (An array of pairs specifying the tax rules for your cart.  The taxes will
		// be calculated when the user checks out.  Each pair should be of the form '98366'=0.080 where
		// the first part is the region and the second the tax rate (e.g. 8%).  Regions can be five digit
		// US zip codes 98366, zip codes with a wild card 98*, two letter state abbreviations WA, or the
		// words 'all' for all valid US addresses, 'full' for all addresses in the 50 states, or 'continental'
		// for all addresses in the 48 contiguous states.  More specific rules should come before less specific.
		// -RequestPhone (If specified the phone number is requested from the purchaser)
		// -TaxShipping (If specified then sales tax is charged on shipping)
		// -ShippingName (A short two to three word description of the shipping method (e.g. Postal Mail or UPS Ground)
		// -Currency='USD' (Defaults to US dollars)
		// -Expires=Date (An expiration date for the cart)
		Define_Tag: 'onCreate',
				-Required='merchantkey',
				-Required='merchantid',
				-Optional='sandbox',
				-Optional='editurl',
				-Optional='continueurl',
				-Optional='taxes',
				-Optional='requestphone',
				-Optional='taxshipping',
				-Optional='shippingname',
				-Optional='currency',
				-Optional='expires';
			
			Self->'mkey' = (String: #merchantkey);
			Self->'mid' = (String: #merchantid);
			If: (Local_Defined: 'sandbox') && ((#sandbox === null) || (#sandbox != false));
				Self->'url' = 'https://sandbox.google.com/checkout/cws/v2/Merchant/' + (encode_stricturl: #merchantid) + '/';
				Self->'src' = 'http://sandbox.google.com/checkout/buttons/checkout.gif?merchant_id=' + (encode_stricturl: #merchantid);
			Else;
				Self->'url' = 'https://checkout.google.com/cws/v2/Merchant/' + (encode_stricturl: #merchantid) + '/';
				Self->'src' = 'http://checkout.google.com/buttons/checkout.gif?merchant_id=' + (encode_stricturl: #merchantid);
			/If;
			If: (Local_Defined: 'currency');
				Self->'currency' = #currency;
			Else;
				Self->'currency' = 'USD';
			/If;
			If: (Local_Defined: 'expires') && #expires->(IsA: 'date');
				Local: 'date' = #expires;
				#date->gmt == false ? Local: 'date' = (Date_LocalToGMT: #date); 
				Self->'expires' = #date;
			Else: (Local_Defined: 'expires') && (Valid_Date: #expires);
				Local: 'date' = (Date: #expires);
				#date->gmt == false ? Local: 'date' = (Date_LocalToGMT: #date); 
				Self->'expires' = #date;
			/If;
			If: (Local_Defined: 'editurl');
				Self->'editurl' = #editurl;
			/If;
			If: (Local_Defined: 'continueurl');
				Self->'continueurl' = #continueurl;
			/If;
			If: (Local_Defined: 'shippingname');
				Self->'shippingname' = #shippingname;
			Else;
				Self->'shippingname' = 'Standard Shipping';
			/If;
			If: (Local_Defined: 'taxes') && (#taxes->(IsA: 'map') || #taxes->(IsA: 'array'));
				Self->'taxes' = #taxes;
			/If;
			If: (Local_Defined: 'requestphone');
				Self->'requestphone' = (#requestphone === Null || #requestphone != False);
			/If;
			If: (Local_Defined: 'taxshipping');
				Self->'taxshipping' = (#taxshipping === Null || #taxshipping != False);
			/If;
			Self->'dirty' = True;
			
		/Define_Tag;
	
		// [String: Google_Checkout]
		// This tag is called when the cart is converted to string.  It does the work
		// of generating the XML for the cart.
		Define_Tag: 'onConvert', -Required='type';
			
			If: (self->'dirty' == False);
				Return: self->'cart';
			/If;
			
			Define_Tag: 'clean', -Required='input';
				Local: 'output' = (string: #input);
				#output->(replace: '&', '&');
				#output->(replace: '<', '<');
				#output->(replace: '>', '>');
				Return: @#output;
			/Define_Tag;
			
			Local: 'output' = '';
			#output += '\r\n';
			#output += '\r\n';
			#output += '\t\r\n';
			If: Self->'expires'->(IsA: 'date');
				#output += '\t\t\r\n';
				#output += '\t\t' + self->'expires'->(Format: '%QT%T') + '\r\n';
				#output += '\t\t\r\n';
			/If;
			#output += '\t\t\r\n';
			Local: 'shipping' = 0.0;
			Iterate: Self->'items', (Local: 'item');
				#item->(Find: 'quantity') == 0 ? Loop_Continue;
				#output += '\t\t\t\r\n';
				Iterate: (Array: 'item', 'item-name', 'item-description', 'unit-price', 'quantity'), (Local: 'key');
					#item !>> #key ? Loop_Continue;
					if: #key == 'unit-price';
						#output += '\t\t\t\t';
					else;
						#output += '\t\t\t\t<' + #key +'>';
					/if;
					#output += (clean: #item->(Find: #key));
					#output += '\r\n';
				/Iterate;
				#output += '\t\t\t\r\n';
				If: #item >> 'shipping';
					#shipping += (Integer: #item->(Find: 'quantity')) * (Decimal: #item->(Find: 'shipping'));
				/If;
			/Iterate;
			#output += '\t\t\r\n';
			#output += '\t\r\n';
			#output += '\t\r\n';
			#output += '\t\t\r\n';
			If: self->'continueurl' != '';
				#output += '\t\t\t' + (clean: self->'continueurl') + '\r\n';
			/If;
			If: self->'editurl' != '';
				#output += '\t\t\t' + (clean: self->'editurl') + '\r\n';
			/If;
			If: self->'requestphone' == True;
				#output += '\t\t\ttrue\r\n';
			/If;
			If: #shipping > 0;
				#output += '\t\t\t\r\n';
				#output += '\t\t\t\t\r\n';
				#output += '\t\t\t\t\t' + #shipping + '\r\n';
				#output += '\t\t\t\t\r\n';
				#output += '\t\t\t\r\n';
			/If;
			If: self->'taxes'->(IsA: 'map') || self->'taxes'->(IsA: 'array');
				#output += '\t\t\t\r\n';
				#output += '\t\t\t\t\r\n';
				#output += '\t\t\t\t\t\r\n';
				Iterate: self->'taxes', (Local: 'rule');
					#output += '\t\t\t\t\t\t\r\n';
					If: self->'taxshipping' == True;
						#output += '\t\t\t\t\t\t\ttrue\r\n';
					/If;
					#output += '\t\t\t\t\t\t\t' + (Decimal: #rule->Second) + '\r\n';
					#output += '\t\t\t\t\t\t\t\r\n';
						if: #rule->First >> 'continental';
							#output += '\t\t\t\t\t\t\t\t\r\n';
						else: #rule->First >> 'all';
							#output += '\t\t\t\t\t\t\t\t\r\n';
						else: #rule->First >> 'full';
							#output += '\t\t\t\t\t\t\t\t\r\n';
						else: (String_ReplaceRegexp: #rule->First, -Find='[A-Z][A-Z]', -Replace='') == '';
							#output += '\t\t\t\t\t\t\t\t' + (clean: #rule->First) + '\r\n';
						else: (String_ReplaceRegexp: #rule->First, -Find='[0-9]+\\*?', -Replace='') == '';
							#output += '\t\t\t\t\t\t\t\t' + (clean: #rule->First) + '\r\n';
						/if;
					#output += '\t\t\t\t\t\t\t\r\n';
					#output += '\t\t\t\t\t\t\r\n';
				/Iterate;
				#output += '\t\t\t\t\t\r\n';
				#output += '\t\t\t\t\r\n';
				#output += '\t\t\t\r\n';
			/If;
			#output += '\t\t\r\n';
			#output += '\t\r\n';
			#output += '\r\n';
			
			Self->'cart' = #output;
			Self->'dirty' = False;
			
			Return: @#output;
			
		/Define_Tag;
		
		// [Google_Checkout->Items]
		// Returns the array of items in the cart.  This can be used to modify the array
		// directly, change item quantities, remove items, etc.
		Define_Tag: 'Items';
		
			Self->'dirty' = True;
			Return: @self->'items';
		
		/Define_Tag;

		// [Google_Checkout->AddItem]
		// Adds an item to the cart.  The item can have the following attributes
		// -Name='Item Name' (Required)
		// -Description='Short item description' (Required)
		// -Price='Unit Price' (Required)
		// -Quantity='Integer' (Default 1)
		// -Shipping='Shipping Cost' (Default 0)
		Define_Tag: 'AddItem',
				-Required='name',
				-Required='description',
				-Required='price',
				-Optional='quantity',
				-Optional='shipping';
			
			Local: 'item' = (Map: 
					'item-name'=#name, 
					'item-description'=#description, 
					'unit-price'=#price, 
					'quantity'=(Math_Max: 1, (Local: 'quantity'))
				);
			(Local_Defined: 'shipping') ? #item->(Insert: 'shipping'=#shipping);
			Self->'dirty' = True;
			Self->'items'->(Insert: @#item);
			
		/Define_Tag;
	
		// [Google_Checkout->GetSignature]
		// Returns the HMAC SHA1 signature for the car with Base64 encoding suitable for posting to Google.
		Define_Tag: 'getsignature';
		
			If: (self->'dirty' == True);
				Self->(onConvert: 'string');
			/If;
			Return: (Encrypt_HMAC: -password=self->'mkey', -token=(bytes: self->'cart'), -digest='sha1', -base64); 
			
		/Define_Tag;
		
		// [Google_Checkout->GetCart]
		// Returns the current cart with Base64 encoding suitable for posting to Google.
		// [String: Google_Checkout] can be used to get the raw XML of the carty.
		Define_Tag: 'getcart';
		
			If: (self->'dirty' == True);
				Self->(onConvert: 'string');
			/If;
			Return: (Encode_Base64: self->'cart'); 

		/Define_Tag;
		
		// [Google_Checkout->PostCart]
		// Posts the cart to Google using [Include_URL] then redirects the user to view the cart.
		// This alternate method of posting the cart can be used instead of the Checkout Form below.
		Define_Tag: 'postcart';
		
			If: (self->'dirty' == True);
				Self->(onConvert: 'string');
			/If;
			Local: 'result' = (Include_URL: Self->'url' + 'request', -Username=Self->'mid', -Password=Self->'mkey', -PostParams=Self->'cart');
			Local: 'url' = (String_ReplaceRegExp: #result, -Find='[\\s\\S]*(.*?)[\\s\\S]*', -replace='\\1');
			#url->(replace: '&', '&');
			Redirect_URL: #url;
			
		/Define_Tag;
				
		// [Google_Checkout->CheckoutForm]
		// Outputs a 
including the cart, signature, member id and key, and the standard Google Checkout image. // -Size='small|large' (default medium) // -Alt='Alternate text which is included on the button' // -Style='white' (default transparent) // -Variant='disabled' (default enabled) Define_Tag: 'checkoutform', -Optional='size', -Optional='alt', -Optional='style', -Optional='variant'; If: (Local: 'size') >> 'large'; Local: 'width' = 180; Local: 'height' = 46; Else: (Local: 'size') >> 'small'; Local: 'width' = 160; Local: 'height' = 43; Else; Local: 'width' = 168; Local: 'height' = 44; /If; If: !(Local_Defined: 'alt'); Local: 'alt' = 'Fast checkout through Google'; /If; Local: 'output' = ''; #output += '\r\n'; #output += '\t\r\n'; #output += '\t\r\n'; #output += '\t\r\n'; #output += '
\r\n'; Return: @#output; /Define_Tag; // [Google_Checkout->CheckoutImage] // Outputs an tag for the standard Google Checkout image // -Size='small|large' (default medium) // -Alt='Alternate text which is included on the button' // -Style='white' (default transparent) // -Variant='disabled' (default enabled) // -Border=0 (default 0) // -Align='left|right (default left) Define_Tag: 'checkoutimage', -Optional='size', -Optional='alt', -Optional='style', -Optional='variant', -Optional='border', -Optional='align'; If: (Local: 'size') >> 'large'; Local: 'width' = 180; Local: 'height' = 46; Else: (Local: 'size') >> 'small'; Local: 'width' = 160; Local: 'height' = 43; Else; Local: 'width' = 168; Local: 'height' = 44; /If; If: !(Local_Defined: 'alt'); Local: 'alt' = 'Fast checkout through Google'; /If; Local: 'output' = ''; #output += '' + (encode_html: #alt) + '\r\n'; Return: @#output; /Define_Tag; /Define_Type; // [Encode_HMAC] // This tag generates a keyed hash message authentication code for a given input and password. // This tag will be included in a future version of Lasso so its definition is conditional. // // Both the -Password and -Token can be either byte streams or strings. // -Password specifies the key for the hash // -Token specifies the text message which is to be hashed // -Digest specifies the algorithm to use for the hash (usually MD5 or SHA1) // // By default the output is a byte stream // -Base64 specifies the output should be a Base64 encoded string. // -Hex specifies the output should be a hex format string 0x0123456789abcdef // -Cram specifies the output should be in a cram hex format 0123456789ABCDEF // // Note that [Encrypt_CRAMMD5] is equivalent to using this tag with -Digest='MD5' and -Cram. // if: !(lasso_tagexists: 'encrypt_hmac'); define_tag('hmac', -required = 'password', -required = 'token', -optional = 'digest', -optional = 'base64', -optional = 'hex', -optional = 'cram', -namespace = 'encrypt_'); local( 'pbytes' = bytes, 'ibytes' = bytes, 'obytes' = bytes, 'output' = bytes); if(local_defined: 'digest'); fail_if(cipher_list(-digest) !>> #digest, -9956, '[Encrypt_HMAC] The digest "' (string: #digest) + '" is not supported by Lasso on this machine. Supported digest types include (' + (cipher_list: -digest)->(join: ', ') + ').'); else; local: 'digest' = 'md5'; /if; if(#password->size > 64); #pbytes = cipher_digest(#password, -digest=#digest); else: #password->isa('bytes'); #pbytes = #password; else; #pbytes->importstring(#password, 'iso-8859-1'); /if; iterate: #pbytes, local('byte'); #ibytes->import8bits(integer(#byte)->bitxor(0x36) &); #obytes->import8bits(integer(#byte)->bitxor(0x5c) &); /iterate; if(#pbytes->size < 64); loop(64 - #pbytes->size); #ibytes->import8bits(0x36); #obytes->import8bits(0x5c); /loop; /if; if: #token->(isa: 'bytes'); #ibytes += #token; else; #ibytes->importstring(#token, 'iso-8859-1'); /if; #obytes += cipher_digest(#ibytes, -digest=#digest); #output = cipher_digest(#obytes, -digest=#digest); if(local_defined('hex') && ((#hex === null) || (#hex != false))); return('0x' + string_lowercase(encode_hex(#output))); else(local_defined('cram') && ((#cram === null) || (#cram != false))); return(encode_hex(#output)); else(local_defined('base64') && ((#base64 === null) || (#base64 != false))); return(encode_base64(#output)); else; return(@#output); /if; /define_tag; /if; ]

Related Tags

Comments

No comments

Please log in to comment

Subscribe to the LassoTalk mail list

LassoSoft Inc. > Home

 

 

©LassoSoft Inc 2015 | Web Development by Treefrog Inc | PrivacyLegal terms and Shipping | Contact LassoSoft