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.
- data/CHANGES +136 -0
- data/LICENSE +22 -0
- data/README.md +72 -0
- data/lib/google4r/checkout.rb +34 -0
- data/lib/google4r/checkout/commands.rb +665 -0
- data/lib/google4r/checkout/frontend.rb +222 -0
- data/lib/google4r/checkout/merchant_calculation.rb +323 -0
- data/lib/google4r/checkout/notifications.rb +774 -0
- data/lib/google4r/checkout/shared.rb +1386 -0
- data/lib/google4r/checkout/utils.rb +94 -0
- data/lib/google4r/checkout/xml_generation.rb +1023 -0
- data/test/frontend_configuration_example.rb +13 -0
- data/test/integration/checkout_command_test.rb +261 -0
- data/test/test_helper.rb +105 -0
- data/test/unit/add_merchant_order_number_command_test.rb +65 -0
- data/test/unit/add_tracking_data_command_test.rb +68 -0
- data/test/unit/address_test.rb +131 -0
- data/test/unit/anonymous_address_test.rb +75 -0
- data/test/unit/archive_order_command_test.rb +63 -0
- data/test/unit/area_test.rb +44 -0
- data/test/unit/authorization_amount_notification_test.rb +69 -0
- data/test/unit/authorize_order_command_test.rb +63 -0
- data/test/unit/backorder_items_command_test.rb +69 -0
- data/test/unit/callback_handler_test.rb +83 -0
- data/test/unit/cancel_items_command_test.rb +76 -0
- data/test/unit/cancel_order_command_test.rb +74 -0
- data/test/unit/carrier_calculated_shipping_test.rb +57 -0
- data/test/unit/charge_amount_notification_test.rb +72 -0
- data/test/unit/charge_and_ship_order_command_test.rb +69 -0
- data/test/unit/charge_fee_test.rb +53 -0
- data/test/unit/charge_order_command_test.rb +69 -0
- data/test/unit/chargeback_amount_notification_test.rb +69 -0
- data/test/unit/checkout_command_test.rb +149 -0
- data/test/unit/checkout_command_xml_generator_test.rb +216 -0
- data/test/unit/command_test.rb +116 -0
- data/test/unit/deliver_order_command_test.rb +65 -0
- data/test/unit/delivery_method_test.rb +42 -0
- data/test/unit/digital_content_test.rb +105 -0
- data/test/unit/flat_rate_shipping_test.rb +133 -0
- data/test/unit/frontend_test.rb +144 -0
- data/test/unit/item_info_test.rb +69 -0
- data/test/unit/item_test.rb +171 -0
- data/test/unit/marketing_preferences_test.rb +65 -0
- data/test/unit/merchant_calculated_shipping_test.rb +173 -0
- data/test/unit/merchant_calculation_callback_test.rb +137 -0
- data/test/unit/merchant_calculation_result_test.rb +78 -0
- data/test/unit/merchant_calculation_results_test.rb +203 -0
- data/test/unit/merchant_code_result_test.rb +51 -0
- data/test/unit/merchant_code_test.rb +122 -0
- data/test/unit/new_order_notification_test.rb +115 -0
- data/test/unit/notification_acknowledgement_test.rb +67 -0
- data/test/unit/notification_handler_test.rb +113 -0
- data/test/unit/order_adjustment_test.rb +119 -0
- data/test/unit/order_report_command_test.rb +109 -0
- data/test/unit/order_state_change_notification_test.rb +158 -0
- data/test/unit/parameterized_url_test.rb +57 -0
- data/test/unit/pickup_shipping_test.rb +70 -0
- data/test/unit/postal_area_test.rb +71 -0
- data/test/unit/private_data_parser_test.rb +68 -0
- data/test/unit/refund_amount_notification_test.rb +67 -0
- data/test/unit/refund_order_command_test.rb +79 -0
- data/test/unit/reset_items_shipping_information_command_test.rb +69 -0
- data/test/unit/return_items_command_test.rb +69 -0
- data/test/unit/risk_information_notification_test.rb +98 -0
- data/test/unit/send_buyer_message_command_test.rb +68 -0
- data/test/unit/ship_items_command_test.rb +81 -0
- data/test/unit/shipping_adjustment_test.rb +100 -0
- data/test/unit/shopping_cart_test.rb +146 -0
- data/test/unit/tax_rule_test.rb +70 -0
- data/test/unit/tax_table_test.rb +88 -0
- data/test/unit/tracking_data_test.rb +54 -0
- data/test/unit/unarchive_order_command_test.rb +63 -0
- data/test/unit/url_parameter_test.rb +55 -0
- data/test/unit/us_country_area_test.rb +76 -0
- data/test/unit/us_state_area_test.rb +70 -0
- data/test/unit/us_zip_area_test.rb +66 -0
- data/test/unit/world_area_test.rb +48 -0
- data/var/cacert.pem +7815 -0
- metadata +230 -0
@@ -0,0 +1,94 @@
|
|
1
|
+
#--
|
2
|
+
# Project: google4r
|
3
|
+
# File: lib/google4r/checkout/utils.rb
|
4
|
+
# Author: Tony Chan <api.htchan@gmail.com>
|
5
|
+
# Copyright: (c) 2007 by Tony Chan
|
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 'cgi'
|
31
|
+
require 'openssl'
|
32
|
+
require 'base64'
|
33
|
+
|
34
|
+
module Google4R #:nodoc:
|
35
|
+
module Checkout #:nodoc:
|
36
|
+
# HTML Signing
|
37
|
+
#
|
38
|
+
# Args:
|
39
|
+
# - params -- html form parameters
|
40
|
+
# - merchant_key -- Google Checkout merchant key
|
41
|
+
#
|
42
|
+
# Returns:
|
43
|
+
# - signature -- The base-64 encoded result of hashing the serialized
|
44
|
+
# parameters with the merchant key
|
45
|
+
#
|
46
|
+
# Example
|
47
|
+
# -------
|
48
|
+
# require 'google4r/checkout/utils'
|
49
|
+
#
|
50
|
+
# Google4R::Checkout.sign({:a=>'123', :b=>'456'}, 'merchantkey')
|
51
|
+
# => "5qBQYatFZk5BMS1hm5gSUS+9yrg="
|
52
|
+
#
|
53
|
+
def self.sign(params, merchant_key)
|
54
|
+
raise "params must be a Hash (e.g. {param1 => value1, param2 => value2, ...})" unless params.kind_of? Hash
|
55
|
+
raise "merchant_key must be a String" unless merchant_key.kind_of? String
|
56
|
+
|
57
|
+
# Remove unwanted parameters
|
58
|
+
params.delete_if do |key, value|
|
59
|
+
key = key.to_s
|
60
|
+
key == '_charset_' || key == 'analyticsdata' ||
|
61
|
+
key == 'urchindata' || key =~ /^(.+\.)*[xy]$/
|
62
|
+
end
|
63
|
+
|
64
|
+
# Strip away whitespaces and url-encode the values
|
65
|
+
params.each do |key, value|
|
66
|
+
params[key] = CGI::escape(value.to_s.strip)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Sort parameters alphabetically by value and then key
|
70
|
+
params_arr = params.sort do |x, y|
|
71
|
+
if x[0] != y[0] then
|
72
|
+
x[0].to_s <=> y[0].to_s
|
73
|
+
else
|
74
|
+
x[1].to_s <=> y[1].to_s
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Create parameter string to be hashed
|
79
|
+
params_str = ''
|
80
|
+
params_arr.each do |x|
|
81
|
+
if params_str != '' then params_str += '&' end
|
82
|
+
params_str += x[0].to_s + '=' + x[1]
|
83
|
+
end
|
84
|
+
|
85
|
+
# Generate hashed signature
|
86
|
+
signature = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new,
|
87
|
+
merchant_key,
|
88
|
+
params_str)
|
89
|
+
|
90
|
+
# Encode the hash value in Base64 before returning it
|
91
|
+
return Base64.encode64(signature).chomp
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,1023 @@
|
|
1
|
+
#--
|
2
|
+
# Project: google4r
|
3
|
+
# File: lib/google4r/checkout/xml_generation.rb
|
4
|
+
# Authors: Manuel Holtgrewe <purestorm at ggnore dot net>
|
5
|
+
# Tony Chan <api.htchan at gmail dot com>
|
6
|
+
# Copyright: (c) 2007 by Manuel Holtgrewe
|
7
|
+
# License: MIT License as follows:
|
8
|
+
#
|
9
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
10
|
+
# a copy of this software and associated documentation files (the
|
11
|
+
# "Software"), to deal in the Software without restriction, including
|
12
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
13
|
+
# distribute, sublicense, and/or sell copies of the Software, and to permit
|
14
|
+
# persons to whom the Software is furnished to do so, subject to the
|
15
|
+
# following conditions:
|
16
|
+
#
|
17
|
+
# The above copyright notice and this permission notice shall be included
|
18
|
+
# in all copies or substantial portions of the Software.
|
19
|
+
#
|
20
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
21
|
+
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
22
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
23
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
24
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
25
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
26
|
+
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27
|
+
#++
|
28
|
+
# This file contains the classes that allow to persist the object hierarchies
|
29
|
+
# that are created with the Google Checkout API to XML.
|
30
|
+
|
31
|
+
require 'stringio'
|
32
|
+
require 'rexml/document'
|
33
|
+
require 'time'
|
34
|
+
|
35
|
+
module Google4R #:nodoc:
|
36
|
+
module Checkout #:nodoc:
|
37
|
+
|
38
|
+
class XmlGenerator
|
39
|
+
def initialize()
|
40
|
+
raise 'Cannot instantiate an abstract class.'
|
41
|
+
end
|
42
|
+
|
43
|
+
# Base method to generate the XML for a particular command
|
44
|
+
def generate
|
45
|
+
@document = REXML::Document.new
|
46
|
+
|
47
|
+
declaration = REXML::XMLDecl.new
|
48
|
+
declaration.encoding = 'utf-8'
|
49
|
+
@document << declaration
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Abstract super class for all CommandXmlGenerators
|
54
|
+
# It should never be instantiated directly
|
55
|
+
class CommandXmlGenerator < XmlGenerator
|
56
|
+
|
57
|
+
# The list of command tag names
|
58
|
+
COMMAND_TO_TAG =
|
59
|
+
{
|
60
|
+
ChargeAndShipOrderCommand => "charge-and-ship-order",
|
61
|
+
ChargeOrderCommand => 'charge-order',
|
62
|
+
RefundOrderCommand => 'refund-order',
|
63
|
+
CancelOrderCommand => 'cancel-order',
|
64
|
+
AuthorizeOrderCommand => 'authorize-order',
|
65
|
+
ProcessOrderCommand => 'process-order',
|
66
|
+
AddMerchantOrderNumberCommand => 'add-merchant-order-number',
|
67
|
+
DeliverOrderCommand => 'deliver-order',
|
68
|
+
AddTrackingDataCommand => 'add-tracking-data',
|
69
|
+
SendBuyerMessageCommand => 'send-buyer-message',
|
70
|
+
ArchiveOrderCommand => 'archive-order',
|
71
|
+
UnarchiveOrderCommand => 'unarchive-order',
|
72
|
+
CreateOrderRecurrenceRequestCommand => 'create-order-recurrence-request',
|
73
|
+
ShipItemsCommand => 'ship-items',
|
74
|
+
BackorderItemsCommand => 'backorder-items',
|
75
|
+
CancelItemsCommand => 'cancel-items',
|
76
|
+
ReturnItemsCommand => 'return-items',
|
77
|
+
ResetItemsShippingInformationCommand => 'reset-items-shipping-information',
|
78
|
+
OrderReportCommand => 'order-list-request',
|
79
|
+
}
|
80
|
+
|
81
|
+
def initialize(command)
|
82
|
+
if COMMAND_TO_TAG.has_key?(command.class)
|
83
|
+
@command = command
|
84
|
+
else
|
85
|
+
raise 'Cannot instantiate an abstract class.'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Base method to generate the XML for a particular command
|
90
|
+
def generate
|
91
|
+
super
|
92
|
+
self.process_command(@command)
|
93
|
+
io = StringIO.new
|
94
|
+
@document.write(io, -1)
|
95
|
+
return io.string
|
96
|
+
end
|
97
|
+
|
98
|
+
def tag_name_for_command(klass)
|
99
|
+
COMMAND_TO_TAG[klass]
|
100
|
+
end
|
101
|
+
|
102
|
+
protected
|
103
|
+
|
104
|
+
# Base method to generate root tag of a command
|
105
|
+
def process_command(command)
|
106
|
+
tag_name = self.tag_name_for_command(command.class)
|
107
|
+
root = @document.add_element(tag_name)
|
108
|
+
root.add_attribute('google-order-number', command.google_order_number)
|
109
|
+
root.add_attribute('xmlns', 'http://checkout.google.com/schema/2')
|
110
|
+
return root
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Use the CheckoutXmlGenerator to create an XML document from a CheckoutCommand
|
115
|
+
# object.
|
116
|
+
#
|
117
|
+
# Usage:
|
118
|
+
#
|
119
|
+
# checkout = CheckoutCommand.new
|
120
|
+
# # set up the CheckoutCommand
|
121
|
+
#
|
122
|
+
# generator = CheckoutCommandXmlGenerator.new(checkout)
|
123
|
+
# puts generator.generate # => "<xml? version=..."
|
124
|
+
# File.new('some.xml', 'w') { |f| f.write generator.generate }
|
125
|
+
#--
|
126
|
+
# TODO: Refactor the big, monolitic generator into smaller, easier testable ones. One for each major part of the resulting XML document. This will also reduce the overhead in generating other types of XML documents.
|
127
|
+
#++
|
128
|
+
class CheckoutCommandXmlGenerator < CommandXmlGenerator
|
129
|
+
|
130
|
+
def initialize(command)
|
131
|
+
@command = command
|
132
|
+
end
|
133
|
+
|
134
|
+
protected
|
135
|
+
|
136
|
+
def process_command(command)
|
137
|
+
root = @document.add_element("checkout-shopping-cart" , { 'xmlns' => 'http://checkout.google.com/schema/2' })
|
138
|
+
|
139
|
+
self.process_shopping_shopping_cart(root, command.shopping_cart)
|
140
|
+
|
141
|
+
# <merchant-checkout-flow-support>
|
142
|
+
flow_element = root.add_element('checkout-flow-support').add_element('merchant-checkout-flow-support')
|
143
|
+
|
144
|
+
# <tax-tables>
|
145
|
+
if command.tax_tables then
|
146
|
+
self.process_tax_tables(command.tax_tables, flow_element)
|
147
|
+
end
|
148
|
+
|
149
|
+
# <continue-shopping-url>
|
150
|
+
if not command.continue_shopping_url.nil? then
|
151
|
+
flow_element.add_element('continue-shopping-url').text = command.continue_shopping_url
|
152
|
+
end
|
153
|
+
|
154
|
+
# <edit-cart-url>
|
155
|
+
if not command.edit_cart_url.nil? then
|
156
|
+
flow_element.add_element('edit-cart-url').text = command.edit_cart_url
|
157
|
+
end
|
158
|
+
|
159
|
+
# <request-buyer-phone-number>
|
160
|
+
if not command.request_buyer_phone_number.nil? then
|
161
|
+
flow_element.add_element('request-buyer-phone-number').text =
|
162
|
+
if command.request_buyer_phone_number then
|
163
|
+
"true"
|
164
|
+
else
|
165
|
+
"false"
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# <merchant-calculations>
|
170
|
+
if not command.merchant_calculations_url.nil? then
|
171
|
+
merchant_calculations = flow_element.add_element('merchant-calculations')
|
172
|
+
merchant_calculations.add_element('merchant-calculations-url').text =
|
173
|
+
command.merchant_calculations_url
|
174
|
+
if not command.accept_merchant_coupons.nil? then
|
175
|
+
merchant_calculations.add_element('accept-merchant-coupons').text =
|
176
|
+
command.accept_merchant_coupons.to_s
|
177
|
+
end
|
178
|
+
if not command.accept_gift_certificates.nil? then
|
179
|
+
merchant_calculations.add_element('accept-gift-certificates').text =
|
180
|
+
command.accept_gift_certificates.to_s
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# <platform-id>
|
185
|
+
if not command.platform_id.nil? then
|
186
|
+
flow_element.add_element('platform-id').text = command.platform_id
|
187
|
+
end
|
188
|
+
|
189
|
+
# <shipping-methods>
|
190
|
+
shippings_element = flow_element.add_element('shipping-methods')
|
191
|
+
command.shipping_methods.each do |shipping_method|
|
192
|
+
self.process_shipping_method(shippings_element, shipping_method)
|
193
|
+
end
|
194
|
+
|
195
|
+
# <analytics-data>
|
196
|
+
unless command.analytics_data.nil? then
|
197
|
+
analytics_element = flow_element.add_element('analytics-data')
|
198
|
+
analytics_element.text = command.analytics_data
|
199
|
+
end
|
200
|
+
|
201
|
+
# <parameterized-urls>
|
202
|
+
if command.parameterized_urls then
|
203
|
+
parameterized_url_element = flow_element.add_element('parameterized-urls')
|
204
|
+
command.parameterized_urls.each do |parameterized_url|
|
205
|
+
self.process_parameterized_urls(parameterized_url, parameterized_url_element)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
# adds the tax-tables to the parent xml element
|
211
|
+
# assumes that the first member of the tax_tables array is the default tax rule table
|
212
|
+
# and that all others are alternate tax rules
|
213
|
+
def process_tax_tables(tax_tables, parent)
|
214
|
+
tax_tables_element = parent.add_element('tax-tables')
|
215
|
+
|
216
|
+
# assumes that the first tax table is the default
|
217
|
+
default_table = tax_tables.first
|
218
|
+
|
219
|
+
if default_table.merchant_calculated
|
220
|
+
tax_tables_element.add_attribute('merchant-calculated', 'true')
|
221
|
+
else
|
222
|
+
tax_tables_element.add_attribute('merchant-calculated', 'false')
|
223
|
+
end
|
224
|
+
|
225
|
+
default_table_element = tax_tables_element.add_element('default-tax-table')
|
226
|
+
rules_element = default_table_element.add_element('tax-rules')
|
227
|
+
|
228
|
+
default_table.rules.each do |rule|
|
229
|
+
default_rule_element = rules_element.add_element('default-tax-rule')
|
230
|
+
default_rule_element.add_element('shipping-taxed').text=rule.shipping_taxed.to_s
|
231
|
+
default_rule_element.add_element('rate').text=rule.rate.to_s
|
232
|
+
self.process_area(default_rule_element.add_element('tax-area'), rule.area)
|
233
|
+
end
|
234
|
+
|
235
|
+
# populate alternate tax tables
|
236
|
+
alt_tables = tax_tables.last(tax_tables.length-1)
|
237
|
+
alt_tables_element = tax_tables_element.add_element('alternate-tax-tables')
|
238
|
+
|
239
|
+
alt_tables.each do |table|
|
240
|
+
table_element = alt_tables_element.add_element('alternate-tax-table')
|
241
|
+
table_element.add_attribute('name', table.name)
|
242
|
+
table_element.add_attribute('standalone', table.standalone.to_s)
|
243
|
+
|
244
|
+
rules_element = table_element.add_element('alternate-tax-rules')
|
245
|
+
table.rules.each do |rule|
|
246
|
+
alt_rule_element = rules_element.add_element('alternate-tax-rule')
|
247
|
+
alt_rule_element.add_element('rate').text=rule.rate.to_s
|
248
|
+
|
249
|
+
self.process_area(alt_rule_element.add_element('tax-area'), rule.area)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
def process_shopping_shopping_cart(parent, shopping_cart)
|
256
|
+
cart_element = parent.add_element('shopping-cart')
|
257
|
+
|
258
|
+
# add <cart-expiration> tag to the cart if a time has been added to the cart
|
259
|
+
if not shopping_cart.expires_at.nil? then
|
260
|
+
cart_element.add_element('cart-expiration').add_element('good-until-date').text =
|
261
|
+
shopping_cart.expires_at.iso8601
|
262
|
+
end
|
263
|
+
|
264
|
+
# add <merchant-private-data> to the cart if any has been set
|
265
|
+
if not shopping_cart.private_data.nil? then
|
266
|
+
self.process_hash(cart_element.add_element('merchant-private-data'), shopping_cart.private_data)
|
267
|
+
end
|
268
|
+
|
269
|
+
# process the items in the cart
|
270
|
+
items_element = cart_element.add_element('items')
|
271
|
+
shopping_cart.items.each do |item|
|
272
|
+
self.process_item(items_element, item)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
# Adds an <item> tag to the tag parent with the appropriate values.
|
277
|
+
def process_item(parent, item)
|
278
|
+
item_element = parent.add_element('item')
|
279
|
+
|
280
|
+
item_element.add_element('item-name').text = item.name
|
281
|
+
item_element.add_element('item-description').text = item.description
|
282
|
+
|
283
|
+
item_element.add_element('unit-price', { 'currency' => item.unit_price.currency.to_s }).text = item.unit_price.to_s
|
284
|
+
item_element.add_element('quantity').text = item.quantity.to_i
|
285
|
+
|
286
|
+
if not item.id.nil? then
|
287
|
+
item_element.add_element('merchant-item-id').text = item.id
|
288
|
+
end
|
289
|
+
|
290
|
+
if not item.weight.nil? then
|
291
|
+
item_element.add_element('item-weight',
|
292
|
+
{ 'unit' => item.weight.unit,
|
293
|
+
'value' => item.weight.value })
|
294
|
+
end
|
295
|
+
|
296
|
+
if not item.private_data.nil? then
|
297
|
+
self.process_hash(item_element.add_element('merchant-private-item-data'), item.private_data)
|
298
|
+
end
|
299
|
+
|
300
|
+
# The above was easy; now we need to get the appropriate tax table for this
|
301
|
+
# item. The Item class makes sure that the table exists.
|
302
|
+
if not item.tax_table.nil? then
|
303
|
+
item_element.add_element('tax-table-selector').text = item.tax_table.name
|
304
|
+
end
|
305
|
+
|
306
|
+
if not item.digital_content.nil? then
|
307
|
+
self.process_digital_content(item_element, item.digital_content)
|
308
|
+
end
|
309
|
+
|
310
|
+
if not (item.kind_of? Item::Subscription::RecurrentItem or item.subscription.nil?) then
|
311
|
+
self.process_subscription(item_element, item.subscription)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
# Adds a <subscription> element to a parent (<item>) element
|
316
|
+
def process_subscription(parent, subscription)
|
317
|
+
subscription_element = parent.add_element('subscription')
|
318
|
+
|
319
|
+
if not subscription.no_charge_after.nil? then
|
320
|
+
subscription_element.attributes['no-charge-after'] = subscription.no_charge_after.xmlschema
|
321
|
+
end
|
322
|
+
|
323
|
+
if not subscription.period.nil? then
|
324
|
+
subscription_element.attributes['period'] = subscription.period.to_s
|
325
|
+
end
|
326
|
+
|
327
|
+
if not subscription.start_date.nil? then
|
328
|
+
subscription_element.attributes['start-date'] = subscription.start_date.xmlschema
|
329
|
+
end
|
330
|
+
|
331
|
+
if not subscription.type.nil? then
|
332
|
+
subscription_element.attributes['type'] = subscription.type.to_s
|
333
|
+
end
|
334
|
+
|
335
|
+
if subscription.payments.length > 0
|
336
|
+
payments_element = subscription_element.add_element('payments')
|
337
|
+
|
338
|
+
subscription.payments.each do |payment|
|
339
|
+
self.process_subscription_payment(payments_element, payment)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
if subscription.recurrent_items.length > 0
|
344
|
+
# this is a little bit of a hack; we use the normal way of generating items
|
345
|
+
# for a shopping cart, and then rename the elements to 'recurrent-item'
|
346
|
+
# after the fact
|
347
|
+
|
348
|
+
subscription.recurrent_items.each do |item|
|
349
|
+
self.process_item(subscription_element, item)
|
350
|
+
end
|
351
|
+
|
352
|
+
subscription_element.elements.each('item') do |item_element|
|
353
|
+
item_element.name = 'recurrent-item'
|
354
|
+
end
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
# Adds a <subcription-payment> element to a parent (<payments>) element
|
359
|
+
def process_subscription_payment(parent, payment)
|
360
|
+
payment_element = parent.add_element('subscription-payment')
|
361
|
+
|
362
|
+
if not payment.times.nil? then
|
363
|
+
payment_element.attributes['times'] = payment.times.to_s
|
364
|
+
end
|
365
|
+
|
366
|
+
if not payment.maximum_charge.nil? then
|
367
|
+
payment_element.add_element('maximum-charge', { 'currency' => payment.maximum_charge.currency.to_s }).text = payment.maximum_charge.to_s
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
# Adds a <digital-content> element to a parent (<item>) element
|
372
|
+
def process_digital_content(parent, digital_content)
|
373
|
+
digital_content_element = parent.add_element('digital-content')
|
374
|
+
|
375
|
+
if not digital_content.description.nil? then
|
376
|
+
digital_content_element.add_element('description').text = digital_content.description.to_s
|
377
|
+
end
|
378
|
+
|
379
|
+
if not digital_content.email_delivery.nil? then
|
380
|
+
digital_content_element.add_element('email-delivery').text = digital_content.email_delivery.to_s
|
381
|
+
end
|
382
|
+
|
383
|
+
if not digital_content.key.nil? then
|
384
|
+
digital_content_element.add_element('key').text = digital_content.key.to_s
|
385
|
+
end
|
386
|
+
|
387
|
+
if not digital_content.url.nil? then
|
388
|
+
digital_content_element.add_element('url').text = digital_content.url.to_s
|
389
|
+
end
|
390
|
+
|
391
|
+
digital_content_element.add_element('display-disposition').text = digital_content.display_disposition.to_s
|
392
|
+
end
|
393
|
+
|
394
|
+
# Adds an item for the given shipping method.
|
395
|
+
def process_shipping_method(parent, shipping_method)
|
396
|
+
if shipping_method.kind_of? PickupShipping then
|
397
|
+
process_pickup(parent, shipping_method)
|
398
|
+
elsif shipping_method.kind_of? FlatRateShipping then
|
399
|
+
process_shipping('flat-rate-shipping', parent, shipping_method)
|
400
|
+
elsif shipping_method.kind_of? MerchantCalculatedShipping then
|
401
|
+
process_shipping('merchant-calculated-shipping', parent, shipping_method)
|
402
|
+
elsif shipping_method.kind_of? CarrierCalculatedShipping then
|
403
|
+
process_carrier_calculated_shipping('carrier-calculated-shipping', parent, shipping_method)
|
404
|
+
else
|
405
|
+
raise "Unknown ShippingMethod type of #{shipping_method.inspect}!"
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
def process_shipping(shipping_type, parent, shipping)
|
410
|
+
element = parent.add_element(shipping_type)
|
411
|
+
element.add_attribute('name', shipping.name)
|
412
|
+
element.add_element('price', { 'currency' => shipping.price.currency.to_s }).text = shipping.price.to_s
|
413
|
+
|
414
|
+
if shipping.shipping_restrictions_excluded_areas.length +
|
415
|
+
shipping.shipping_restrictions_allowed_areas.length > 0 then
|
416
|
+
shipping_restrictions_tag = element.add_element('shipping-restrictions')
|
417
|
+
|
418
|
+
allow_us_po_box = shipping_restrictions_tag.add_element('allow-us-po-box')
|
419
|
+
if shipping.shipping_restrictions_allow_us_po_box
|
420
|
+
allow_us_po_box.text = 'true'
|
421
|
+
else
|
422
|
+
allow_us_po_box.text = 'false'
|
423
|
+
end
|
424
|
+
|
425
|
+
if shipping.shipping_restrictions_allowed_areas.length > 0 then
|
426
|
+
allowed_tag = shipping_restrictions_tag.add_element('allowed-areas')
|
427
|
+
|
428
|
+
shipping.shipping_restrictions_allowed_areas.each do |area|
|
429
|
+
self.process_area(allowed_tag, area)
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
if shipping.shipping_restrictions_excluded_areas.length > 0 then
|
434
|
+
excluded_tag = shipping_restrictions_tag.add_element('excluded-areas')
|
435
|
+
|
436
|
+
shipping.shipping_restrictions_excluded_areas.each do |area|
|
437
|
+
self.process_area(excluded_tag, area)
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
if shipping.kind_of? MerchantCalculatedShipping then
|
443
|
+
if shipping.address_filters_excluded_areas.length +
|
444
|
+
shipping.address_filters_allowed_areas.length > 0 then
|
445
|
+
address_filters_tag = element.add_element('address-filters')
|
446
|
+
|
447
|
+
allow_us_po_box = address_filters_tag.add_element('allow-us-po-box')
|
448
|
+
if shipping.address_filters_allow_us_po_box
|
449
|
+
allow_us_po_box.text = 'true'
|
450
|
+
else
|
451
|
+
allow_us_po_box.text = 'false'
|
452
|
+
end
|
453
|
+
|
454
|
+
if shipping.address_filters_allowed_areas.length > 0 then
|
455
|
+
allowed_tag = address_filters_tag.add_element('allowed-areas')
|
456
|
+
|
457
|
+
shipping.address_filters_allowed_areas.each do |area|
|
458
|
+
self.process_area(allowed_tag, area)
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
if shipping.address_filters_excluded_areas.length > 0 then
|
463
|
+
excluded_tag = address_filters_tag.add_element('excluded-areas')
|
464
|
+
|
465
|
+
shipping.address_filters_excluded_areas.each do |area|
|
466
|
+
self.process_area(excluded_tag, area)
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
def process_pickup(parent, shipping)
|
474
|
+
element = parent.add_element('pickup')
|
475
|
+
element.add_attribute('name', shipping.name)
|
476
|
+
element.add_element('price', { 'currency' => shipping.price.currency.to_s }).text = shipping.price.to_s
|
477
|
+
end
|
478
|
+
|
479
|
+
def process_carrier_calculated_shipping(shipping_type, parent, shipping)
|
480
|
+
element = parent.add_element(shipping_type)
|
481
|
+
options_element = element.add_element('carrier-calculated-shipping-options')
|
482
|
+
packages_element = element.add_element('shipping-packages')
|
483
|
+
shipping.carrier_calculated_shipping_options.each do | option |
|
484
|
+
process_carrier_calculated_shipping_option(options_element, option)
|
485
|
+
end
|
486
|
+
shipping.shipping_packages.each do | package |
|
487
|
+
process_shipping_package(packages_element, package)
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
def process_carrier_calculated_shipping_option(parent, option)
|
492
|
+
element = parent.add_element('carrier-calculated-shipping-option')
|
493
|
+
element.add_element('price', { 'currency' => option.price.currency.to_s }).text = option.price.to_s
|
494
|
+
element.add_element('shipping-company').text = option.shipping_company
|
495
|
+
element.add_element('shipping-type').text = option.shipping_type
|
496
|
+
if not option.carrier_pickup.nil?
|
497
|
+
element.add_element('carrier-pickup').text = option.carrier_pickup
|
498
|
+
end
|
499
|
+
if not option.additional_fixed_charge.nil?
|
500
|
+
element.add_element('additional-fixed-charge',
|
501
|
+
{ 'currency' => option.additional_fixed_charge.currency.to_s }).text =
|
502
|
+
option.additional_fixed_charge.to_s
|
503
|
+
end
|
504
|
+
if not option.additional_variable_charge_percent.nil?
|
505
|
+
element.add_element('additional-variable-charge-percent').text =
|
506
|
+
option.additional_variable_charge_percent.to_s
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
510
|
+
def process_shipping_package(parent, package)
|
511
|
+
element = parent.add_element('shipping-package')
|
512
|
+
ship_from = package.ship_from
|
513
|
+
ship_from_element = element.add_element('ship-from')
|
514
|
+
ship_from_element.add_attribute('id', ship_from.address_id)
|
515
|
+
ship_from_element.add_element('city').text = ship_from.city
|
516
|
+
ship_from_element.add_element('region').text = ship_from.region
|
517
|
+
ship_from_element.add_element('country-code').text = ship_from.country_code
|
518
|
+
ship_from_element.add_element('postal-code').text = ship_from.postal_code
|
519
|
+
if not package.delivery_address_category.nil?
|
520
|
+
element.add_element('delivery-address-category').text =
|
521
|
+
package.delivery_address_category
|
522
|
+
end
|
523
|
+
if not package.height.nil?
|
524
|
+
height_element = element.add_element('height')
|
525
|
+
height_element.add_attribute('unit', package.height.unit)
|
526
|
+
height_element.add_attribute('value', package.height.value.to_s)
|
527
|
+
end
|
528
|
+
if not package.length.nil?
|
529
|
+
length_element = element.add_element('length')
|
530
|
+
length_element.add_attribute('unit', package.length.unit)
|
531
|
+
length_element.add_attribute('value', package.length.value.to_s)
|
532
|
+
end
|
533
|
+
if not package.width.nil?
|
534
|
+
width_element = element.add_element('width')
|
535
|
+
width_element.add_attribute('unit', package.width.unit)
|
536
|
+
width_element.add_attribute('value', package.width.value.to_s)
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
# Adds an appropriate tag for the given Area subclass instance to the parent Element.
|
541
|
+
def process_area(parent, area)
|
542
|
+
if area.kind_of? UsZipArea then
|
543
|
+
parent.add_element('us-zip-area').add_element('zip-pattern').text = area.pattern
|
544
|
+
elsif area.kind_of? UsCountryArea then
|
545
|
+
parent.add_element('us-country-area', { 'country-area' => area.area })
|
546
|
+
elsif area.kind_of? UsStateArea then
|
547
|
+
parent.add_element('us-state-area').add_element('state').text = area.state
|
548
|
+
elsif area.kind_of? WorldArea then
|
549
|
+
parent.add_element('world-area')
|
550
|
+
elsif area.kind_of? PostalArea then
|
551
|
+
postal_area_element = parent.add_element('postal-area')
|
552
|
+
postal_area_element.add_element('country-code').text = area.country_code
|
553
|
+
if area.postal_code_pattern then
|
554
|
+
postal_area_element.add_element('postal-code-pattern').text = area.postal_code_pattern
|
555
|
+
end
|
556
|
+
else
|
557
|
+
raise "Area of unknown type: #{area.inspect}."
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
561
|
+
# Adda the paramterized URL nodes for 3rd party conversion tracking
|
562
|
+
# Adds a <paramertized-url> element to a parent (<parameterized-urls>) element
|
563
|
+
def process_parameterized_urls(parameterized_url, parent)
|
564
|
+
parameterized_url_node = parent.add_element('parameterized-url')
|
565
|
+
parameterized_url_node.add_attribute('url', parameterized_url.url)
|
566
|
+
parent_parameters_node = parameterized_url_node.add_element('parameters') if parameterized_url.url_parameters
|
567
|
+
parameterized_url.url_parameters.each do |parameter|
|
568
|
+
parameter_node = parent_parameters_node.add_element('url-parameter')
|
569
|
+
parameter_node.add_attribute('name', parameter.name)
|
570
|
+
parameter_node.add_attribute('type',parameter.parameter_type)
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
# Converts a Hash into an XML structure. The keys are converted to tag names. If
|
575
|
+
# the values are Hashs themselves then process_hash is called upon them. If the
|
576
|
+
# values are Arrays then a new element with the key's name will be created.
|
577
|
+
#
|
578
|
+
# If a value is an Array then this array will be flattened before it is processed.
|
579
|
+
# Thus, nested arrays are not allowed.
|
580
|
+
#
|
581
|
+
# === Example
|
582
|
+
#
|
583
|
+
# process_hash(parent, { 'foo' => { 'bar' => 'baz' } })
|
584
|
+
#
|
585
|
+
# # will produce a structure that is equivalent to.
|
586
|
+
#
|
587
|
+
# <foo>
|
588
|
+
# <bar>baz</bar>
|
589
|
+
# </foo>
|
590
|
+
#
|
591
|
+
#
|
592
|
+
# process_hash(parent, { 'foo' => [ { 'bar' => 'baz' }, "d'oh", 2 ] })
|
593
|
+
#
|
594
|
+
# # will produce a structure that is equivalent to.
|
595
|
+
#
|
596
|
+
# <foo>
|
597
|
+
# <bar>baz</bar>
|
598
|
+
# </foo>
|
599
|
+
# <foo>d&</foo>
|
600
|
+
# <foo>2</foo>
|
601
|
+
def process_hash(parent, hash)
|
602
|
+
hash.each do |key, value|
|
603
|
+
if value.kind_of? Array then
|
604
|
+
value.flatten.each do |arr_entry|
|
605
|
+
if arr_entry.kind_of? Hash then
|
606
|
+
self.process_hash(parent.add_element(self.str2tag_name(key.to_s)), arr_entry)
|
607
|
+
else
|
608
|
+
parent.add_element(self.str2tag_name(key.to_s)).text = arr_entry.to_s
|
609
|
+
end
|
610
|
+
end
|
611
|
+
elsif value.kind_of? Hash then
|
612
|
+
process_hash(parent.add_element(self.str2tag_name(key.to_s)), value)
|
613
|
+
else
|
614
|
+
parent.add_element(self.str2tag_name(key.to_s)).text = value.to_s
|
615
|
+
end
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
# Converts a string to a valid XML tag name. Whitespace will be converted into a dash/minus
|
620
|
+
# sign, non alphanumeric characters that are neither "-" nor "_" nor ":" will be stripped.
|
621
|
+
def str2tag_name(str)
|
622
|
+
str.gsub(%r{\s}, '-').gsub(%r{[^a-zA-Z0-9\-\_:]}, '')
|
623
|
+
end
|
624
|
+
end
|
625
|
+
|
626
|
+
class ChargeOrderCommandXmlGenerator < CommandXmlGenerator
|
627
|
+
|
628
|
+
protected
|
629
|
+
|
630
|
+
def process_command(command)
|
631
|
+
root = super
|
632
|
+
process_money(root, command.amount) if command.amount
|
633
|
+
end
|
634
|
+
|
635
|
+
# add the amount element to the charge command
|
636
|
+
def process_money(parent, money)
|
637
|
+
amount_element = parent.add_element('amount')
|
638
|
+
amount_element.text = money.to_s
|
639
|
+
amount_element.add_attribute('currency', money.currency.to_s)
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
class ChargeAndShipOrderCommandXmlGenerator < CommandXmlGenerator
|
644
|
+
|
645
|
+
protected
|
646
|
+
|
647
|
+
def process_command(command)
|
648
|
+
root = super
|
649
|
+
process_money(root, command.amount) if command.amount
|
650
|
+
process_tracking_data(root, command.carrier, command.tracking_number)
|
651
|
+
root.add_element('send-email').text = command.send_email.to_s if command.send_email
|
652
|
+
end
|
653
|
+
|
654
|
+
def process_money(parent, money)
|
655
|
+
amount_element = parent.add_element('amount')
|
656
|
+
amount_element.text = money.to_s
|
657
|
+
amount_element.add_attribute('currency', money.currency.to_s)
|
658
|
+
end
|
659
|
+
|
660
|
+
def process_tracking_data(parent, carrier, tracking_number)
|
661
|
+
if carrier and tracking_number then
|
662
|
+
e1 = parent.add_element('tracking-data-list')
|
663
|
+
e2 = e1.add_element('tracking-data')
|
664
|
+
e2.add_element('carrier').text = carrier
|
665
|
+
e2.add_element('tracking-number').text = tracking_number
|
666
|
+
end
|
667
|
+
end
|
668
|
+
end
|
669
|
+
|
670
|
+
class RefundOrderCommandXmlGenerator < CommandXmlGenerator
|
671
|
+
|
672
|
+
protected
|
673
|
+
|
674
|
+
def process_command(command)
|
675
|
+
root = super
|
676
|
+
process_money(root, command.amount) if command.amount
|
677
|
+
process_comment(root, command.comment) if command.comment
|
678
|
+
process_reason(root, command.reason)
|
679
|
+
end
|
680
|
+
|
681
|
+
# add the amount element to the refund command
|
682
|
+
def process_money(parent, money)
|
683
|
+
amount_element = parent.add_element('amount')
|
684
|
+
amount_element.text = money.to_s
|
685
|
+
amount_element.add_attribute('currency', money.currency.to_s)
|
686
|
+
end
|
687
|
+
|
688
|
+
# add the comment element to the refund command
|
689
|
+
def process_comment(parent, comment)
|
690
|
+
comment_element = parent.add_element('comment')
|
691
|
+
comment_element.text = comment
|
692
|
+
end
|
693
|
+
|
694
|
+
# add the reason element to the refund command
|
695
|
+
def process_reason(parent, reason)
|
696
|
+
reason_element = parent.add_element('reason')
|
697
|
+
reason_element.text = reason
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|
701
|
+
class CancelOrderCommandXmlGenerator < CommandXmlGenerator
|
702
|
+
|
703
|
+
protected
|
704
|
+
|
705
|
+
def process_command(command)
|
706
|
+
root = super
|
707
|
+
root.add_element('reason').text = command.reason
|
708
|
+
|
709
|
+
if command.comment then
|
710
|
+
root.add_element('comment').text = command.comment
|
711
|
+
end
|
712
|
+
end
|
713
|
+
|
714
|
+
end
|
715
|
+
|
716
|
+
class AuthorizeOrderCommandXmlGenerator < CommandXmlGenerator
|
717
|
+
|
718
|
+
protected
|
719
|
+
|
720
|
+
def process_command(command)
|
721
|
+
super
|
722
|
+
end
|
723
|
+
end
|
724
|
+
|
725
|
+
class ProcessOrderCommandXmlGenerator < CommandXmlGenerator
|
726
|
+
|
727
|
+
protected
|
728
|
+
|
729
|
+
def process_command(command)
|
730
|
+
super
|
731
|
+
end
|
732
|
+
end
|
733
|
+
|
734
|
+
class AddMerchantOrderNumberCommandXmlGenerator < CommandXmlGenerator
|
735
|
+
|
736
|
+
protected
|
737
|
+
|
738
|
+
def process_command(command)
|
739
|
+
root = super
|
740
|
+
process_merchant_order_number(root, command.merchant_order_number)
|
741
|
+
end
|
742
|
+
|
743
|
+
def process_merchant_order_number(parent, merchant_order_number)
|
744
|
+
merchant_order_number_element = parent.add_element('merchant-order-number')
|
745
|
+
merchant_order_number_element.text = merchant_order_number
|
746
|
+
end
|
747
|
+
end
|
748
|
+
|
749
|
+
class DeliverOrderCommandXmlGenerator < CommandXmlGenerator
|
750
|
+
|
751
|
+
protected
|
752
|
+
|
753
|
+
def process_command(command)
|
754
|
+
root = super
|
755
|
+
# Add tracking info
|
756
|
+
process_tracking_data(root, command.carrier, command.tracking_number)
|
757
|
+
root.add_element('send-email').text = command.send_email.to_s
|
758
|
+
end
|
759
|
+
|
760
|
+
def process_tracking_data(parent, carrier, tracking_number)
|
761
|
+
if carrier and tracking_number then
|
762
|
+
element = parent.add_element('tracking-data')
|
763
|
+
element.add_element('carrier').text = carrier
|
764
|
+
element.add_element('tracking-number').text = tracking_number
|
765
|
+
end
|
766
|
+
end
|
767
|
+
end
|
768
|
+
|
769
|
+
class AddTrackingDataCommandXmlGenerator < CommandXmlGenerator
|
770
|
+
|
771
|
+
protected
|
772
|
+
|
773
|
+
def process_command(command)
|
774
|
+
root = super
|
775
|
+
# Add tracking info
|
776
|
+
process_tracking_data(root, command.carrier, command.tracking_number)
|
777
|
+
end
|
778
|
+
|
779
|
+
def process_tracking_data(parent, carrier, tracking_number)
|
780
|
+
if carrier and tracking_number then
|
781
|
+
element = parent.add_element('tracking-data')
|
782
|
+
element.add_element('carrier').text = carrier
|
783
|
+
element.add_element('tracking-number').text = tracking_number
|
784
|
+
end
|
785
|
+
end
|
786
|
+
end
|
787
|
+
|
788
|
+
class SendBuyerMessageCommandXmlGenerator < CommandXmlGenerator
|
789
|
+
|
790
|
+
protected
|
791
|
+
|
792
|
+
def process_command(command)
|
793
|
+
root = super
|
794
|
+
root.add_element('message').text = command.message
|
795
|
+
if not command.send_email.nil? then
|
796
|
+
root.add_element('send-email').text = command.send_email.to_s
|
797
|
+
end
|
798
|
+
end
|
799
|
+
end
|
800
|
+
|
801
|
+
class ArchiveOrderCommandXmlGenerator < CommandXmlGenerator
|
802
|
+
|
803
|
+
protected
|
804
|
+
|
805
|
+
def process_command(command)
|
806
|
+
super
|
807
|
+
end
|
808
|
+
end
|
809
|
+
|
810
|
+
class UnarchiveOrderCommandXmlGenerator < CommandXmlGenerator
|
811
|
+
|
812
|
+
protected
|
813
|
+
|
814
|
+
def process_command(command)
|
815
|
+
super
|
816
|
+
end
|
817
|
+
end
|
818
|
+
|
819
|
+
class CreateOrderRecurrenceRequestCommandXmlGenerator < CheckoutCommandXmlGenerator
|
820
|
+
|
821
|
+
protected
|
822
|
+
|
823
|
+
def process_command(command)
|
824
|
+
root = @document.add_element("create-order-recurrence-request" , { 'xmlns' => 'http://checkout.google.com/schema/2' })
|
825
|
+
|
826
|
+
root.attributes['google-order-number'] = command.google_order_number
|
827
|
+
|
828
|
+
self.process_shopping_shopping_cart(root, command.shopping_cart)
|
829
|
+
end
|
830
|
+
end
|
831
|
+
|
832
|
+
class MerchantCalculationResultsXmlGenerator < XmlGenerator
|
833
|
+
|
834
|
+
def initialize(merchant_calculation_results)
|
835
|
+
@merchant_calculation_results = merchant_calculation_results
|
836
|
+
end
|
837
|
+
|
838
|
+
def generate()
|
839
|
+
super
|
840
|
+
process_results(@merchant_calculation_results.merchant_calculation_results)
|
841
|
+
io = StringIO.new
|
842
|
+
@document.write(io, -1)
|
843
|
+
return io.string
|
844
|
+
end
|
845
|
+
|
846
|
+
protected
|
847
|
+
|
848
|
+
def process_results(merchant_calculation_results)
|
849
|
+
root = @document.add_element("merchant-calculation-results" , { 'xmlns' => 'http://checkout.google.com/schema/2' })
|
850
|
+
results = root.add_element("results")
|
851
|
+
for merchant_calculation_result in merchant_calculation_results do
|
852
|
+
process_result(results, merchant_calculation_result)
|
853
|
+
end
|
854
|
+
end
|
855
|
+
|
856
|
+
def process_result(parent, merchant_calculation_result)
|
857
|
+
element = parent.add_element("result")
|
858
|
+
element.add_attribute("shipping-name", merchant_calculation_result.shipping_name)
|
859
|
+
element.add_attribute("address-id", merchant_calculation_result.address_id)
|
860
|
+
shipping_rate = element.add_element("shipping-rate")
|
861
|
+
shipping_rate.text = merchant_calculation_result.shipping_rate.to_s
|
862
|
+
shipping_rate.add_attribute("currency", merchant_calculation_result.shipping_rate.currency.to_s)
|
863
|
+
element.add_element("shippable").text = merchant_calculation_result.shippable.to_s
|
864
|
+
if (!merchant_calculation_result.total_tax.nil?)
|
865
|
+
total_tax = element.add_element("total-tax")
|
866
|
+
total_tax.text = merchant_calculation_result.total_tax.to_s
|
867
|
+
total_tax.add_attribute("currency", merchant_calculation_result.total_tax.currency.to_s)
|
868
|
+
end
|
869
|
+
process_code_results(element, merchant_calculation_result.merchant_code_results)
|
870
|
+
end
|
871
|
+
|
872
|
+
def process_code_results(parent, merchant_code_results)
|
873
|
+
element = parent.add_element("merchant-code-results")
|
874
|
+
for merchant_code_result in merchant_code_results do
|
875
|
+
process_merchant_code_result(element, merchant_code_result)
|
876
|
+
end
|
877
|
+
end
|
878
|
+
|
879
|
+
def process_merchant_code_result(parent, merchant_code_result)
|
880
|
+
if merchant_code_result.kind_of?(CouponResult)
|
881
|
+
element = parent.add_element("coupon-result")
|
882
|
+
elsif merchant_code_result.kind_of?(GiftCertificateResult)
|
883
|
+
element = parent.add_element("gift-certificate-result")
|
884
|
+
else
|
885
|
+
raise "Code of unknown type: #{merchant_code_result.inspect}."
|
886
|
+
end
|
887
|
+
element.add_element("valid").text = merchant_code_result.valid.to_s
|
888
|
+
element.add_element("code").text = merchant_code_result.code.to_s
|
889
|
+
calculated_amount = element.add_element("calculated-amount")
|
890
|
+
calculated_amount.text = merchant_code_result.calculated_amount.to_s
|
891
|
+
calculated_amount.add_attribute("currency", merchant_code_result.calculated_amount.currency.to_s)
|
892
|
+
element.add_element("message").text = merchant_code_result.message
|
893
|
+
end
|
894
|
+
end
|
895
|
+
|
896
|
+
class NotificationAcknowledgementXmlGenerator < XmlGenerator
|
897
|
+
|
898
|
+
def initialize(notification_acknowledgement)
|
899
|
+
@notification_acknowledgement = notification_acknowledgement
|
900
|
+
end
|
901
|
+
|
902
|
+
def generate
|
903
|
+
super
|
904
|
+
self.process_notification_acknowledgement(@notification_acknowledgement)
|
905
|
+
io = StringIO.new
|
906
|
+
@document.write(io, -1)
|
907
|
+
return io.string
|
908
|
+
end
|
909
|
+
|
910
|
+
def process_notification_acknowledgement(notification_acknowledgement)
|
911
|
+
root = @document.add_element('notification-acknowledgment')
|
912
|
+
root.add_attribute('xmlns', 'http://checkout.google.com/schema/2')
|
913
|
+
if not notification_acknowledgement.serial_number.nil?
|
914
|
+
root.add_attribute('serial-number', notification_acknowledgement.serial_number)
|
915
|
+
end
|
916
|
+
end
|
917
|
+
end
|
918
|
+
|
919
|
+
# Line-item shipping commands
|
920
|
+
class ItemsCommandXmlGenerator < CommandXmlGenerator
|
921
|
+
protected
|
922
|
+
|
923
|
+
def process_command(command)
|
924
|
+
root = super
|
925
|
+
process_item_info_arr(root, command.item_info_arr)
|
926
|
+
process_send_email(root, command.send_email)
|
927
|
+
return root
|
928
|
+
end
|
929
|
+
|
930
|
+
def process_item_info_arr(parent, item_info_arr)
|
931
|
+
element = parent.add_element('item-ids')
|
932
|
+
item_info_arr.each do |item_info|
|
933
|
+
item_id = element.add_element('item-id')
|
934
|
+
item_id.add_element('merchant-item-id').text =
|
935
|
+
item_info.merchant_item_id
|
936
|
+
end
|
937
|
+
end
|
938
|
+
|
939
|
+
def process_send_email(parent, send_email)
|
940
|
+
parent.add_element('send-email').text = send_email.to_s
|
941
|
+
end
|
942
|
+
end
|
943
|
+
|
944
|
+
class ShipItemsCommandXmlGenerator < ItemsCommandXmlGenerator
|
945
|
+
protected
|
946
|
+
|
947
|
+
def process_item_info_arr(parent, item_info_arr)
|
948
|
+
e1 = parent.add_element('item-shipping-information-list')
|
949
|
+
item_info_arr.each do |item_info|
|
950
|
+
e2 = e1.add_element('item-shipping-information')
|
951
|
+
item_id = e2.add_element('item-id')
|
952
|
+
item_id.add_element('merchant-item-id').text =
|
953
|
+
item_info.merchant_item_id
|
954
|
+
if !item_info.tracking_data_arr.nil?
|
955
|
+
e3 = e2.add_element('tracking-data-list')
|
956
|
+
item_info.tracking_data_arr.each do |tracking_data|
|
957
|
+
e4 = e3.add_element('tracking-data')
|
958
|
+
e4.add_element('carrier').text = tracking_data.carrier
|
959
|
+
e4.add_element('tracking-number').text =
|
960
|
+
tracking_data.tracking_number
|
961
|
+
end
|
962
|
+
end
|
963
|
+
end
|
964
|
+
end
|
965
|
+
end
|
966
|
+
|
967
|
+
class BackorderItemsCommandXmlGenerator < ItemsCommandXmlGenerator
|
968
|
+
end
|
969
|
+
|
970
|
+
class CancelItemsCommandXmlGenerator < ItemsCommandXmlGenerator
|
971
|
+
protected
|
972
|
+
|
973
|
+
def process_command(command)
|
974
|
+
root = super
|
975
|
+
root.add_element('reason').text = command.reason
|
976
|
+
|
977
|
+
if command.comment then
|
978
|
+
root.add_element('comment').text = command.comment
|
979
|
+
end
|
980
|
+
end
|
981
|
+
end
|
982
|
+
|
983
|
+
class ReturnItemsCommandXmlGenerator < ItemsCommandXmlGenerator
|
984
|
+
end
|
985
|
+
|
986
|
+
class ResetItemsShippingInformationCommandXmlGenerator < ItemsCommandXmlGenerator
|
987
|
+
end
|
988
|
+
|
989
|
+
class ReturnOrderReportCommandXmlGenerator < CommandXmlGenerator
|
990
|
+
def initialize(command)
|
991
|
+
@command = command
|
992
|
+
end
|
993
|
+
|
994
|
+
protected
|
995
|
+
|
996
|
+
def process_command(command)
|
997
|
+
root = super
|
998
|
+
# TODO - sanity check format ?
|
999
|
+
root.add_attribute('start-date', command.start_date.to_s)
|
1000
|
+
root.add_attribute('end-date', command.end_date.to_s)
|
1001
|
+
flow_element = root
|
1002
|
+
|
1003
|
+
# <financial-state>
|
1004
|
+
if command.financial_state then
|
1005
|
+
financial_state_element = flow_element.add_element('financial-state')
|
1006
|
+
financial_state_element.text = command.financial_state.to_s
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
# <fulfillment-state>
|
1010
|
+
if command.fulfillment_state then
|
1011
|
+
fulfillment_state_element = flow_element.add_element('fulfillment-state')
|
1012
|
+
fulfillment_state_element.text = command.fulfillment_state.to_s
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
# <date-time-zone>
|
1016
|
+
if command.date_time_zone then
|
1017
|
+
dtz_element = flow_element.add_element('date-time-zone')
|
1018
|
+
dtz_element.text = command.date_time_zone.to_s
|
1019
|
+
end
|
1020
|
+
end
|
1021
|
+
end
|
1022
|
+
end
|
1023
|
+
end
|