google4r-checkout-jn 1.1.jniziol

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 (79) hide show
  1. data/CHANGES +136 -0
  2. data/LICENSE +22 -0
  3. data/README.md +72 -0
  4. data/lib/google4r/checkout.rb +34 -0
  5. data/lib/google4r/checkout/commands.rb +665 -0
  6. data/lib/google4r/checkout/frontend.rb +222 -0
  7. data/lib/google4r/checkout/merchant_calculation.rb +323 -0
  8. data/lib/google4r/checkout/notifications.rb +774 -0
  9. data/lib/google4r/checkout/shared.rb +1386 -0
  10. data/lib/google4r/checkout/utils.rb +94 -0
  11. data/lib/google4r/checkout/xml_generation.rb +1023 -0
  12. data/test/frontend_configuration_example.rb +13 -0
  13. data/test/integration/checkout_command_test.rb +261 -0
  14. data/test/test_helper.rb +105 -0
  15. data/test/unit/add_merchant_order_number_command_test.rb +65 -0
  16. data/test/unit/add_tracking_data_command_test.rb +68 -0
  17. data/test/unit/address_test.rb +131 -0
  18. data/test/unit/anonymous_address_test.rb +75 -0
  19. data/test/unit/archive_order_command_test.rb +63 -0
  20. data/test/unit/area_test.rb +44 -0
  21. data/test/unit/authorization_amount_notification_test.rb +69 -0
  22. data/test/unit/authorize_order_command_test.rb +63 -0
  23. data/test/unit/backorder_items_command_test.rb +69 -0
  24. data/test/unit/callback_handler_test.rb +83 -0
  25. data/test/unit/cancel_items_command_test.rb +76 -0
  26. data/test/unit/cancel_order_command_test.rb +74 -0
  27. data/test/unit/carrier_calculated_shipping_test.rb +57 -0
  28. data/test/unit/charge_amount_notification_test.rb +72 -0
  29. data/test/unit/charge_and_ship_order_command_test.rb +69 -0
  30. data/test/unit/charge_fee_test.rb +53 -0
  31. data/test/unit/charge_order_command_test.rb +69 -0
  32. data/test/unit/chargeback_amount_notification_test.rb +69 -0
  33. data/test/unit/checkout_command_test.rb +149 -0
  34. data/test/unit/checkout_command_xml_generator_test.rb +216 -0
  35. data/test/unit/command_test.rb +116 -0
  36. data/test/unit/deliver_order_command_test.rb +65 -0
  37. data/test/unit/delivery_method_test.rb +42 -0
  38. data/test/unit/digital_content_test.rb +105 -0
  39. data/test/unit/flat_rate_shipping_test.rb +133 -0
  40. data/test/unit/frontend_test.rb +144 -0
  41. data/test/unit/item_info_test.rb +69 -0
  42. data/test/unit/item_test.rb +171 -0
  43. data/test/unit/marketing_preferences_test.rb +65 -0
  44. data/test/unit/merchant_calculated_shipping_test.rb +173 -0
  45. data/test/unit/merchant_calculation_callback_test.rb +137 -0
  46. data/test/unit/merchant_calculation_result_test.rb +78 -0
  47. data/test/unit/merchant_calculation_results_test.rb +203 -0
  48. data/test/unit/merchant_code_result_test.rb +51 -0
  49. data/test/unit/merchant_code_test.rb +122 -0
  50. data/test/unit/new_order_notification_test.rb +115 -0
  51. data/test/unit/notification_acknowledgement_test.rb +67 -0
  52. data/test/unit/notification_handler_test.rb +113 -0
  53. data/test/unit/order_adjustment_test.rb +119 -0
  54. data/test/unit/order_report_command_test.rb +109 -0
  55. data/test/unit/order_state_change_notification_test.rb +158 -0
  56. data/test/unit/parameterized_url_test.rb +57 -0
  57. data/test/unit/pickup_shipping_test.rb +70 -0
  58. data/test/unit/postal_area_test.rb +71 -0
  59. data/test/unit/private_data_parser_test.rb +68 -0
  60. data/test/unit/refund_amount_notification_test.rb +67 -0
  61. data/test/unit/refund_order_command_test.rb +79 -0
  62. data/test/unit/reset_items_shipping_information_command_test.rb +69 -0
  63. data/test/unit/return_items_command_test.rb +69 -0
  64. data/test/unit/risk_information_notification_test.rb +98 -0
  65. data/test/unit/send_buyer_message_command_test.rb +68 -0
  66. data/test/unit/ship_items_command_test.rb +81 -0
  67. data/test/unit/shipping_adjustment_test.rb +100 -0
  68. data/test/unit/shopping_cart_test.rb +146 -0
  69. data/test/unit/tax_rule_test.rb +70 -0
  70. data/test/unit/tax_table_test.rb +88 -0
  71. data/test/unit/tracking_data_test.rb +54 -0
  72. data/test/unit/unarchive_order_command_test.rb +63 -0
  73. data/test/unit/url_parameter_test.rb +55 -0
  74. data/test/unit/us_country_area_test.rb +76 -0
  75. data/test/unit/us_state_area_test.rb +70 -0
  76. data/test/unit/us_zip_area_test.rb +66 -0
  77. data/test/unit/world_area_test.rb +48 -0
  78. data/var/cacert.pem +7815 -0
  79. metadata +230 -0
