Class: Google4R::Checkout::Command

Inherits:
Object
  • Object
show all
Defined in:
lib/google4r/checkout/commands.rb

Overview

Abstract super class for all commands that are to be sent to Google. Provides the base functionality for signing and encoding the cart.

Direct Known Subclasses

CheckoutCommand

Constant Summary collapse

SANDBOX_URL =

The URL to use for requests to the sandboxed API. The merchant id is to be put in via String#%.

"https://sandbox.google.com/checkout/cws/v2/Merchant/%s/request"
PRODUCTION_URL =

The URL to use for real requests to the Google Checkout API. The merchant id is to be put in via String#%.

"https://checkout.google.com/cws/v2/Merchant/%s/request"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(frontend) ⇒ Command

Initialize the frontend attribute with the value of the frontend parameter.



55
56
57
# File 'lib/google4r/checkout/commands.rb', line 55

def initialize(frontend)
  @frontend = frontend
end

Instance Attribute Details

#frontendObject (readonly)

The Frontent class that was used to create this CheckoutCommand and whose configuration will be used.



52
53
54
# File 'lib/google4r/checkout/commands.rb', line 52

def frontend
  @frontend
end

Instance Method Details

#send_to_google_checkoutObject

Sends the cart’s XML to GoogleCheckout via HTTPs with Basic Auth.

Raises an OpenSSL::SSL::SSLError when the SSL certificate verification failed.

Raises a GoogleCheckoutError when Google returns an error.

Raises a RuntimeException on unknown responses.



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/google4r/checkout/commands.rb', line 89

def send_to_google_checkout
  # Create HTTP(S) POST command and set up Basic Authentication.
  url_str = 
    if frontend.configuration[:use_sandbox] then
      SANDBOX_URL % frontend.configuration[:merchant_id]
    else
      PRODUCTION_URL % frontend.configuration[:merchant_id]
    end
  url = URI.parse(url_str)
  
  request = Net::HTTP::Post.new(url.path)
  request.basic_auth(frontend.configuration[:merchant_id], frontend.configuration[:merchant_key])

  # Set up the HTTP connection object and the SSL layer.
  https = Net::HTTP.new(url.host, url.port)
  https.use_ssl = true
  https.cert_store = self.class.x509_store
  https.verify_mode = OpenSSL::SSL::VERIFY_PEER
  https.verify_depth = 5

  # Send the request to Google.
  result = https.request(request, self.to_xml)
  
  case result
  when Net::HTTPSuccess then
    xml_doc = REXML::Document.new(result.body)
    
    case xml_doc.root.name
    when 'checkout-redirect'
      serial_number = xml_doc.elements['/checkout-redirect/@serial-number'].value
      redirect_url = xml_doc.elements['/checkout-redirect/redirect-url/text()'].value
      return CheckoutRedirectResponse.new(serial_number, redirect_url)
    else
      raise "Unknown response:\n--\n#{xml_doc.to_s}\n--"
    end
  when Net::HTTPClientError then
    xml_doc = REXML::Document.new(result.body)
    
    if xml_doc.elements['/error/@serial-number'].nil? or xml_doc.elements['/error/error-message/text()'].nil? then
      raise "Invalid response from Google:\n---\n#{result.body}\n---"
    end
    
    hash = 
      {
        :serial_number => xml_doc.elements['/error/@serial-number'].value,
        :message       => xml_doc.elements['/error/error-message/text()'].value
      }
    
    raise GoogleCheckoutError.new(hash)
  when Net::HTTPRedirection, Net::HTTPServerError, Net::HTTPInformation then
    raise "Unexpected reponse code (#{result.class}): #{result.code} - #{result.message}"
  else
    raise "Unknown reponse code: #{result.code} - #{result.message}"
  end
end

#sign_and_encodeObject

Returns a hash with xml representation of this command and the signature for this representation. Both values are Base64 encoded.

This can be used for generating the CheckoutButton when directly posted to Google.

command.sign_and_encode
# => { :cart => 'asdf', :signature => 'asdfasdf' }


67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/google4r/checkout/commands.rb', line 67

def sign_and_encode
  xml = self.to_xml
  
  # Create a signature of the XML using OpenSSL::HMAC. Note that we do not want a 
  # hexadecimal result from the hash function but a binary result.
  signature = OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha1'), 
    frontend.configuration[:merchant_key], xml)
  
  # Create Base64 encoded versions of the XML and the signature.
  encoded_xml = Base64.encode64(xml)
  encoded_signature = Base64.encode64(signature)
  
  return { :cart => encoded_xml, :signature => encoded_signature }
end

#to_xmlObject

Abstract method that is to contain the command’s XML representation.



146
147
148
# File 'lib/google4r/checkout/commands.rb', line 146

def to_xml
  raise "Command#to_xml is abstract and must be overridden in a subclass."
end