google4r-checkout 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. data/CHANGES +40 -0
  2. data/LICENSE +22 -0
  3. data/README +76 -0
  4. data/lib/google4r/checkout.rb +33 -0
  5. data/lib/google4r/checkout/commands.rb +260 -0
  6. data/lib/google4r/checkout/frontend.rb +108 -0
  7. data/lib/google4r/checkout/notifications.rb +549 -0
  8. data/lib/google4r/checkout/shared.rb +541 -0
  9. data/lib/google4r/checkout/xml_generation.rb +313 -0
  10. data/test/integration/checkout_command_test.rb +103 -0
  11. data/test/unit/address_test.rb +131 -0
  12. data/test/unit/area_test.rb +44 -0
  13. data/test/unit/checkout_command_test.rb +116 -0
  14. data/test/unit/checkout_command_xml_generator_test.rb +203 -0
  15. data/test/unit/command_test.rb +115 -0
  16. data/test/unit/flat_rate_shipping_test.rb +114 -0
  17. data/test/unit/frontend_test.rb +63 -0
  18. data/test/unit/item_test.rb +159 -0
  19. data/test/unit/marketing_preferences_test.rb +65 -0
  20. data/test/unit/merchant_code_test.rb +122 -0
  21. data/test/unit/new_order_notification_test.rb +115 -0
  22. data/test/unit/notification_acknowledgement_test.rb +43 -0
  23. data/test/unit/notification_handler_test.rb +93 -0
  24. data/test/unit/order_adjustment_test.rb +119 -0
  25. data/test/unit/order_state_change_notification_test.rb +159 -0
  26. data/test/unit/pickup_shipping_test.rb +70 -0
  27. data/test/unit/postal_area_test.rb +71 -0
  28. data/test/unit/private_data_parser_test.rb +68 -0
  29. data/test/unit/shipping_adjustment_test.rb +100 -0
  30. data/test/unit/shipping_method_test.rb +41 -0
  31. data/test/unit/shopping_cart_test.rb +146 -0
  32. data/test/unit/tax_rule_test.rb +70 -0
  33. data/test/unit/tax_table_test.rb +82 -0
  34. data/test/unit/us_country_area_test.rb +76 -0
  35. data/test/unit/us_state_area_test.rb +70 -0
  36. data/test/unit/us_zip_area_test.rb +66 -0
  37. data/test/unit/world_area_test.rb +48 -0
  38. data/var/cacert.pem +7815 -0
  39. metadata +92 -0
