Class: GoogleCheckout::Cart
- Includes:
- GoogleCheckout
- Defined in:
- lib/google-checkout/cart.rb
Overview
This class represents a cart for Google Checkout. After initializing it with a merchant_id
and merchant_key
, you add items via add_item, and can then get xml via to_xml, or html code for a form that provides a checkout button via checkout_button.
Example:
item = {
:name => 'A Quarter',
:description => 'One shiny quarter.',
:price => 0.25
}
@cart = GoogleCheckout::Cart.new(merchant_id, merchant_key, item)
@cart.add_item(:name => "Pancakes",
:description => "Flapjacks by mail."
:price => 0.50,
:quantity => 10,
"merchant-item-id" => '2938292839')
Then in your view:
Checkout here! <%= @cart.checkout_button %>
This object is also useful for getting back a url to the image for a Google Checkout button. You can use this image in forms that submit back to your own server for further processing via Google Checkout’s level 2 XML API.
Constant Summary collapse
- SANDBOX_CHECKOUT_URL =
"https://sandbox.google.com/checkout/cws/v2/Merchant/%s/checkout"
- PRODUCTION_CHECKOUT_URL =
"https://checkout.google.com/cws/v2/Merchant/%s/checkout"
- DefaultButtonOpts =
The default options for drawing in the button that are filled in when checkout_button or button_url is called.
{ :size => :medium, :style => 'white', :variant => 'text', :loc => 'en_US', :buy_or_checkout => nil, }
Constants included from GoogleCheckout
Constants inherited from Command
GoogleCheckout::Command::PRODUCTION_REQUEST_URL, GoogleCheckout::Command::SANDBOX_REQUEST_URL
Instance Attribute Summary collapse
-
#continue_shopping_url ⇒ Object
Returns the value of attribute continue_shopping_url.
-
#edit_cart_url ⇒ Object
Returns the value of attribute edit_cart_url.
-
#merchant_private_data ⇒ Object
You can provide extra data that will be sent to Google and returned with the NewOrderNotification.
Attributes inherited from Command
Instance Method Summary collapse
-
#add_item(item) ⇒ Object
This method puts items in the cart.
-
#button_url(opts = {}) ⇒ Object
Given a set of options for the button, button_url returns the URL for the button image.
-
#checkout_button(button_opts = {}) ⇒ Object
Returns HTML for a checkout form for buying all the items in the cart.
-
#currency ⇒ Object
Returns the currency for the cart.
- #empty? ⇒ Boolean
-
#flat_rate_shipping(frs_options) ⇒ Object
This method sets the flat rate shipping for the entire cart.
-
#initialize(merchant_id, merchant_key, *items) ⇒ Cart
constructor
You need to supply, as strings, the
merchant_id
andmerchant_key
used to identify your store to Google. -
#shipping_cost ⇒ Object
Returns the shipping cost for the contents of the cart.
-
#shipping_cost_xml ⇒ Object
Generates the XML for the shipping cost, conditional on.
-
#signature ⇒ Object
Returns the signature for the cart XML.
-
#size ⇒ Object
Number of items in the cart.
- #submit_domain ⇒ Object
-
#submit_url ⇒ Object
The Google Checkout form submission url.
-
#to_xml ⇒ Object
This is the important method; it generatest the XML call.
Methods included from GoogleCheckout
production?, sandbox?, use_production, use_sandbox
Methods inherited from Command
Constructor Details
#initialize(merchant_id, merchant_key, *items) ⇒ Cart
You need to supply, as strings, the merchant_id
and merchant_key
used to identify your store to Google. You may optionally supply one or more items to put inside the cart.
83 84 85 86 87 88 |
# File 'lib/google-checkout/cart.rb', line 83 def initialize(merchant_id, merchant_key, *items) super(merchant_id, merchant_key) @contents = [] @merchant_private_data = {} items.each { |i| add_item i } end |
Instance Attribute Details
#continue_shopping_url ⇒ Object
Returns the value of attribute continue_shopping_url.
68 69 70 |
# File 'lib/google-checkout/cart.rb', line 68 def continue_shopping_url @continue_shopping_url end |
#edit_cart_url ⇒ Object
Returns the value of attribute edit_cart_url.
67 68 69 |
# File 'lib/google-checkout/cart.rb', line 67 def edit_cart_url @edit_cart_url end |
#merchant_private_data ⇒ Object
You can provide extra data that will be sent to Google and returned with the NewOrderNotification.
This should be a Hash and will be turned into XML with proper escapes.
Beware using symbols as values. They may be set as sub-keys instead of values, so use a String or other datatype.
65 66 67 |
# File 'lib/google-checkout/cart.rb', line 65 def merchant_private_data @merchant_private_data end |
Instance Method Details
#add_item(item) ⇒ Object
This method puts items in the cart. item
may be a hash, or have a method named to_google_product
that returns a hash with the required values.
-
name
-
description (a brief description as it will appear on the bill)
-
price
You may fill in some optional values as well:
-
quantity (defaults to 1)
-
currency (defaults to ‘USD’)
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/google-checkout/cart.rb', line 138 def add_item(item) @xml = nil if item.respond_to? :to_google_product item = item.to_google_product end # We need to check that the necessary keys are in the hash, # Otherwise the error will happen in the middle of to_xml, # and the bug will be harder to track. missing_keys = [ :name, :description, :price ].select { |key| !item.include? key } unless missing_keys.empty? raise ArgumentError, "Required keys missing: #{missing_keys.inspect}" end @contents << { :quantity => 1, :currency => 'USD' }.merge(item) item end |
#button_url(opts = {}) ⇒ Object
Given a set of options for the button, button_url returns the URL for the button image. The options are the same as those specified on checkout.google.com/seller/checkout_buttons.html , with a couple of extra options for convenience. Rather than specifying the width and height manually, you may specify :size to be one of :small, :medium, or :large, and that you may set :buy_or_checkout to :buy_now or :checkout to get a ‘Buy Now’ button versus a ‘Checkout’ button. If you don’t specify :buy_or_checkout, the Cart will try to guess based on if the cart has more than one item in it. Whatever you don’t pass will be filled in with the defaults from DefaultButtonOpts.
http://checkout.google.com//checkout.gif
http://sandbox.google.com/checkout//checkout.gif
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
# File 'lib/google-checkout/cart.rb', line 335 def (opts = {}) opts = DefaultButtonOpts.merge opts opts[:buy_or_checkout] ||= @contents.size > 1 ? :checkout : :buy_now opts.merge! ButtonSizes[opts[:buy_or_checkout]][opts[:size]] bname = opts[:buy_or_checkout] == :buy_now ? 'buy.gif' : 'checkout.gif' opts.delete :size opts.delete :buy_or_checkout opts[:merchant_id] = @merchant_id path = opts.map { |k,v| "#{k}=#{v}" }.join('&') # HACK Sandbox graphics are in the checkout subdirectory subdir = "" if GoogleCheckout.sandbox? && bname == "checkout.gif" subdir = "checkout/" end # TODO Use /checkout/buttons/checkout.gif if in sandbox. "https://#{submit_domain}/#{ subdir }buttons/#{bname}?#{path}" end |
#checkout_button(button_opts = {}) ⇒ Object
Returns HTML for a checkout form for buying all the items in the cart.
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 |
# File 'lib/google-checkout/cart.rb', line 290 def ( = {}) @xml or to_xml burl = () html = Builder::XmlMarkup.new(:indent => 2) html.form({ :action => submit_url, :style => 'border: 0;', :id => 'BB_BuyButtonForm', :method => 'post', :name => 'BB_BuyButtonForm' }) do html.input({ :name => 'cart', :type => 'hidden', :value => Base64.encode64(@xml).gsub("\n", '') }) html.input({ :name => 'signature', :type => 'hidden', :value => Base64.encode64(signature).gsub("\n", '') }) html.input({ :alt => 'Google Checkout', :style => "width: auto;", :src => (), :type => 'image' }) end end |
#currency ⇒ Object
Returns the currency for the cart. Mixing currency not allowed; this library can’t convert between currencies.
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 |
# File 'lib/google-checkout/cart.rb', line 263 def currency # Mixing currency not allowed; this # library can't convert between # currencies. currencies = @contents.map { |item| item[:currency] }.uniq || "USD" case currencies.count when 0 "USD" when 1 currencies.first else raise RuntimeError.new("Mixing currency not allowed") end end |
#empty? ⇒ Boolean
109 110 111 |
# File 'lib/google-checkout/cart.rb', line 109 def empty? @contents.empty? end |
#flat_rate_shipping(frs_options) ⇒ Object
This method sets the flat rate shipping for the entire cart. If set, it will over ride the per product flat rate shipping. frs_options
should be a hash containing the following options:
-
price
You may fill an some optional values as well:
-
currency (defaults to ‘USD’)
97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/google-checkout/cart.rb', line 97 def flat_rate_shipping() # We need to check that the necessary keys are in the hash, # Otherwise the error will happen in the middle of to_xml, # and the bug will be harder to track. unless .include? :price raise ArgumentError, "Required keys missing: :price" end @flat_rate_shipping = {:currency => 'USD'}.merge() end |
#shipping_cost ⇒ Object
Returns the shipping cost for the contents of the cart.
254 255 256 257 258 259 |
# File 'lib/google-checkout/cart.rb', line 254 def shipping_cost currency = 'USD' shipping = @contents.inject(0) { |total,item| total + item[:regular_shipping].to_i }.to_s end |
#shipping_cost_xml ⇒ Object
Generates the XML for the shipping cost, conditional on
240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/google-checkout/cart.rb', line 240 def shipping_cost_xml xml = Builder::XmlMarkup.new if @flat_rate_shipping xml.price(:currency => currency) { xml.text! @flat_rate_shipping[:price].to_s } else xml.price(:currency => @currency) { xml.text! shipping_cost.to_s } end end |
#signature ⇒ Object
Returns the signature for the cart XML.
281 282 283 284 285 286 |
# File 'lib/google-checkout/cart.rb', line 281 def signature @xml or to_xml digest = OpenSSL::Digest::Digest.new('sha1') OpenSSL::HMAC.digest(digest, @merchant_key, @xml) end |
#size ⇒ Object
Number of items in the cart.
114 115 116 |
# File 'lib/google-checkout/cart.rb', line 114 def size @contents.size end |
#submit_domain ⇒ Object
118 119 120 |
# File 'lib/google-checkout/cart.rb', line 118 def submit_domain (GoogleCheckout.production? ? 'checkout' : 'sandbox') + ".google.com" end |
#submit_url ⇒ Object
The Google Checkout form submission url.
125 126 127 |
# File 'lib/google-checkout/cart.rb', line 125 def submit_url GoogleCheckout.sandbox? ? (SANDBOX_CHECKOUT_URL % @merchant_id) : (PRODUCTION_CHECKOUT_URL % @merchant_id) end |
#to_xml ⇒ Object
This is the important method; it generatest the XML call. It’s fairly lengthy, but trivial. It follows the docs at code.google.com/apis/checkout/developer/index.html#checkout_api
It returns the raw XML string, not encoded.
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/google-checkout/cart.rb', line 165 def to_xml raise RuntimeError, "Empty cart" if self.empty? xml = Builder::XmlMarkup.new xml.instruct! @xml = xml.tag!('checkout-shopping-cart', :xmlns => "http://checkout.google.com/schema/2") { xml.tag!("shopping-cart") { xml.items { @contents.each { |item| xml.item { if item.key?(:item_id) xml.tag!('merchant-item-id', item[:item_id]) end xml.tag!('item-name') { xml.text! item[:name].to_s } xml.tag!('item-description') { xml.text! item[:description].to_s } xml.tag!('unit-price', :currency => (item[:currency] || 'USD')) { xml.text! item[:price].to_s } xml.quantity { xml.text! item[:quantity].to_s } } } } unless @merchant_private_data.empty? xml.tag!("merchant-private-data") { @merchant_private_data.each do |key, value| xml.tag!(key, value) end } end } xml.tag!('checkout-flow-support') { xml.tag!('merchant-checkout-flow-support') { xml.tag!('edit-cart-url', @edit_cart_url) if @edit_cart_url xml.tag!('continue-shopping-url', @continue_shopping_url) if @continue_shopping_url xml.tag!("request-buyer-phone-number", false) # TODO tax-tables xml.tag!("tax-tables") { xml.tag!("default-tax-table") { xml.tag!("tax-rules") { xml.tag!("default-tax-rule") { xml.tag!("shipping-taxed", false) xml.tag!("rate", "0.00") xml.tag!("tax-area") { xml.tag!("world-area") } } } } } # TODO Shipping calculations # These are currently hard-coded for PeepCode. # Does anyone care to send a patch to enhance # this for more flexibility? xml.tag!('shipping-methods') { xml.tag!('pickup', :name =>'Shipping') { xml.tag!('price', "2.00", :currency => currency) } } } } } @xml.dup end |