data/CHANGES ADDED
@@ -0,0 +1,136 @@
1
+ =google4r-checkout Changelog
2
+
3
+ == 1.1.beta5 (2010-09-21)
4
+
5
+ * Support for chargeback fees and chargeback gateway refund fees, contributed by George Palmer
6
+ * Test::Unit fixes for Ruby 1.9.2
7
+
8
+ == 1.1.beta4 (2010-07-09)
9
+
10
+ * All changes in this release contributed by George Palmer (thanks very much George!)
11
+ * Make the tax field optional as can be set at Google Account level
12
+ * Add a new command ChargeAndShipOrder (v2.5 of the API although we ended up going with 2.4 but it was fully tested and worked)
13
+ * Ability to get the refund amount available in RefundAmountNotification
14
+ * Ability to get gateway fee information
15
+
16
+ == 1.1.beta3 (2010-06-28)
17
+
18
+ * Add required test files to the gem build
19
+
20
+ == 1.1.beta2 (2010-06-23)
21
+
22
+ * Make gem compatible with Money 3.x (thanks George Palmer!)
23
+ * Use Bundler for running test suite
24
+
25
+ == 1.1.beta1 (2010-04-21)
26
+
27
+ * Full Ruby 1.9.x compatibility
28
+ * Major overhaul of automated test suite
29
+ * Support for merchant-calculated and allow-us-po-box tags
30
+ * Update to Money library version 2.3 (beware - this may break things if you expect the currency to be a string)
31
+ * Verify that we are actually talking to Google's servers when sending checkout commands
32
+ * Generated XML will no longer include extra whitespace, to help comply with Google's XML schema
33
+ * Use BigDecimal instead of Float for all calculations due to weird rounding errors in Ruby's standard library
34
+ * Fixed deprecation warnings
35
+
36
+ == 1.0.6.1 (2010-04-20)
37
+
38
+ * Fixed issue #14 - will not load on Ruby 1.9.x
39
+ * Added homepage URL to gem specification
40
+
41
+ == 1.0.6 (2010-04-01)
42
+
43
+ * Added beta Subscriptions API support.
44
+ * Fixed email-delivery XML generation bug.
45
+
46
+ == 1.0.5 (2008-9-17)
47
+
48
+ * Added Order Report API support. Thanks to Daniel Pirone!
49
+ * Added unit tests for OrderReportCommand. Added validation checks fro start_date, end_date, financial_state and fulfillment_state.
50
+
51
+ == 1.0.4 (2008-09-02)
52
+
53
+ * Fixed undefined email_delivery? method bug
54
+ * Added unit test to cover digital content creation
55
+
56
+ == 1.0.3 (2008-08-08)
57
+
58
+ * Added analytics_data support. Thanks to Will Schwenk!
59
+ * Added create_address_filters_allowed_area and create_address_filters_excluded_area method to the MerchantCalculatedShipping class.
60
+ * Created two aliases create_shipping_restrictions_allowed_area and create_shipping_restrictions_excluded_area to facilitate deprecation of create_allowed_area and create_excluded_area.
61
+ * country_code in PostalArea class is now optional in the initialize method so it can be called properly in the create_area method in shared.rb.
62
+ * Added line-item shipping support.
63
+ * Refactor notifications to extract a base notification class that has the front_end, serial_number, google_order_number and timestamp.
64
+ * Added notification handshake support (i.e. serial-number) for notifciation-acknowledgement.
65
+ * Added digital delivery support. Thanks to Andy Kim and Matthew Moore!
66
+ * Added Carrier Calculated Shipping support.
67
+ * Added unit tests - carrier_calculated_shipping_test.rb, digital_content_test.rb, *_items_*commands.rb
68
+ * Updated unit tests - item_test.rb, merchant_calculated_shipping_test.rb, notification_acknowledgement_test.rb
69
+ * Updated integration test - checkout_command_test.rb
70
+ * Added HTML Form API Signature support. It is included in utils.rb.
71
+
72
+ == 1.0.2 (2007-08-18)
73
+
74
+ * Moved Address from notifications.rb to shared.rb
75
+ * Added AnonymousAddress class, now Address is extended from it
76
+ * Added merchant calcuations callback and result support
77
+ * Added unit tests for merchant calculation callback and result
78
+ * Added merchant calculations tag support in Shopping Cart XML
79
+ * Updated checkout_command_test.rb and checkout_command_xml_generator_test.rb after for testing merchant calculations tag support
80
+
81
+ == 1.0.1 (2007-08-16)
82
+
83
+ * Fixed text.to_s.gsub(/[^0-9]/, '') to (...text.to_f*100).to_i so dollar amount is now handled correctly
84
+
85
+ == 1.0.0 (2007-08-04)
86
+
87
+ * Added refund-amount-notification
88
+ * Added chargeback-amount-notification
89
+ * Added authorization-amount-notification
90
+ * Added refund command
91
+ * Added authorize command
92
+ * Added add-merchant-number command
93
+ * Added add-tracking-data command
94
+ * Added send-buyer-message command
95
+ * Added archive-order command
96
+ * Added unarchive-order command
97
+ * Refactored to_xml in the Command class
98
+ * Added CommandXmlGenerator base class
99
+ * Added ChargeOrderCommand, DeliverOrderCommand, CancelOrderCommand, ChargeAmountNotification and RiskInfoNotification (all contributed by Dan Dukeson).
100
+ * Attributes are not retrieved via XPaths with "tag/@attribute" any more but with REXML's Element#attributes. This should fix problems with Ruby 1.8.6.
101
+
102
+ == 0.1.0 (2007-05-12)
103
+ * Added property "shipping_taxed" to TaxRule (contributed by Dan Dukeson).
104
+ * Added XML generation for the tax tables in the shopping cart (contributed by Dan Dukeson).
105
+ * Added Area subclasses WorldArea and PostalArea (contributed by Dan Dukeson).
106
+ * Changed time zones in tests to UTC.
107
+ * Added Test::Unit::TestCase#assert_strings_equal to test_helper.rb.
108
+ * Added "rake test" (alias of "rake test:all")
109
+ * Added GoogleCheckoutError#to_s to return verbose representation.
110
+ * Split google4r into google4r-checkout and google4r-maps.
111
+ * MerchantCode#create_from_element raises an ArgumentError instead of a RuntimeError on invalid elements now.
112
+ * Changed the #create_from_element code to set the properties directly into the objects instead of building Hashes to collect the values first.
113
+ * "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.
114
+ * Added example to NotificationHandler of how to use the class.
115
+ * Added link to simple_http_auth plugin in NotificationHandler which allows for easy HTTP Auth Basic protection of Rails controllers.
116
+ * Renamed CheckoutCommand#cart to CheckoutCommand#shopping_cart
117
+ * CheckoutCommand raises ArgumentError instead of RuntimeError on invalid clazz parameter.
118
+ * Added "Howto freeze google4r in a Rails project" to README
119
+ * Google4R::Checkout::Command#to_xml raises an NotImplementedError instead of a RuntimeError now.
120
+ * Geocoder returns nil on 603 (G_UNAVAILABLE_ADDRESS) results now.
121
+ * Added support for registering GUnload() to be called on window's unload event.
122
+ * 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.
123
+ * Using Syck as the YAML parser now. However, a workaround is needed because of http://code.whytheluckystiff.net/syck/ticket/27.
124
+ * 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.
125
+ * Added GMarker#info_window_html.
126
+ * Added support for onclick handlers in markers.
127
+ * Added support for the value :auto of GMap2#zoom and GMap2#center.
128
+ * Fixed buggy generation of GMarker Javascript.
129
+ * Adding website folder to contain a webgen based website.
130
+ * Fixed a problem with generating XML from Hashes in the "private" data of shopping carts and items.
131
+ * The parse for the <order-adjustment> tag does not expect to see a <shipping> tag in every case any more.
132
+ * Extending Google4R::Maps by the classes GMap2, GIcon and GMarker to allow for easy Google Maps HTML generation.
133
+
134
+ == 0.0.1 (2007-02-17)
135
+
136
+ * 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.
@@ -0,0 +1,72 @@
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
+ ### Installing
12
+
13
+ Gems are hosted on rubygems.org (aka Gemcutter), so on reasonably recent versions of Rubygems, you should be able to install just like this:
14
+
15
+ gem install google4r-checkout
16
+
17
+ Or, go to [our page on rubygems.org](http://rubygems.org/gems/google4r-checkout).
18
+
19
+ ### Issue Tracking and Wiki
20
+
21
+ Our issue tracker and wiki can be found [on Google Code](http://code.google.com/p/google-checkout-ruby-sample-code/). The best way to let us know about bugs or feature requests is to report an issue there.
22
+
23
+ ### Documentation
24
+
25
+ We've got RDoc documentation for the google4r-checkout library [generated on rdoc.info](http://rdoc.info/projects/nbudin/google4r-checkout).
26
+
27
+ 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.
28
+
29
+ ## Google Checkout Tests
30
+
31
+ 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.
32
+
33
+ The file should contain content similar to:
34
+
35
+ # Uncomment the following line if you are using Google Checkout in Great Britain
36
+ # and adjust it if you want to test google4r-checkout against any other (future)
37
+ # Google Checkout service.
38
+
39
+ # Money.default_currency = 'GBP'
40
+
41
+ # The test configuration for the Google4R::Checkout::Frontend class.
42
+ FRONTEND_CONFIGURATION =
43
+ {
44
+ :merchant_id => '<your merchant id>',
45
+ :merchant_key => '<your merchant key>',
46
+ :use_sandbox => true
47
+ }
48
+
49
+ ## Dependencies
50
+
51
+ 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.
52
+
53
+ ## How To: Freeze a google4r version in a Rails project
54
+
55
+ <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:
56
+
57
+ cd RAILS_ROOT
58
+ cd vendor
59
+ gem unpack google4r-checkout
60
+ ls
61
+ # ... google4r-checkout-0.1.1 ...
62
+
63
+ 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>:
64
+
65
+ # Freeze non-Rails gem.
66
+ Dir.glob(File.join(RAILS_ROOT, 'vendor', '*', 'lib')) do |path|
67
+ $LOAD_PATH << path
68
+ end
69
+
70
+ Now you can use the following in your own code:
71
+
72
+ require 'google4r/checkout'
@@ -0,0 +1,34 @@
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'
34
+ require 'google4r/checkout/merchant_calculation'
@@ -0,0 +1,665 @@
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
+ SANDBOX_URL_PREFIX = 'https://sandbox.google.com/checkout/'
44
+
45
+ # The URL to use for real requests to the Google Checkout API. The merchant id
46
+ # is to be put in via String#%.
47
+ PRODUCTION_URL_PREFIX = 'https://checkout.google.com/'
48
+
49
+ CHECKOUT_API_URL = 'api/checkout/v2/merchantCheckout/Merchant/%s'
50
+
51
+ ORDER_PROCESSING_API_URL = 'api/checkout/v2/request/Merchant/%s'
52
+
53
+ ORDER_REPORT_API_URL = 'api/checkout/v2/reports/Merchant/%s'
54
+
55
+
56
+ # The Frontent class that was used to create this CheckoutCommand and whose
57
+ # configuration will be used.
58
+ attr_reader :frontend
59
+
60
+ # The tag name of the command
61
+ attr_reader :command_tag_name
62
+
63
+ # The google order number, required, String
64
+ attr_accessor :google_order_number
65
+
66
+ # Initialize the frontend attribute with the value of the frontend parameter.
67
+ def initialize(frontend)
68
+ if self.instance_of?(Command) || self.instance_of?(ItemsCommand)
69
+ raise 'Cannot instantiate abstract class ' + self.class.to_s
70
+ end
71
+ @frontend = frontend
72
+ end
73
+
74
+ # Sends the cart's XML to GoogleCheckout via HTTPs with Basic Auth.
75
+ #
76
+ # Raises an OpenSSL::SSL::SSLError when the SSL certificate verification failed.
77
+ #
78
+ # Raises a GoogleCheckoutError when Google returns an error.
79
+ #
80
+ # Raises a RuntimeException on unknown responses.
81
+ #--
82
+ # TODO: The send-and-expect-response part should be adaptable to other commands and responses.
83
+ #++
84
+ def send_to_google_checkout
85
+ xml_response = (self.class == OrderReportCommand) ? false : true
86
+ # Create HTTP(S) POST command and set up Basic Authentication.
87
+ url_str =
88
+ if frontend.configuration[:use_sandbox] then
89
+ SANDBOX_URL_PREFIX
90
+ else
91
+ PRODUCTION_URL_PREFIX
92
+ end
93
+ url_str +=
94
+ if self.class == CheckoutCommand then
95
+ CHECKOUT_API_URL
96
+ elsif self.class == OrderReportCommand then
97
+ ORDER_REPORT_API_URL
98
+ else
99
+ ORDER_PROCESSING_API_URL
100
+ end
101
+ url_str = url_str % frontend.configuration[:merchant_id]
102
+ url = URI.parse(url_str)
103
+
104
+ request = Net::HTTP::Post.new(url.path)
105
+ request.basic_auth(frontend.configuration[:merchant_id], frontend.configuration[:merchant_key])
106
+
107
+ # Set up the HTTP connection object and the SSL layer.
108
+ https = Net::HTTP.new(url.host, url.port)
109
+ https.use_ssl = true
110
+ https.cert_store = self.class.x509_store
111
+ https.verify_mode = OpenSSL::SSL::VERIFY_PEER
112
+ https.verify_depth = 5
113
+ https.verify_callback = Proc.new do |ok, ctx|
114
+ domain = ctx.chain.first.subject.to_a.select { |part| part.first == "CN" }.first[1]
115
+
116
+ domain == if frontend.configuration[:use_sandbox]
117
+ "sandbox.google.com"
118
+ else
119
+ "checkout.google.com"
120
+ end
121
+ end
122
+
123
+ # Send the request to Google.
124
+ result = https.request(request, self.to_xml)
125
+
126
+ case result
127
+ when Net::HTTPSuccess then
128
+ if ( xml_response ) then
129
+ xml_doc = REXML::Document.new(result.body)
130
+
131
+ case xml_doc.root.name
132
+ when 'checkout-redirect'
133
+ serial_number = xml_doc.elements['/checkout-redirect'].attributes['serial-number']
134
+ redirect_url = xml_doc.elements['/checkout-redirect/redirect-url/text()'].value
135
+ return CheckoutRedirectResponse.new(serial_number, redirect_url)
136
+ when 'request-received'
137
+ serial_number = xml_doc.elements['/request-received'].attributes['serial-number']
138
+ return serial_number
139
+ else
140
+ raise "Unknown response:\n--\n#{xml_doc.to_s}\n--"
141
+ end
142
+ else
143
+ # handle the CSV output of the order-report-list command
144
+ return result.body
145
+ end
146
+ when Net::HTTPClientError then
147
+ xml_doc = REXML::Document.new(result.body)
148
+
149
+ if xml_doc.elements['/error'].attributes['serial-number'].nil? or xml_doc.elements['/error/error-message/text()'].nil? then
150
+ raise "Invalid response from Google:\n---\n#{result.body}\n---"
151
+ end
152
+
153
+ hash =
154
+ {
155
+ :serial_number => xml_doc.elements['/error'].attributes['serial-number'],
156
+ :message => xml_doc.elements['/error/error-message/text()'].value
157
+ }
158
+
159
+ raise GoogleCheckoutError.new(hash)
160
+ when Net::HTTPRedirection, Net::HTTPServerError, Net::HTTPInformation then
161
+ raise "Unexpected reponse code (#{result.class}): #{result.code} - #{result.message}"
162
+ else
163
+ raise "Unknown reponse code: #{result.code} - #{result.message}"
164
+ end
165
+ end
166
+
167
+ # Class method to return the command's XML representation.
168
+ def to_xml
169
+ generator_class = Google4R::Command.get_const("#{self.class}XmlGenerator")
170
+ return generator_class.new(self).generate
171
+ end
172
+
173
+ protected
174
+
175
+ # Class method to return the OpenSSL::X509::Store instance for the
176
+ # CA certificates.
177
+ #--
178
+ # TODO: Is OpenSSL::X509::Store thread safe when reading only? This method most certainly is *not*. It must become so.
179
+ #++
180
+ def self.x509_store
181
+ return @@x509_store if defined?(@@x509_store)
182
+
183
+ cacert_path = File.expand_path(File.dirname(__FILE__) + '/../../../var/cacert.pem')
184
+
185
+ @@x509_store = OpenSSL::X509::Store.new
186
+ @@x509_store.add_file(cacert_path)
187
+
188
+ return @@x509_store
189
+ end
190
+ end
191
+
192
+ # The CheckoutCommand represents a <checkout-shopping-cart> command sent
193
+ # to the server.
194
+ #
195
+ # A CheckoutCommand instance can have an arbitrary number of TaxTable
196
+ # and ShippingMethod instances. You must create these instances using the
197
+ # create_* methods which CheckoutCommand supplies.
198
+ #
199
+ # CheckoutCommand#send_to_google_checkout returns CheckoutRedirectResponse
200
+ # instances.
201
+ #
202
+ # Use the Frontend class to create new CheckoutCommand instances and do not
203
+ # instanciate the class directly.
204
+ #
205
+ # Note that you have to create/set the tax tables for CheckoutCommands before you
206
+ # can add any items to the cart that define a tax table.
207
+ #
208
+ # === Example
209
+ #
210
+ # frontend = Google4R::Checkout::Frontend.new(configuration)
211
+ # frontend.tax_table_factory = TaxTableFactory.new
212
+ # command = frontend.create_checkout_command
213
+ class CheckoutCommand < Command
214
+ # The ShoppingCart of this CheckoutCommand.
215
+ attr_reader :shopping_cart
216
+
217
+ # An array of the TaxTable objects of this CheckoutCommand. They have been
218
+ # created with the tax table factory of the frontend which created this
219
+ # command.
220
+ attr_reader :tax_tables
221
+
222
+ # An array of ShippingMethod objects of this CheckoutCommand. Use
223
+ # #create_shipping_method to create new shipping methods.
224
+ attr_reader :shipping_methods
225
+
226
+ attr_reader :parameterized_urls
227
+
228
+ # The URL at where the cart can be edited (String, optional).
229
+ attr_accessor :edit_cart_url
230
+
231
+ # The URL to continue shopping after completing the checkout (String, optional).
232
+ attr_accessor :continue_shopping_url
233
+
234
+ # A boolean flag; true iff the customer HAS to provide his phone number (optional).
235
+ attr_accessor :request_buyer_phone_number
236
+
237
+ # The URL of the merchant calculation callback (optional).
238
+ attr_accessor :merchant_calculations_url
239
+
240
+ # A boolean flag to indicate whether merchant coupon is supported or not (optional).
241
+ attr_accessor :accept_merchant_coupons
242
+
243
+ # A boolean flag to indicate whether gift certificate is supported or not (optional).
244
+ attr_accessor :accept_gift_certificates
245
+
246
+ # A Google Checkout merchant ID that identifies the eCommerce provider.
247
+ attr_accessor :platform_id
248
+
249
+ # Setting this allows Google Analytics to track purchases that use Checkout
250
+ # The value should be as set by the analytics javascript in the hidden form
251
+ # element names "analyticsdata" on the page with the checkout button.
252
+ # If left unset then the element will not be generated.
253
+ # see: http://code.google.com/apis/checkout/developer/checkout_analytics_integration.html
254
+ attr_accessor :analytics_data
255
+
256
+ # Generates the XML for this CheckoutCommand.
257
+ def to_xml
258
+ CheckoutCommandXmlGenerator.new(self).generate
259
+ end
260
+
261
+ # Initialize a new CheckoutCommand with a fresh CheckoutCart and an empty
262
+ # Array of tax tables and an empty array of ShippingMethod instances.
263
+ # Do not use this method directly but use Frontent#create_checkout_command
264
+ # to create CheckoutCommand objects.
265
+ def initialize(frontend)
266
+ super(frontend)
267
+ @shopping_cart = ShoppingCart.new(self)
268
+ @shipping_methods = Array.new
269
+ @parameterized_urls = Array.new
270
+ if frontend.tax_table_factory
271
+ @tax_tables = frontend.tax_table_factory.effective_tax_tables_at(Time.new)
272
+ end
273
+ end
274
+
275
+ # Use this method to create a new shipping method. You have to pass in one of
276
+ # { PickupShipping, FlatRateShipping } for clazz. The method will create a
277
+ # new instance of the class you passedin object and add it to the internal list
278
+ # of shipping methods.
279
+ #
280
+ # If you pass a block to this method (preferred) then the newly created
281
+ # ShippingMethod object will be passed into this block for setting its attributes.
282
+ # The newly created shipping method will be returned in all cases.
283
+ #
284
+ # The first created shipping method will be used as the default.
285
+ #
286
+ # Raises a ArgumentError if the parameter clazz is invalid.
287
+ def create_shipping_method(clazz, &block)
288
+ if not [ PickupShipping, FlatRateShipping,
289
+ MerchantCalculatedShipping, CarrierCalculatedShipping
290
+ ].include?(clazz) then
291
+ raise ArgumentError, "Unknown shipping method: #{clazz.inspect}."
292
+ end
293
+
294
+ shipping_method = clazz.new
295
+ @shipping_methods << shipping_method
296
+
297
+ yield(shipping_method) if block_given?
298
+
299
+ return shipping_method
300
+ end
301
+
302
+ # Use this method to create a new parameterized_url object. It requires the URL
303
+ # to be passed in the 'opts' hash. It will create a new instance of the
304
+ # paramterized URL object.
305
+ #
306
+ # Raises an argument error if the URL passed in the opts hash is not a String
307
+ #
308
+ # To find more information on 3rd party conversion tracking visit the API documentation
309
+ # http://code.google.com/apis/checkout/developer/checkout_pixel_tracking.html
310
+ def create_parameterized_url(opts, &block)
311
+ raise(ArgumentError, "Url option required") unless opts[:url].kind_of?(String)
312
+
313
+ parameterized_url = ParameterizedUrl.new(opts[:url])
314
+ @parameterized_urls << parameterized_url
315
+
316
+ yield(parameterized_url) if block_given?
317
+
318
+ return parameterized_url
319
+ end
320
+
321
+ end
322
+
323
+ # CheckoutRedirectResponse instances are returned when a CheckoutCommand is successfully
324
+ # processed by Google Checkout.
325
+ class CheckoutRedirectResponse
326
+ # The serial number of the <checkout-redirect> response.
327
+ attr_reader :serial_number
328
+
329
+ # The URL to redirect to.
330
+ attr_reader :redirect_url
331
+
332
+ # Create a new CheckoutRedirectResponse with the given serial number and redirection URL.
333
+ # Do not create CheckoutRedirectResponse instances in your own code. Google4R creates them
334
+ # for you.
335
+ def initialize(serial_number, redirect_url)
336
+ @serial_number = serial_number
337
+ @redirect_url = redirect_url
338
+ end
339
+
340
+ def to_s
341
+ return @redirect_url
342
+ end
343
+ end
344
+
345
+ # SubscriptionRequestReceivedResponse instances are returned when a
346
+ # CreateOrderRecurrenceRequestCommand is successfully processed by Google Checkout.
347
+ class SubscriptionRequestReceivedResponse
348
+ # The serial number of the <subscription-request-received> response.
349
+ attr_reader :serial_number
350
+
351
+ # The new order number that was generated for this request.
352
+ attr_reader :new_google_order_number
353
+
354
+ # Create a new SubscriptionRequestReceivedResponse with the given serial number and Google
355
+ # order number. Do not create SubscriptionRequestReceivedResponse instances in your own
356
+ # code. Google4R creates them for you.
357
+ def initialize(serial_number, new_google_order_number)
358
+ @serial_number = serial_number
359
+ @new_google_order_number = new_google_order_number
360
+ end
361
+
362
+ def to_s
363
+ return @new_google_order_number
364
+ end
365
+ end
366
+
367
+ #
368
+ # The ChargeOrderCommand instructs Google Checkout to charge the buyer for a
369
+ # particular order.
370
+ #
371
+ class ChargeOrderCommand < Command
372
+ # The amount to charge, optional, Money
373
+ attr_accessor :amount
374
+
375
+ # Generates the XML for this ChargeOrderCommand
376
+ def to_xml
377
+ ChargeOrderCommandXmlGenerator.new(self).generate
378
+ end
379
+ end
380
+
381
+ class ChargeAndShipOrderCommand < Command
382
+ # The amount to charge, optional, Money
383
+ attr_accessor :amount
384
+
385
+ # if google checkout should email buyer to ssay order is dispatched
386
+ attr_accessor :send_email
387
+
388
+ # The name of the company responsible for shipping the item. Valid values
389
+ # for this tag are DHL, FedEx, UPS, USPS and Other.
390
+ attr_accessor :carrier
391
+
392
+ # The shipper's tracking number that is associated with an order
393
+ attr_accessor :tracking_number
394
+
395
+ # Generates the XML for this ChargeOrderCommand
396
+ def to_xml
397
+ ChargeAndShipOrderCommandXmlGenerator.new(self).generate
398
+ end
399
+ end
400
+
401
+ # The RefundOrderCommand instructs Google Checkout to refund an order
402
+ class RefundOrderCommand < Command
403
+ # The amount to refund, optional, Money
404
+ attr_accessor :amount
405
+
406
+ # The reason that the order is to be refunded, String of maximum 140 characters, required
407
+ attr_accessor :reason
408
+
409
+ # A comment related to the refunded order, String of maximum 140 characters, optional
410
+ attr_accessor :comment
411
+
412
+ def to_xml
413
+ RefundOrderCommandXmlGenerator.new(self).generate
414
+ end
415
+ end
416
+
417
+ # The CancelOrderCommand instructs Google Checkout to cancel an order
418
+ class CancelOrderCommand < Command
419
+ # The reason that the order is to be cancelled, String of maximum 140 characters, required
420
+ attr_accessor :reason
421
+
422
+ # A comment related to the cancelled order, String of maximum 140 characters, optional
423
+ attr_accessor :comment
424
+
425
+ def to_xml
426
+ CancelOrderCommandXmlGenerator.new(self).generate
427
+ end
428
+ end
429
+
430
+ # The AuthorizeOrderCommand instructs Google Checkout to explicitly reauthorize
431
+ # a customer's credit card for the uncharged balance of an order to verify that
432
+ # funds for the order are available
433
+ class AuthorizeOrderCommand < Command
434
+ def to_xml
435
+ AuthorizeOrderCommandXmlGenerator.new(self).generate
436
+ end
437
+ end
438
+
439
+ # The ProcessOrderCommand instructs Google Checkout to to update
440
+ # an order's fulfillment state from NEW to PROCESSING
441
+ class ProcessOrderCommand < Command
442
+ def to_xml
443
+ ProcessOrderCommandXmlGenerator.new(self).generate
444
+ end
445
+ end
446
+
447
+ # The AddMerchantOrderCommand instructs Google Checkout to associate a
448
+ # merchant-assigned order number with an order
449
+ class AddMerchantOrderNumberCommand < Command
450
+ # The merchant-assigned order number associated with an order
451
+ attr_accessor :merchant_order_number
452
+
453
+ def to_xml
454
+ AddMerchantOrderNumberCommandXmlGenerator.new(self).generate
455
+ end
456
+ end
457
+
458
+ # The DeliverOrderCommand indicates that Google should update an order's fulfillment order state to DELIVERED
459
+ class DeliverOrderCommand < Command
460
+ # if google checkout should email buyer to ssay order is dispatched
461
+ attr_accessor :send_email
462
+
463
+ # The name of the company responsible for shipping the item. Valid values
464
+ # for this tag are DHL, FedEx, UPS, USPS and Other.
465
+ attr_accessor :carrier
466
+
467
+ # The shipper's tracking number that is associated with an order
468
+ attr_accessor :tracking_number
469
+
470
+ def to_xml
471
+ DeliverOrderCommandXmlGenerator.new(self).generate
472
+ end
473
+ end
474
+
475
+ # The AddTrackingDataCommand instructs Google Checkout to associate a shipper's tracking number with an order.
476
+ class AddTrackingDataCommand < Command
477
+ # The name of the company responsible for shipping the item. Valid values
478
+ # for this tag are DHL, FedEx, UPS, USPS and Other.
479
+ attr_accessor :carrier
480
+
481
+ # The shipper's tracking number that is associated with an order
482
+ attr_accessor :tracking_number
483
+
484
+ def to_xml
485
+ AddTrackingDataCommandXmlGenerator.new(self).generate
486
+ end
487
+ end
488
+
489
+ # The SendBuyerMessageCommand instructs Google Checkout to place a message in the customer's Google Checkout account.
490
+ class SendBuyerMessageCommand < Command
491
+ # The message to the customer
492
+ attr_accessor :message
493
+
494
+ # if google checkout should email buyer to say order is dispatched
495
+ attr_accessor :send_email
496
+
497
+ def to_xml
498
+ SendBuyerMessageCommandXmlGenerator.new(self).generate
499
+ end
500
+ end
501
+
502
+ # The ArchiveOrderCommand instructs Google Checkout to remove an order from your Merchant Center Inbox.
503
+ class ArchiveOrderCommand < Command
504
+ def to_xml
505
+ ArchiveOrderCommandXmlGenerator.new(self).generate
506
+ end
507
+ end
508
+
509
+ # The UnarchiveOrderCommand instructs Google Checkout to return a previously archived order to your Merchant Center Inbox.
510
+ class UnarchiveOrderCommand < Command
511
+ def to_xml
512
+ UnarchiveOrderCommandXmlGenerator.new(self).generate
513
+ end
514
+ end
515
+
516
+ # The <create-order-recurrence-request> tag contains a request to charge a customer for one or more items in a subscription.
517
+ class CreateOrderRecurrenceRequestCommand < Command
518
+ # The ID that uniquely identifies this order
519
+ attr_accessor :google_order_number
520
+
521
+ attr_reader :shopping_cart
522
+
523
+ # Initialize a new CreateOrderRecurrenceRequestCommand with a fresh ShoppingCart.
524
+ def initialize(frontend)
525
+ super(frontend)
526
+ @shopping_cart = ShoppingCart.new(self)
527
+ end
528
+
529
+ def to_xml
530
+ CreateOrderRecurrenceRequestCommandXmlGenerator.new(self).generate
531
+ end
532
+ end
533
+
534
+ #
535
+ # XML API Commands for Line-item Shipping
536
+ #
537
+
538
+ # Abstract class for Line-item shipping commands
539
+ class ItemsCommand < Command
540
+ # An array of ItemInfo objects that you are marking as backordered,
541
+ # cancelled, returned or resetting shipping information
542
+ attr_accessor :item_info_arr
543
+
544
+ # if google checkout should email buyer to say order is dispatched
545
+ attr_accessor :send_email
546
+
547
+ def initialize(frontend)
548
+ super
549
+ @item_info_arr = []
550
+ @send_email = false
551
+ end
552
+ end
553
+
554
+ # The <ship-items> command specifies shipping information for one or
555
+ # more items in an order.
556
+ class ShipItemsCommand < ItemsCommand
557
+ def to_xml
558
+ ShipItemsCommandXmlGenerator.new(self).generate
559
+ end
560
+ end
561
+
562
+ # The <backorder-items> command lets you specify that one or more
563
+ # specific items in an order are out of stock.
564
+ class BackorderItemsCommand < ItemsCommand
565
+ def to_xml
566
+ BackorderItemsCommandXmlGenerator.new(self).generate
567
+ end
568
+ end
569
+
570
+ # The <cancel-items> command lets you specify that one or more
571
+ # specific items in an order have been cancelled, meaning they
572
+ # will not be delivered to the customer.
573
+ class CancelItemsCommand < ItemsCommand
574
+ # The reason that you are canceling one or more line items
575
+ attr_accessor :reason
576
+
577
+ # An optional comment related to one or more canceled line items
578
+ attr_accessor :comment
579
+
580
+ def to_xml
581
+ CancelItemsCommandXmlGenerator.new(self).generate
582
+ end
583
+ end
584
+
585
+ # The <return-items> command lets you specify that your customer
586
+ # returned one or more specific items in an order.
587
+ class ReturnItemsCommand < ItemsCommand
588
+ def to_xml
589
+ ReturnItemsCommandXmlGenerator.new(self).generate
590
+ end
591
+ end
592
+
593
+ # The <reset-items-shipping-information> command allows you to reset
594
+ # the shipping status for specific items in an order to "Not yet shipped".
595
+ class ResetItemsShippingInformationCommand < ItemsCommand
596
+ def to_xml
597
+ ResetItemsShippingInformationCommandXmlGenerator.new(self).generate
598
+ end
599
+ end
600
+
601
+ # The <order-list-request> command lets you to download a list of
602
+ # Google Checkout orders into a comma-separated file.
603
+ # The API will return a list of orders for a period of up to 31 days,
604
+ # and you can limit results to orders that have specific financial or
605
+ # fulfillment order states.
606
+ # http://code.google.com/apis/checkout/developer/Google_Checkout_XML_API_Order_Report_API.html
607
+ class OrderReportCommand < Command
608
+ # The earliest time that an order could have been submitted to be
609
+ # included in the API response (Time)
610
+ attr_reader :start_date
611
+
612
+ # The time before which an order must have been sent to be included
613
+ # in the API response (Time)
614
+ attr_reader :end_date
615
+
616
+ # The financial status of an order
617
+ attr_accessor :financial_state
618
+
619
+ # The fulfillment status of an order
620
+ attr_accessor :fulfillment_state
621
+
622
+ # The time zone that will be associated with the start date and
623
+ # end date for the report
624
+ attr_accessor :date_time_zone
625
+
626
+ def initialize(frontend, start_date, end_date)
627
+ super frontend
628
+ raise 'start_date has to be of type Time' unless start_date.class == Time
629
+ raise 'end_date has to be of type Time' unless start_date.class == Time
630
+ raise 'end_date has to be before start_date' unless
631
+ end_date >= start_date
632
+ @start_date = start_date
633
+ @end_date = end_date
634
+ end
635
+
636
+ def start_date
637
+ return @start_date.strftime('%Y-%m-%dT%H:%M:%S')
638
+ end
639
+
640
+ def end_date
641
+ return @end_date.strftime('%Y-%m-%dT%H:%M:%S')
642
+ end
643
+
644
+ def financial_state=(financial_state)
645
+ financial_state_name = financial_state.to_s
646
+
647
+ raise 'Invalid financial state %s' % financial_state unless
648
+ FinancialState.constants.any? { |state_name| state_name.to_s == financial_state_name }
649
+ @financial_state = financial_state_name
650
+ end
651
+
652
+ def fulfillment_state=(fulfillment_state)
653
+ fulfillment_state_name = fulfillment_state.to_s
654
+
655
+ raise 'Invalid fulfillment state %s' % fulfillment_state unless
656
+ FulfillmentState.constants.any? { |state_name| state_name.to_s == fulfillment_state_name }
657
+ @fulfillment_state = fulfillment_state_name
658
+ end
659
+
660
+ def to_xml
661
+ ReturnOrderReportCommandXmlGenerator.new(self).generate
662
+ end
663
+ end
664
+ end
665
+ end