data/CHANGES ADDED
@@ -0,0 +1,40 @@
1
+ = google4r-checkout Changelog
2
+
3
+ == HEAD
4
+
5
+ == 0.1.0 (2007-05-12)
6
+
7
+ * Added property "shipping_taxed" to TaxRule (contributed by Dan Dukeson).
8
+ * Added XML generation for the tax tables in the shopping cart (contributed by Dan Dukeson).
9
+ * Added Area subclasses WorldArea and PostalArea (contributed by Dan Dukeson).
10
+ * Changed time zones in tests to UTC.
11
+ * Added Test::Unit::TestCase#assert_strings_equal to test_helper.rb.
12
+ * Added "rake test" (alias of "rake test:all")
13
+ * Added GoogleCheckoutError#to_s to return verbose representation.
14
+ * Split google4r into google4r-checkout and google4r-maps.
15
+ * MerchantCode#create_from_element raises an ArgumentError instead of a RuntimeError on invalid elements now.
16
+ * Changed the #create_from_element code to set the properties directly into the objects instead of building Hashes to collect the values first.
17
+ * "Resolved" the problem of converting currency amounts which are fractional numbers into the amount of the minor currency to be passed into the Money class: Instead of converting the fractional number into a float and multiplying by 100, all nonnumeric characters are stripped from the string, the resulting number is converted into an integer and this integer is then passed to Money.new.
18
+ * Added example to NotificationHandler of how to use the class.
19
+ * Added link to simple_http_auth plugin in NotificationHandler which allows for easy HTTP Auth Basic protection of Rails controllers.
20
+ * Renamed CheckoutCommand#cart to CheckoutCommand#shopping_cart
21
+ * CheckoutCommand raises ArgumentError instead of RuntimeError on invalid clazz parameter.
22
+ * Added "Howto freeze google4r in a Rails project" to README
23
+ * Google4R::Checkout::Command#to_xml raises an NotImplementedError instead of a RuntimeError now.
24
+ * Geocoder returns nil on 603 (G_UNAVAILABLE_ADDRESS) results now.
25
+ * Added support for registering GUnload() to be called on window's unload event.
26
+ * The generated Javascript that creates the GMap2() instance (and thus modifies the map div) has been put into a function <var name>_loader that is called in an onload handler. This should remove a problem with MSIE.
27
+ * Using Syck as the YAML parser now. However, a workaround is needed because of http://code.whytheluckystiff.net/syck/ticket/27.
28
+ * Only require the json gem if objects have no "to_json" method already added to them. This solves a problem with converting arbitrary objects to json because the json gem seemingly only converts simple types.
29
+ * Added GMarker#info_window_html.
30
+ * Added support for onclick handlers in markers.
31
+ * Added support for the value :auto of GMap2#zoom and GMap2#center.
32
+ * Fixed buggy generation of GMarker Javascript.
33
+ * Adding website folder to contain a webgen based website.
34
+ * Fixed a problem with generating XML from Hashes in the "private" data of shopping carts and items.
35
+ * The parse for the <order-adjustment> tag does not expect to see a <shipping> tag in every case any more.
36
+ * Extending Google4R::Maps by the classes GMap2, GIcon and GMarker to allow for easy Google Maps HTML generation.
37
+
38
+ == 0.0.1 (2007-02-17)
39
+
40
+ * initial release, be prepared for some API changes that move the API closer to the XML API
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Unless noted otherwise, the files of this projects are licensed under a MIT
2
+ style license:
3
+
4
+ Copyright (c) 2007 Manuel Holtgrewe
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to
8
+ deal in the Software without restriction, including without limitation the
9
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
+ sell copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in
14
+ all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
+ IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,76 @@
1
+ = google4r/checkout
2
+
3
+ google4r/checkout is a library to access the Google Checkout API.
4
+
5
+ === License
6
+
7
+ google4r itself is distributed under an MIT style license.
8
+
9
+ However, the library includes the cacert.pem:http://curl.haxx.se/ca/cacert.pem file from the Mozilla project. This file is distributed under the MPL:http://www.mozilla.org/MPL/.
10
+
11
+ == Status
12
+
13
+ You can find more information on the Google Checkout API here:http://code.google.com/apis/checkout/developer/index.html. Note that the API documentation assumes an understanding of the Google Checkout XML API.
14
+
15
+ Google4R also contains a partial implementation of the level 2 of the Google Checkout API:
16
+
17
+ * The <checkout-cart-command> tag and all of its subtags that are not related to the merchant calculation API can be generated.
18
+ * The <new-order-notification> tag and all of its subtags which are not related to the merchant calculation API can be parsed.
19
+ * The <order-state-change-notification> tag can be parsed.
20
+
21
+ == Google Checkout Tests
22
+
23
+ You have to place a file called 'frontend_configuration.rb' in the directory'test' with the configuration for the Google4R::Checkout::Frontend class to use for running the tests.
24
+
25
+ The file should contain content similar to:
26
+
27
+ # Uncomment the following line if you are using Google Checkout in Great Britain
28
+ # and adjust it if you want to test google4r-checkout against any other (future)
29
+ # Google Checkout service.
30
+
31
+ # Money.default_currency = 'GBP'
32
+
33
+ # The test configuration for the Google4R::Checkout::Frontend class.
34
+ FRONTEND_CONFIGURATION =
35
+ {
36
+ :merchant_id => '<your merchant id>',
37
+ :merchant_key => '<your merchant key>',
38
+ :use_sandbox => true
39
+ }
40
+
41
+ == TODO
42
+
43
+ Notifications:
44
+
45
+ * <risk-information-notification>
46
+ * <charge-amount-notification>
47
+ * <refund-amount-notification>
48
+ * <chargeback-amount-notification>
49
+ * <authorization-amount-notification>
50
+
51
+ All of the Order Processing API.
52
+
53
+ == Dependencies
54
+
55
+ The unit tests use Mocha so you have to install the gem "mocha" to run the tests. You will also need the money gem library.
56
+
57
+ == How To: Freeze a google4r version in a Rails project
58
+
59
+ <code>rake rails:freeze:gems</code> only works for the Rails gems. So, how do you freeze your own gems like google4r? It turns out to be pretty straightforward:
60
+
61
+ cd RAILS_ROOT
62
+ cd vendor
63
+ gem unpack google4r-checkout
64
+ ls
65
+ # ... google4r-checkout-0.1.1 ...
66
+
67
+ Then, open RAILS_ROOT/config/environment.rb in your favourite text editor and add the following lines at the top of the file just below <code>require File.join(File.dirname(__FILE__), 'boot')</code>:
68
+
69
+ # Freeze non-Rails gem.
70
+ Dir.glob(File.join(RAILS_ROOT, 'vendor', '*', 'lib')) do |path|
71
+ $LOAD_PATH << path
72
+ end
73
+
74
+ Now you can use the following in your own code:
75
+
76
+ require 'google4r/checkout'
@@ -0,0 +1,33 @@
1
+ #--
2
+ # Project: google4r
3
+ # File: lib/google4r/checkout.rb
4
+ # Author: Manuel Holtgrewe <purestorm at ggnore dot net>
5
+ # Copyright: (c) 2007 by Manuel Holtgrewe
6
+ # License: MIT License as follows:
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining
9
+ # a copy of this software and associated documentation files (the
10
+ # "Software"), to deal in the Software without restriction, including
11
+ # without limitation the rights to use, copy, modify, merge, publish,
12
+ # distribute, sublicense, and/or sell copies of the Software, and to permit
13
+ # persons to whom the Software is furnished to do so, subject to the
14
+ # following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be included
17
+ # in all copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
25
+ # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ #++
27
+ # Require all the files that provide the code for the Google Checkout wrapper.
28
+
29
+ require 'google4r/checkout/shared'
30
+ require 'google4r/checkout/commands'
31
+ require 'google4r/checkout/notifications'
32
+ require 'google4r/checkout/xml_generation'
33
+ require 'google4r/checkout/frontend'
@@ -0,0 +1,260 @@
1
+ #--
2
+ # Project: google4r
3
+ # File: lib/google4r/checkout/commands.rb
4
+ # Author: Manuel Holtgrewe <purestorm at ggnore dot net>
5
+ # Copyright: (c) 2007 by Manuel Holtgrewe
6
+ # License: MIT License as follows:
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining
9
+ # a copy of this software and associated documentation files (the
10
+ # "Software"), to deal in the Software without restriction, including
11
+ # without limitation the rights to use, copy, modify, merge, publish,
12
+ # distribute, sublicense, and/or sell copies of the Software, and to permit
13
+ # persons to whom the Software is furnished to do so, subject to the
14
+ # following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be included
17
+ # in all copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
25
+ # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ #++
27
+ # This file contains the classes and modules that are used by the command
28
+ # generating code.
29
+
30
+ require 'openssl'
31
+ require 'money'
32
+ require 'net/http'
33
+ require 'net/https'
34
+ require 'uri'
35
+
36
+ module Google4R #:nodoc:
37
+ module Checkout #:nodoc:
38
+ # Abstract super class for all commands that are to be sent to Google. Provides the base
39
+ # functionality for signing and encoding the cart.
40
+ class Command
41
+ # The URL to use for requests to the sandboxed API. The merchant id is to be
42
+ # put in via String#%.
43
+ #--
44
+ # TODO: Move this into a class variable (e.g. via cattr) so it is adaptable.
45
+ #++
46
+ SANDBOX_URL = "https://sandbox.google.com/checkout/cws/v2/Merchant/%s/request"
47
+
48
+ # The URL to use for real requests to the Google Checkout API. The merchant id
49
+ # is to be put in via String#%.
50
+ #--
51
+ # TODO: Move this into a class variable (e.g. via cattr) so it is adaptable.
52
+ #++
53
+ PRODUCTION_URL = "https://checkout.google.com/cws/v2/Merchant/%s/request"
54
+
55
+ # The Frontent class that was used to create this CheckoutCommand and whose
56
+ # configuration will be used.
57
+ attr_reader :frontend
58
+
59
+ # Initialize the frontend attribute with the value of the frontend parameter.
60
+ def initialize(frontend)
61
+ @frontend = frontend
62
+ end
63
+
64
+ # Sends the cart's XML to GoogleCheckout via HTTPs with Basic Auth.
65
+ #
66
+ # Raises an OpenSSL::SSL::SSLError when the SSL certificate verification failed.
67
+ #
68
+ # Raises a GoogleCheckoutError when Google returns an error.
69
+ #
70
+ # Raises a RuntimeException on unknown responses.
71
+ #--
72
+ # TODO: The send-and-expect-response part should be adaptable to other commands and responses.
73
+ #++
74
+ def send_to_google_checkout
75
+ # Create HTTP(S) POST command and set up Basic Authentication.
76
+ url_str =
77
+ if frontend.configuration[:use_sandbox] then
78
+ SANDBOX_URL % frontend.configuration[:merchant_id]
79
+ else
80
+ PRODUCTION_URL % frontend.configuration[:merchant_id]
81
+ end
82
+ url = URI.parse(url_str)
83
+
84
+ request = Net::HTTP::Post.new(url.path)
85
+ request.basic_auth(frontend.configuration[:merchant_id], frontend.configuration[:merchant_key])
86
+
87
+ # Set up the HTTP connection object and the SSL layer.
88
+ https = Net::HTTP.new(url.host, url.port)
89
+ https.use_ssl = true
90
+ https.cert_store = self.class.x509_store
91
+ https.verify_mode = OpenSSL::SSL::VERIFY_PEER
92
+ https.verify_depth = 5
93
+
94
+ # Send the request to Google.
95
+ result = https.request(request, self.to_xml)
96
+
97
+ case result
98
+ when Net::HTTPSuccess then
99
+ xml_doc = REXML::Document.new(result.body)
100
+
101
+ case xml_doc.root.name
102
+ when 'checkout-redirect'
103
+ serial_number = xml_doc.elements['/checkout-redirect/@serial-number'].value
104
+ redirect_url = xml_doc.elements['/checkout-redirect/redirect-url/text()'].value
105
+ return CheckoutRedirectResponse.new(serial_number, redirect_url)
106
+ else
107
+ raise "Unknown response:\n--\n#{xml_doc.to_s}\n--"
108
+ end
109
+ when Net::HTTPClientError then
110
+ xml_doc = REXML::Document.new(result.body)
111
+
112
+ if xml_doc.elements['/error/@serial-number'].nil? or xml_doc.elements['/error/error-message/text()'].nil? then
113
+ raise "Invalid response from Google:\n---\n#{result.body}\n---"
114
+ end
115
+
116
+ hash =
117
+ {
118
+ :serial_number => xml_doc.elements['/error/@serial-number'].value,
119
+ :message => xml_doc.elements['/error/error-message/text()'].value
120
+ }
121
+
122
+ raise GoogleCheckoutError.new(hash)
123
+ when Net::HTTPRedirection, Net::HTTPServerError, Net::HTTPInformation then
124
+ raise "Unexpected reponse code (#{result.class}): #{result.code} - #{result.message}"
125
+ else
126
+ raise "Unknown reponse code: #{result.code} - #{result.message}"
127
+ end
128
+ end
129
+
130
+ # Abstract method that is to contain the command's XML representation.
131
+ #
132
+ # Raises a NotImplementedError by default, override to remove this.
133
+ def to_xml
134
+ raise NotImplementedError, "Command#to_xml is abstract and must be overridden in a subclass."
135
+ end
136
+
137
+ protected
138
+
139
+ # Class method to return the OpenSSL::X509::Store instance for the
140
+ # CA certificates.
141
+ #--
142
+ # TODO: Is OpenSSL::X509::Store thread safe when reading only? This method most certainly is *not*. It must become so.
143
+ #++
144
+ def self.x509_store
145
+ return @@x509_store if defined?(@@x509_store)
146
+
147
+ cacert_path = File.expand_path(File.dirname(__FILE__) + '/../../../var/cacert.pem')
148
+
149
+ @@x509_store = OpenSSL::X509::Store.new
150
+ @@x509_store.add_file(cacert_path)
151
+
152
+ return @@x509_store
153
+ end
154
+ end
155
+
156
+ # The CheckoutCommand represents a <checkout-shopping-cart> command sent
157
+ # to the server.
158
+ #
159
+ # A CheckoutCommand instance can have an arbitrary number of TaxTable
160
+ # and ShippingMethod instances. You must create these instances using the
161
+ # create_* methods which CheckoutCommand supplies.
162
+ #
163
+ # CheckoutCommand#send_to_google_checkout returns CheckoutRedirectResponse
164
+ # instances.
165
+ #
166
+ # Use the Frontend class to create new CheckoutCommand instances and do not
167
+ # instanciate the class directly.
168
+ #
169
+ # Note that you have to create/set the tax tables for CheckoutCommands before you
170
+ # can add any items to the cart that define a tax table.
171
+ #
172
+ # === Example
173
+ #
174
+ # frontend = Google4R::Checkout::Frontend.new(configuration)
175
+ # frontend.tax_table_factory = TaxTableFactory.new
176
+ # command = frontend.create_checkout_command
177
+ class CheckoutCommand < Command
178
+ # The ShoppingCart of this CheckoutCommand.
179
+ attr_reader :shopping_cart
180
+
181
+ # An array of the TaxTable objects of this CheckoutCommand. They have been
182
+ # created with the tax table factory of the frontend which created this
183
+ # command.
184
+ attr_reader :tax_tables
185
+
186
+ # An array of ShippingMethod objects of this CheckoutCommand. Use
187
+ # #create_shipping_method to create new shipping methods.
188
+ attr_reader :shipping_methods
189
+
190
+ # The URL at where the cart can be edited (String, optional).
191
+ attr_accessor :edit_cart_url
192
+
193
+ # The URL to continue shopping after completing the checkout (String, optional).
194
+ attr_accessor :continue_shopping_url
195
+
196
+ # A boolean flag; true iff the customer HAS to provide his phone number (optional).
197
+ attr_accessor :request_buyer_phone_number
198
+
199
+ # Generates the XML for this CheckoutCommand.
200
+ def to_xml
201
+ CheckoutCommandXmlGenerator.new(self).generate
202
+ end
203
+
204
+ # Initialize a new CheckoutCommand with a fresh CheckoutCart and an empty
205
+ # Array of tax tables and an empty array of ShippingMethod instances.
206
+ # Do not use this method directly but use Frontent#create_checkout_command
207
+ # to create CheckoutCommand objects.
208
+ def initialize(frontend)
209
+ super(frontend)
210
+
211
+ @shopping_cart = ShoppingCart.new(self)
212
+ @tax_tables = frontend.tax_table_factory.effective_tax_tables_at(Time.new)
213
+ @shipping_methods = Array.new
214
+ end
215
+
216
+ # Use this method to create a new shipping method. You have to pass in one of
217
+ # { PickupShipping, FlatRateShipping } for clazz. The method will create a
218
+ # new instance of the class you passedin object and add it to the internal list
219
+ # of shipping methods.
220
+ #
221
+ # If you pass a block to this method (preferred) then the newly created
222
+ # ShippingMethod object will be passed into this block for setting its attributes.
223
+ # The newly created shipping method will be returned in all cases.
224
+ #
225
+ # The first created shipping method will be used as the default.
226
+ #
227
+ # Raises a ArgumentError if the parameter clazz is invalid.
228
+ def create_shipping_method(clazz, &block)
229
+ if not [ PickupShipping, FlatRateShipping ].include?(clazz) then
230
+ raise ArgumentError, "Unknown shipping method: #{clazz.inspect}."
231
+ end
232
+
233
+ shipping_method = clazz.new
234
+ @shipping_methods << shipping_method
235
+
236
+ yield(shipping_method) if block_given?
237
+
238
+ return shipping_method
239
+ end
240
+ end
241
+
242
+ # CheckoutRedirectResponse instances are returned when a CheckoutCommand is successfully
243
+ # processed by Google Checkout.
244
+ class CheckoutRedirectResponse
245
+ # The serial number of the <checkout-redirect> response.
246
+ attr_reader :serial_number
247
+
248
+ # The URL to redirect to.
249
+ attr_reader :redirect_url
250
+
251
+ # Create a new CheckoutRedirectResponse with the given serial number and redirection URL.
252
+ # Do not create CheckoutRedirectResponse instances in your own code. Google4R creates them
253
+ # for you.
254
+ def initialize(serial_number, redirect_url)
255
+ @serial_number = serial_number
256
+ @redirect_url = redirect_url
257
+ end
258
+ end
259
+ end
260
+ end
@@ -0,0 +1,108 @@
1
+ #--
2
+ # Project: google4r
3
+ # File: lib/google4r/checkout/frontend.rb
4
+ # Author: Manuel Holtgrewe <purestorm at ggnore dot net>
5
+ # Copyright: (c) 2007 by Manuel Holtgrewe
6
+ # License: MIT License as follows:
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining
9
+ # a copy of this software and associated documentation files (the
10
+ # "Software"), to deal in the Software without restriction, including
11
+ # without limitation the rights to use, copy, modify, merge, publish,
12
+ # distribute, sublicense, and/or sell copies of the Software, and to permit
13
+ # persons to whom the Software is furnished to do so, subject to the
14
+ # following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be included
17
+ # in all copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
25
+ # OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ #++
27
+ # This file provides the Google4R::Checkout::Frontend class that is a factory for the commands
28
+ # to be sent to Google Checkout.
29
+
30
+ module Google4R #:nodoc:
31
+ module Checkout #:nodoc:
32
+ # The Frontend class is the factory that is to be used to create the Command (and later
33
+ # NotificationHandler) objects.
34
+ #
35
+ # === Example
36
+ #
37
+ # configuration = { :merchant_id => '123456789', :merchant_key => '12345abcd' }
38
+ #
39
+ # frontend = Google4R::Checkout::Frontend.new(configuration)
40
+ #
41
+ # == Tax Table Factory
42
+ #
43
+ # You have to set the tax_table_factory attribute of every Frontend object before you
44
+ # can call #create_checkout_command or #create_notification_handler because the
45
+ # objects created by those methods require tax tables.
46
+ #
47
+ # The Tax Table Factory must provide the method "effective_tax_tables_at" accept a Time
48
+ # object and provide a method that returns an Array of TaxTable object that describe the
49
+ # effective tax rules at the given point of time.
50
+ #
51
+ # Effectively, this means you have to implement the Temporal Property pattern as described
52
+ # here: http://www.martinfowler.com/ap2/temporalProperty.html.
53
+ #
54
+ # == Example
55
+ #
56
+ # class TaxTableFactory
57
+ # def effective_tax_tables_at(time)
58
+ # if time < Time.parse("Wed Apr 09 08:56:03 CDT 2003") then
59
+ # table1, table2 = TaxTable.new, TaxTable.new
60
+ # # ... set rules
61
+ # [ table1, table 2]
62
+ # else
63
+ # table3, table4 = TaxTable.new, TaxTable.new
64
+ # # ... set rules
65
+ # [ table3, table 4]
66
+ # end
67
+ # end
68
+ # end
69
+ #
70
+ # frontend = Google4R::Checkout::Frontend.new(configuration)
71
+ # frontend.tax_table_factory = TaxTableFactory.new
72
+ #
73
+ # checkout_command = frontent.create_checkout_command
74
+ # # ...
75
+ # handler = frontend.create_notification_handler
76
+ class Frontend
77
+ # The configuration for this Frontend class. It will be used by all classes created
78
+ # by this Frontend instance (Hash).
79
+ attr_reader :configuration
80
+
81
+ # An object with a factory method that can create the effective TaxTable objects
82
+ # that were valid at a given point of time.
83
+ attr_accessor :tax_table_factory
84
+
85
+ # Creates a new Frontend instance and sets the configuration attribute to the parameter
86
+ # configuration.
87
+ def initialize(configuration)
88
+ raise "Missing configuration setting: merchant_id" if configuration[:merchant_id].nil?
89
+ raise "Missing configuration setting: merchant_key" if configuration[:merchant_key].nil?
90
+ raise "Missing configuration setting: use_sandbox" if configuration[:use_sandbox].nil?
91
+
92
+ @configuration = configuration.dup.freeze
93
+ end
94
+
95
+ # Factory method that creates a new CheckoutCommand object. Use this method to create
96
+ # your CheckoutCommand instances.
97
+ def create_checkout_command
98
+ return CheckoutCommand.new(self)
99
+ end
100
+
101
+ # Factory method that creates a new NotificationHandler object. Use this method to
102
+ # create your NotificationHandler instances.
103
+ def create_notification_handler
104
+ return NotificationHandler.new(self)
105
+ end
106
+ end
107
+ end
108
+ end