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,1386 @@
|
|
1
|
+
#--
|
2
|
+
# Project: google4r
|
3
|
+
# File: lib/google4r/checkout/shared.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 shared by the notification
|
28
|
+
# handling and parsing as well as the command generating code.
|
29
|
+
|
30
|
+
require 'bigdecimal'
|
31
|
+
|
32
|
+
#--
|
33
|
+
# TODO: Make the optional attributes return defaults that make sense, i.e. Money.new(0)?
|
34
|
+
#++
|
35
|
+
module Google4R #:nodoc:
|
36
|
+
module Checkout #:nodoc:
|
37
|
+
# This exception is thrown by Command#send_to_google_checkout when an error occured.
|
38
|
+
class GoogleCheckoutError < Exception
|
39
|
+
# The serial number of the error returned by Google.
|
40
|
+
attr_reader :serial_number
|
41
|
+
|
42
|
+
# The HTTP response code of Google's response.
|
43
|
+
attr_reader :response_code
|
44
|
+
|
45
|
+
# The parameter is a hash with the entries :serial_number, :message and :response_code.
|
46
|
+
# The attributes serial_number, message and response_code are set to the values in the
|
47
|
+
# Hash.
|
48
|
+
def initialize(hash)
|
49
|
+
@response_code = hash[:response_code]
|
50
|
+
@message = hash[:message]
|
51
|
+
@serial_number = hash[:serial_number]
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns a human readable representation of the Exception with the message, HTTP
|
55
|
+
# response code and serial number as returned by Google checkout.
|
56
|
+
def to_s
|
57
|
+
"GoogleCheckoutError: message = '#{@message}', response code = '#{@response_code}', serial number = '#{@serial_number}'."
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# ShoppingCart instances are containers for Item instances. You can add
|
62
|
+
# Items to the class using #create_item (see the documentation of this
|
63
|
+
# method for an example).
|
64
|
+
class ShoppingCart
|
65
|
+
# The owner of this cart. At the moment, this always is the CheckoutCartCommand.
|
66
|
+
attr_reader :owner
|
67
|
+
|
68
|
+
# The items in the cart. Do not modify this array directly but use
|
69
|
+
# #create_item to add items.
|
70
|
+
attr_reader :items
|
71
|
+
|
72
|
+
# You can set the <cart-expiration> time with this property. If left
|
73
|
+
# unset then the tag will not be generated and the cart will never
|
74
|
+
# expire.
|
75
|
+
attr_accessor :expires_at
|
76
|
+
|
77
|
+
# You can set almost arbitrary data into the cart using this method.
|
78
|
+
#
|
79
|
+
# The data will be converted to XML in the following way: The keys are converted
|
80
|
+
# to tag names (whitespace becomes "-", all chars not matching /[a-zA-Z0-9\-_])/
|
81
|
+
# will be removed.
|
82
|
+
#
|
83
|
+
# If a value is an array then the key for this value will be used as the tag
|
84
|
+
# name for each of the arrays's entries.
|
85
|
+
#
|
86
|
+
# Arrays will be flattened before it is processed.
|
87
|
+
#
|
88
|
+
# === Example
|
89
|
+
#
|
90
|
+
# cart.private_data = { 'foo' => { 'bar' => 'baz' } })
|
91
|
+
#
|
92
|
+
# # will produce the following XML
|
93
|
+
#
|
94
|
+
# <foo>
|
95
|
+
# <bar>baz</bar>
|
96
|
+
# </foo>
|
97
|
+
#
|
98
|
+
#
|
99
|
+
# cart.private_data = { 'foo' => [ { 'bar' => 'baz' }, "d'oh", 2 ] }
|
100
|
+
#
|
101
|
+
# # will produce the following XML
|
102
|
+
#
|
103
|
+
# <foo>
|
104
|
+
# <bar>baz</bar>
|
105
|
+
# </foo>
|
106
|
+
# <foo>d&</foo>
|
107
|
+
# <foo>2</foo>
|
108
|
+
attr_reader :private_data
|
109
|
+
|
110
|
+
# Sets the value of the private_data attribute.
|
111
|
+
def private_data=(value)
|
112
|
+
raise "The given value #{value.inspect} is not a Hash!" unless value.kind_of?(Hash)
|
113
|
+
@private_data = value
|
114
|
+
end
|
115
|
+
|
116
|
+
# Initialize a new ShoppingCart with an empty Array for the items.
|
117
|
+
def initialize(owner)
|
118
|
+
@owner = owner
|
119
|
+
@items = Array.new
|
120
|
+
end
|
121
|
+
|
122
|
+
# Use this method to add a new item to the cart. If you use a block with
|
123
|
+
# this method then the block will be given the new item. The new item
|
124
|
+
# will be returned in any case.
|
125
|
+
#
|
126
|
+
# Passing a block is the preferred way of using this method.
|
127
|
+
#
|
128
|
+
# === Example
|
129
|
+
#
|
130
|
+
# # Using a block (preferred).
|
131
|
+
# cart = ShoppingCart.new
|
132
|
+
#
|
133
|
+
# cart.create_item do |item|
|
134
|
+
# item.name = "Dry Food Pack"
|
135
|
+
# item.description = "A pack of highly nutritious..."
|
136
|
+
# item.unit_price = Money.new(3500, "USD") # $35.00
|
137
|
+
# item.quantity = 1
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# # Not using a block.
|
141
|
+
# cart = ShoppingCart.new
|
142
|
+
#
|
143
|
+
# item = cart.create_item
|
144
|
+
# item.name = "Dry Food Pack"
|
145
|
+
# item.description = "A pack of highly nutritious..."
|
146
|
+
# item.unit_price = Money.new(3500, "USD") # $35.00
|
147
|
+
# item.quantity = 1
|
148
|
+
def create_item(&block)
|
149
|
+
item = Item.new(self)
|
150
|
+
@items << item
|
151
|
+
|
152
|
+
# Pass the newly generated item to the given block to set its attributes.
|
153
|
+
yield(item) if block_given?
|
154
|
+
|
155
|
+
return item
|
156
|
+
end
|
157
|
+
|
158
|
+
# Creates a new ShoppingCart object from a REXML::Element object.
|
159
|
+
def self.create_from_element(element, owner)
|
160
|
+
result = ShoppingCart.new(owner)
|
161
|
+
|
162
|
+
text = element.elements['cart-expiration/good-until-date'].text rescue nil
|
163
|
+
result.expires_at = Time.parse(text) unless text.nil?
|
164
|
+
|
165
|
+
data_element = element.elements['merchant-private-data']
|
166
|
+
value = PrivateDataParser.element_to_value(data_element) unless data_element.nil?
|
167
|
+
|
168
|
+
result.private_data = value unless value.nil?
|
169
|
+
|
170
|
+
element.elements.each('items/item') do |item_element|
|
171
|
+
result.items << Item.create_from_element(item_element, result)
|
172
|
+
end
|
173
|
+
|
174
|
+
return result
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# An Item object represents a line of goods in the shopping cart/receipt.
|
179
|
+
#
|
180
|
+
# You should never initialize them directly but use ShoppingCart#create_item instead.
|
181
|
+
#
|
182
|
+
# Note that you have to create/set the tax tables for the owner of the cart in which
|
183
|
+
# the item is before you can set the tax_table attribute.
|
184
|
+
class Item
|
185
|
+
# The cart that this item belongs to.
|
186
|
+
attr_reader :shopping_cart
|
187
|
+
|
188
|
+
# The name of the cart item (string, required).
|
189
|
+
attr_accessor :name
|
190
|
+
|
191
|
+
# The description of the cart item (string, required).
|
192
|
+
attr_accessor :description
|
193
|
+
|
194
|
+
# The price for one unit of the given good (Money instance, required).
|
195
|
+
attr_reader :unit_price
|
196
|
+
|
197
|
+
# Sets the price for one unit of goods described by this item. money must respond to
|
198
|
+
# :cents and :currency as the Money class does.
|
199
|
+
def unit_price=(money)
|
200
|
+
if not (money.respond_to?(:cents) and money.respond_to?(:currency)) then
|
201
|
+
raise "Invalid price - does not respond to :cents and :currency - #{money.inspect}."
|
202
|
+
end
|
203
|
+
|
204
|
+
@unit_price = money
|
205
|
+
end
|
206
|
+
|
207
|
+
# The weigth of the cart item (Weight, required when carrier calculated
|
208
|
+
# shipping is used)
|
209
|
+
attr_reader :weight
|
210
|
+
|
211
|
+
# Sets the weight of this item
|
212
|
+
def weight=(weight)
|
213
|
+
raise "Invalid object type for weight" unless weight.kind_of? Weight
|
214
|
+
@weight = weight
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
# Number of units that this item represents (integer, required).
|
219
|
+
attr_accessor :quantity
|
220
|
+
|
221
|
+
# Optional string value that is used to store the item's id (defined by the merchant)
|
222
|
+
# in the cart. Serialized to <merchant-item-id> in XML. Displayed by Google Checkout.
|
223
|
+
attr_accessor :id
|
224
|
+
|
225
|
+
# Optional hash value that is used to store the item's id (defined by the merchant)
|
226
|
+
# in the cart. Serialized to <merchant-private-item-data> in XML. Not displayed by
|
227
|
+
# Google Checkout.
|
228
|
+
#
|
229
|
+
# Must be a Hash. See ShoppingCart#private_data on how the serialization to XML is
|
230
|
+
# done.
|
231
|
+
attr_reader :private_data
|
232
|
+
|
233
|
+
# Sets the private data for this item.
|
234
|
+
def private_data=(value)
|
235
|
+
raise "The given value #{value.inspect} is not a Hash!" unless value.kind_of?(Hash)
|
236
|
+
@private_data = value
|
237
|
+
end
|
238
|
+
|
239
|
+
# The tax table to use for this item. Optional.
|
240
|
+
attr_reader :tax_table
|
241
|
+
|
242
|
+
# Sets the tax table to use for this item. When you set this attribute using this
|
243
|
+
# method then the used table must already be added to the cart. Otherwise, a
|
244
|
+
# RuntimeError will be raised.
|
245
|
+
def tax_table=(table)
|
246
|
+
raise "The table #{table.inspect} is not in the item's cart yet!" unless shopping_cart.owner.tax_tables.include?(table)
|
247
|
+
|
248
|
+
@tax_table = table
|
249
|
+
end
|
250
|
+
|
251
|
+
# DigitalContent information for this item. Optional.
|
252
|
+
attr_reader :digital_content
|
253
|
+
|
254
|
+
def create_digital_content(digital_content=nil, &block)
|
255
|
+
|
256
|
+
if @digital_content.nil?
|
257
|
+
if digital_content.nil?
|
258
|
+
@digital_content = DigitalContent.new
|
259
|
+
else
|
260
|
+
@digital_content = digital_content
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
if block_given?
|
265
|
+
yield @digital_content
|
266
|
+
end
|
267
|
+
|
268
|
+
return @digital_content
|
269
|
+
end
|
270
|
+
|
271
|
+
# Subscription information for this item. Optional.
|
272
|
+
attr_reader :subscription
|
273
|
+
|
274
|
+
def create_subscription(subscription=nil, &block)
|
275
|
+
|
276
|
+
if @subscription.nil?
|
277
|
+
if subscription.nil?
|
278
|
+
@subscription = Subscription.new
|
279
|
+
else
|
280
|
+
@subscription = subscription
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
if block_given?
|
285
|
+
yield @subscription
|
286
|
+
end
|
287
|
+
|
288
|
+
return @subscription
|
289
|
+
end
|
290
|
+
|
291
|
+
# Create a new Item in the given Cart. You should not instantize this class directly
|
292
|
+
# but use Cart#create_item instead.
|
293
|
+
def initialize(shopping_cart)
|
294
|
+
@shopping_cart = shopping_cart
|
295
|
+
end
|
296
|
+
|
297
|
+
# Creates a new Item object from a REXML::Element object.
|
298
|
+
def self.create_from_element(element, shopping_cart)
|
299
|
+
result = Item.new(shopping_cart)
|
300
|
+
|
301
|
+
result.name = element.elements['item-name'].text
|
302
|
+
result.description = element.elements['item-description'].text
|
303
|
+
result.quantity = element.elements['quantity'].text.to_i
|
304
|
+
result.id = element.elements['merchant-item-id'].text rescue nil
|
305
|
+
|
306
|
+
weight_element = element.elements['item-weight']
|
307
|
+
if not weight_element.nil?
|
308
|
+
result.weight = Weight.create_from_element(weight_element)
|
309
|
+
end
|
310
|
+
|
311
|
+
data_element = element.elements['merchant-private-item-data']
|
312
|
+
if not data_element.nil? then
|
313
|
+
value = PrivateDataParser.element_to_value(data_element)
|
314
|
+
result.private_data = value unless value.nil?
|
315
|
+
end
|
316
|
+
|
317
|
+
table_selector = element.elements['tax-table-selector'].text rescue nil
|
318
|
+
if not table_selector.nil? then
|
319
|
+
result.tax_table = shopping_cart.owner.tax_tables.find {|table| table.name == table_selector }
|
320
|
+
end
|
321
|
+
|
322
|
+
unit_price = (BigDecimal.new(element.elements['unit-price'].text) * 100).to_i
|
323
|
+
unit_price_currency = element.elements['unit-price'].attributes['currency']
|
324
|
+
result.unit_price = Money.new(unit_price, unit_price_currency)
|
325
|
+
|
326
|
+
digital_content_element = element.elements['digital-content']
|
327
|
+
if not digital_content_element.nil?
|
328
|
+
result.create_digital_content(DigitalContent.create_from_element(digital_content_element))
|
329
|
+
end
|
330
|
+
|
331
|
+
return result
|
332
|
+
end
|
333
|
+
|
334
|
+
# A DigitalContent item represents the information relating to online delivery of digital items
|
335
|
+
#
|
336
|
+
# You should never initialize it directly but use Item#digital_content instead
|
337
|
+
#
|
338
|
+
# See http://code.google.com/apis/checkout/developer/Google_Checkout_Digital_Delivery.html
|
339
|
+
# for information on Google Checkout's idea of digital content.
|
340
|
+
#
|
341
|
+
# item.digital_content do |dc|
|
342
|
+
# dc.optimistic!
|
343
|
+
# dc.description = %{Here's some information on how to get your content}
|
344
|
+
# end
|
345
|
+
class DigitalContent
|
346
|
+
|
347
|
+
# Constants for display-disposition
|
348
|
+
OPTIMISTIC = 'OPTIMISTIC'
|
349
|
+
PESSIMISTIC = 'PESSIMISTIC'
|
350
|
+
|
351
|
+
# A description of how the user should access the digital content
|
352
|
+
# after completing the order (string, required for description-based
|
353
|
+
# delivery, otherwise optional)
|
354
|
+
attr_accessor :description
|
355
|
+
|
356
|
+
# Either 'OPTIMISTIC' or 'PESSIMISTIC'. If OPTIMISTIC, then Google
|
357
|
+
# will display instructions for accessing the digital content as soon
|
358
|
+
#as the buyer confirms the order. Optional, but default is PESSIMISTIC
|
359
|
+
attr_reader :display_disposition
|
360
|
+
|
361
|
+
def display_disposition=(disposition)
|
362
|
+
raise "display_disposition can only be set to PESSIMISTIC or OPTIMISTIC" unless disposition == OPTIMISTIC || disposition == PESSIMISTIC
|
363
|
+
@display_disposition = disposition
|
364
|
+
end
|
365
|
+
|
366
|
+
# A boolean identifying whether email delivery is used for this item.
|
367
|
+
attr_accessor :email_delivery
|
368
|
+
|
369
|
+
# A key required by the user to access this digital content after completing the order (string, optional)
|
370
|
+
attr_accessor :key
|
371
|
+
|
372
|
+
# A URL required by the user to access this digital content after completing the order (string, optional)
|
373
|
+
attr_accessor :url
|
374
|
+
|
375
|
+
def initialize
|
376
|
+
@display_disposition = PESSIMISTIC
|
377
|
+
end
|
378
|
+
|
379
|
+
# Creates a new DigitalContent object from a REXML::Element object
|
380
|
+
def self.create_from_element(element)
|
381
|
+
result = DigitalContent.new
|
382
|
+
result.description = element.elements['description'].text rescue nil
|
383
|
+
result.display_disposition = element.elements['display-disposition'].text rescue nil
|
384
|
+
result.email_delivery = element.elements['email-delivery'].text rescue nil # TODO need to convert to boolean?
|
385
|
+
result.key = element.elements['key'].text rescue nil
|
386
|
+
result.url = element.elements['url'].text rescue nil
|
387
|
+
return result
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
class Subscription
|
392
|
+
|
393
|
+
# Constants for period
|
394
|
+
DAILY = 'DAILY'
|
395
|
+
WEEKLY = 'WEEKLY'
|
396
|
+
SEMI_MONTHLY = 'SEMI_MONTHLY'
|
397
|
+
MONTHLY = 'MONTHLY'
|
398
|
+
EVERY_TWO_MONTHS = 'EVERY_TWO_MONTHS'
|
399
|
+
QUARTERLY = 'QUARTERLY'
|
400
|
+
YEARLY = 'YEARLY'
|
401
|
+
|
402
|
+
# Constants for type
|
403
|
+
MERCHANT = 'merchant'
|
404
|
+
GOOGLE = 'google'
|
405
|
+
|
406
|
+
# Optional. The no-charge-after attribute specifies the latest date and time that
|
407
|
+
# you can charge the customer for the subscription. This element can help you to
|
408
|
+
# ensure that you do not overcharge your customers.
|
409
|
+
attr_accessor :no_charge_after
|
410
|
+
|
411
|
+
# Required. The period attribute specifies how frequently you will charge the
|
412
|
+
# customer for the subscription. Valid values for this attribute are DAILY,
|
413
|
+
# WEEKLY, SEMI_MONTHLY, MONTHLY, EVERY_TWO_MONTHS, QUARTERLY, and YEARLY.
|
414
|
+
attr_reader :period
|
415
|
+
|
416
|
+
def period=(period)
|
417
|
+
unless [DAILY, WEEKLY, SEMI_MONTHLY, MONTHLY, EVERY_TWO_MONTHS, QUARTERLY, YEARLY].include?(period)
|
418
|
+
raise "period can only be set to DAILY, WEEKLY, SEMI_MONTHLY, MONTHLY, EVERY_TWO_MONTHS, QUARTERLY, or YEARLY"
|
419
|
+
end
|
420
|
+
@period = period
|
421
|
+
end
|
422
|
+
|
423
|
+
# Optional. The start-date attribute specifies the date that the subscription's
|
424
|
+
# recurrence period will begin. Like all dates in Checkout, this is in ISO 8601
|
425
|
+
# format. If you set the <unit-price> tag's value to a nonzero value, then the
|
426
|
+
# start-date for the subscription will automatically be set to the time that is
|
427
|
+
# exactly one recurrence period after the order is placed.
|
428
|
+
attr_accessor :start_date
|
429
|
+
|
430
|
+
# Required. The type attribute identifies the type of subscription that you are
|
431
|
+
# creating. The valid values for this attribute are merchant and google, and this
|
432
|
+
# specifies who handles the recurrences. The merchant value specifies
|
433
|
+
# Merchant-Handled recurrences, and the google value specifies Google-Handled
|
434
|
+
# recurrences.
|
435
|
+
attr_reader :type
|
436
|
+
|
437
|
+
def type=(type)
|
438
|
+
unless [MERCHANT, GOOGLE].include?(type)
|
439
|
+
raise "type can only be set to MERCHANT or GOOGLE"
|
440
|
+
end
|
441
|
+
@type = type
|
442
|
+
end
|
443
|
+
|
444
|
+
# Container for payments
|
445
|
+
attr_reader :payments
|
446
|
+
|
447
|
+
def add_payment(&block)
|
448
|
+
payment = SubscriptionPayment.new(self)
|
449
|
+
@payments << payment
|
450
|
+
|
451
|
+
# Pass the newly generated payment to the given block to set its attributes.
|
452
|
+
yield(payment) if block_given?
|
453
|
+
|
454
|
+
return payment
|
455
|
+
end
|
456
|
+
|
457
|
+
# Container for recurrent items
|
458
|
+
attr_reader :recurrent_items
|
459
|
+
|
460
|
+
def add_recurrent_item(&block)
|
461
|
+
item = RecurrentItem.new(self)
|
462
|
+
@recurrent_items << item
|
463
|
+
|
464
|
+
# Pass the newly generated item to the given block to set its attributes.
|
465
|
+
yield(item) if block_given?
|
466
|
+
|
467
|
+
return item
|
468
|
+
end
|
469
|
+
|
470
|
+
def initialize
|
471
|
+
@payments = []
|
472
|
+
@recurrent_items = []
|
473
|
+
end
|
474
|
+
|
475
|
+
def self.create_from_element(element)
|
476
|
+
result = Subscription.new
|
477
|
+
result.no_charge_after = Time.iso8601(element.attributes['no-charge-after']) rescue nil
|
478
|
+
result.period = element.attributes['period'] rescue nil
|
479
|
+
result.start_date = Time.iso8601(element.attributes['start-date']) rescue nil
|
480
|
+
result.type = element.attributes['type'] rescue nil
|
481
|
+
|
482
|
+
element.elements['payments/subscription-payment'].each do |payment_element|
|
483
|
+
result.payments << SubscriptionPayment.create_from_element(subscription, payment_element)
|
484
|
+
end
|
485
|
+
|
486
|
+
element.elements['recurrent-item'].each do |item_element|
|
487
|
+
result.recurrent_items << Item.create_from_element(item_element)
|
488
|
+
end
|
489
|
+
|
490
|
+
return result
|
491
|
+
end
|
492
|
+
|
493
|
+
class SubscriptionPayment
|
494
|
+
|
495
|
+
attr_accessor :subscription
|
496
|
+
|
497
|
+
# Optional. The times attribute indicates how many times you will charge the
|
498
|
+
# customer for a defined subscription payment. A subscription may have multiple
|
499
|
+
# payment schedules, and the times attribute lets you indicate how many times
|
500
|
+
# each charge will be assessed. For example, you might charge the customer a
|
501
|
+
# reduced rate for the first three months of a subscription and then charge the
|
502
|
+
# standard rate each month thereafter.
|
503
|
+
attr_accessor :times
|
504
|
+
|
505
|
+
# The maximum amount that you will be allowed to charge the customer, including
|
506
|
+
# tax, for all recurrences (Money instance, required).
|
507
|
+
attr_reader :maximum_charge
|
508
|
+
|
509
|
+
def initialize(subscription)
|
510
|
+
@subscription = subscription
|
511
|
+
end
|
512
|
+
|
513
|
+
# Sets the maximum charge for this subscription payment. money must respond to
|
514
|
+
# :cents and :currency as the Money class does.
|
515
|
+
def maximum_charge=(money)
|
516
|
+
if not (money.respond_to?(:cents) and money.respond_to?(:currency)) then
|
517
|
+
raise "Invalid price - does not respond to :cents and :currency - #{money.inspect}."
|
518
|
+
end
|
519
|
+
|
520
|
+
@maximum_charge = money
|
521
|
+
end
|
522
|
+
|
523
|
+
def self.create_from_element(subscription, element)
|
524
|
+
result = SubscriptionPayment.new
|
525
|
+
result.subscription = subscription
|
526
|
+
result.times = element.attributes['times'].to_i rescue nil
|
527
|
+
|
528
|
+
maximum_charge = (BigDecimal.new(element.elements['maximum-charge'].text) * 100).to_i
|
529
|
+
maximum_charge_currency = element.elements['maximum-charge'].attributes['currency']
|
530
|
+
result.maximum_charge = Money.new(maximum_charge, maximum_charge_currency)
|
531
|
+
|
532
|
+
return result
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
class RecurrentItem < Item
|
537
|
+
|
538
|
+
attr_accessor :subscription
|
539
|
+
|
540
|
+
def initialize(subscription)
|
541
|
+
@subscription = subscription
|
542
|
+
end
|
543
|
+
|
544
|
+
def self.create_from_element(element, subscription)
|
545
|
+
item = super(element, nil)
|
546
|
+
|
547
|
+
result = RecurrentItem.new(subscription)
|
548
|
+
result.description = item.description
|
549
|
+
result.digital_content = item.digital_content
|
550
|
+
result.id = item.id
|
551
|
+
result.name = item.name
|
552
|
+
result.private_data = item.private_data
|
553
|
+
result.quantity = item.quantity
|
554
|
+
result.tax_table = item.tax_table
|
555
|
+
result.unit_price = item.unit_price
|
556
|
+
result.weight = item.weight
|
557
|
+
|
558
|
+
return result
|
559
|
+
end
|
560
|
+
|
561
|
+
end
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
# A TaxTable is an ordered array of TaxRule objects. You should create the TaxRule
|
566
|
+
# instances using #create_rule
|
567
|
+
#
|
568
|
+
# You must set up a tax table factory and should only create tax tables from within
|
569
|
+
# its temporal factory method as described in the class documentation of Frontend.
|
570
|
+
#
|
571
|
+
# Each tax table must have one or more tax rules.
|
572
|
+
#
|
573
|
+
# === Example
|
574
|
+
#
|
575
|
+
# include Google4R::Checkout
|
576
|
+
#
|
577
|
+
# tax_free_table = TaxTable.new(false)
|
578
|
+
# tax_free_table.name = "default table"
|
579
|
+
# tax_free_table.create_rule do |rule|
|
580
|
+
# rule.area = UsCountryArea.new(UsCountryArea::ALL)
|
581
|
+
# rule.rate = 0.0
|
582
|
+
# end
|
583
|
+
class TaxTable
|
584
|
+
# The name of this tax table (string, required).
|
585
|
+
attr_accessor :name
|
586
|
+
|
587
|
+
# An Array of the TaxRule objects that this TaxTable contains. Use #create_rule do
|
588
|
+
# add to this Array but do not change it directly.
|
589
|
+
attr_reader :rules
|
590
|
+
|
591
|
+
# Boolean, true iff the table's standalone attribute is to be set to "true".
|
592
|
+
attr_reader :standalone
|
593
|
+
|
594
|
+
# indicates whether tax for the order is calculated using a special process. default "false"
|
595
|
+
attr_accessor :merchant_calculated
|
596
|
+
|
597
|
+
def initialize(standalone)
|
598
|
+
@rules = Array.new
|
599
|
+
|
600
|
+
@standalone = standalone
|
601
|
+
@merchant_calculated = false
|
602
|
+
end
|
603
|
+
|
604
|
+
# Use this method to add a new TaxRule to the table. If you use a block with
|
605
|
+
# this method then the block will called with the newly created rule for the
|
606
|
+
# parameter. The method will return the new rule in any case.
|
607
|
+
def create_rule(&block)
|
608
|
+
rule = TaxRule.new(self)
|
609
|
+
@rules << rule
|
610
|
+
|
611
|
+
# Pass the newly generated rule to the given block to set its attributes.
|
612
|
+
yield(rule) if block_given?
|
613
|
+
|
614
|
+
return rule
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
618
|
+
# A TaxRule specifies which taxes to apply in which area. Have a look at the "Google
|
619
|
+
# Checkout documentation" [http://code.google.com/apis/checkout/developer/index.html#specifying_tax_info]
|
620
|
+
# for more information.
|
621
|
+
class TaxRule
|
622
|
+
# The table this rule belongs to.
|
623
|
+
attr_reader :table
|
624
|
+
|
625
|
+
# The tax rate for this rule (double, required).
|
626
|
+
attr_accessor :rate
|
627
|
+
|
628
|
+
# The area where this tax rule applies (Area subclass instance, required). Serialized
|
629
|
+
# to <tax-area> in XML.
|
630
|
+
attr_accessor :area
|
631
|
+
|
632
|
+
# If shipping should be taxed with this tax rule (boolean, defaults to false)
|
633
|
+
attr_accessor :shipping_taxed
|
634
|
+
|
635
|
+
# Creates a new TaxRule in the given TaxTable. Do no call this method yourself
|
636
|
+
# but use TaxTable#create_rule instead!
|
637
|
+
def initialize(table)
|
638
|
+
@table = table
|
639
|
+
@shipping_taxed = false
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
# Abstract class for areas that are used to specify a tax area. Do not use this class
|
644
|
+
# but only its subclasses.
|
645
|
+
class Area
|
646
|
+
# Mark this class as abstract by throwing a RuntimeError on initialization.
|
647
|
+
def initialize #:nodoc:
|
648
|
+
raise "Do not use the abstract class Google::Checkout::Area!"
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
# Instances of UsZipArea represent areas specified by US ZIPs and ZIP patterns.
|
653
|
+
class UsZipArea < Area
|
654
|
+
# The pattern for this ZIP area.
|
655
|
+
attr_accessor :pattern
|
656
|
+
|
657
|
+
# You can optionally initialize the Area with its value.
|
658
|
+
def initialize(pattern=nil)
|
659
|
+
self.pattern = pattern unless pattern.nil?
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
# Instances of WorldArea represent a tax area that applies globally.
|
664
|
+
class WorldArea < Area
|
665
|
+
def initialize
|
666
|
+
end
|
667
|
+
end
|
668
|
+
|
669
|
+
# Instances of PostalArea represent a geographical region somewhere in the world.
|
670
|
+
class PostalArea < Area
|
671
|
+
|
672
|
+
# String; The two-letter ISO 3166 country code.
|
673
|
+
attr_accessor :country_code
|
674
|
+
|
675
|
+
# String; Postal code or a range of postal codes for a specific country. To specify a
|
676
|
+
# range of postal codes, use an asterisk as a wildcard operator. For example,
|
677
|
+
# you can provide a postal_code_pattern value of "SW*" to indicate that a shipping
|
678
|
+
# option is available or a tax rule applies in any postal code beginning with the
|
679
|
+
# characters SW.
|
680
|
+
#
|
681
|
+
# === Example
|
682
|
+
#
|
683
|
+
# area = PostalArea.new('DE')
|
684
|
+
# area.postal_code_pattern = '10*'
|
685
|
+
attr_accessor :postal_code_pattern
|
686
|
+
|
687
|
+
# === Parameters
|
688
|
+
#
|
689
|
+
# country_code should be a two-letter ISO 3166 country code
|
690
|
+
# postal_code_pattern should be a full or partial postcode string, using * as a wildcard
|
691
|
+
def initialize(country_code=nil, postal_code_pattern=nil)
|
692
|
+
@country_code = country_code
|
693
|
+
@postal_code_pattern = postal_code_pattern
|
694
|
+
end
|
695
|
+
end
|
696
|
+
|
697
|
+
# Instances of UsStateArea represent states in the US.
|
698
|
+
class UsStateArea < Area
|
699
|
+
# The two-letter code of the US state.
|
700
|
+
attr_reader :state
|
701
|
+
|
702
|
+
# You can optionally initialize the Area with its value.
|
703
|
+
def initialize(state=nil)
|
704
|
+
@state = state unless state.nil?
|
705
|
+
end
|
706
|
+
|
707
|
+
# Writer for the state attribute. value must match /^[A-Z]{2,2}$/.
|
708
|
+
def state=(value)
|
709
|
+
raise "Invalid US state: #{value}" unless value =~ /^[A-Z]{2,2}$/
|
710
|
+
@state = value
|
711
|
+
end
|
712
|
+
end
|
713
|
+
|
714
|
+
# Instances of UsCountryArea identify a region within the US.
|
715
|
+
class UsCountryArea < Area
|
716
|
+
CONTINENTAL_48 = "CONTINENTAL_48".freeze
|
717
|
+
FULL_50_STATES = "FULL_50_STATES".freeze
|
718
|
+
ALL = "ALL".freeze
|
719
|
+
|
720
|
+
# The area that is specified with this UsCountryArea (required). Can be
|
721
|
+
# one of UsCountryArea::CONTINENTAL_48, UsCountryArea::FULL_50_STATES
|
722
|
+
# and UsCountryArea::ALL.
|
723
|
+
# See the Google Checkout API for information on these values.
|
724
|
+
attr_reader :area
|
725
|
+
|
726
|
+
# You can optionally initialize the Area with its value.
|
727
|
+
def initialize(area=nil)
|
728
|
+
self.area = area unless area.nil?
|
729
|
+
end
|
730
|
+
|
731
|
+
# Writer for the area attribute. value must be one of CONTINENTAL_48,
|
732
|
+
# FULL_50_STATES and ALL
|
733
|
+
def area=(value)
|
734
|
+
raise "Invalid area :#{value}!" unless [ CONTINENTAL_48, FULL_50_STATES, ALL ].include?(value)
|
735
|
+
@area = value
|
736
|
+
end
|
737
|
+
end
|
738
|
+
|
739
|
+
# Abstract class for delivery methods
|
740
|
+
class DeliveryMethod
|
741
|
+
# The name of the shipping method (string, required).
|
742
|
+
attr_accessor :name
|
743
|
+
|
744
|
+
# The price of the shipping method (Money instance, required).
|
745
|
+
attr_reader :price
|
746
|
+
|
747
|
+
# Sets the cost for this shipping method. money must respond to :cents and :currency
|
748
|
+
# as Money objects would.
|
749
|
+
def price=(money)
|
750
|
+
if not (money.respond_to?(:cents) and money.respond_to?(:currency)) then
|
751
|
+
raise "Invalid cost - does not respond to :cents and :currency - #{money.inspect}."
|
752
|
+
end
|
753
|
+
|
754
|
+
@price = money
|
755
|
+
end
|
756
|
+
|
757
|
+
# Mark this class as abstract by throwing a RuntimeError on initialization.
|
758
|
+
def initialize
|
759
|
+
raise "Do not use the abstract class Google::Checkout::ShippingMethod!"
|
760
|
+
end
|
761
|
+
end
|
762
|
+
|
763
|
+
# Abstract class for shipping methods. Do not use this class directly but only
|
764
|
+
# one of its subclasses.
|
765
|
+
class ShippingMethod < DeliveryMethod
|
766
|
+
# An Array of allowed areas for shipping-restrictions of this shipping instance. Use
|
767
|
+
# #create_allowed_area to add to this area but do not change it directly.
|
768
|
+
attr_reader :shipping_restrictions_allowed_areas
|
769
|
+
|
770
|
+
# An Array of excluded areas for shipping-restrictions of this shipping instance. Use
|
771
|
+
# #create_excluded_area to add to this area but do not change it directly.
|
772
|
+
attr_reader :shipping_restrictions_excluded_areas
|
773
|
+
|
774
|
+
def initialize
|
775
|
+
@shipping_restrictions_allowed_areas = Array.new
|
776
|
+
@shipping_restrictions_excluded_areas = Array.new
|
777
|
+
end
|
778
|
+
|
779
|
+
# This method create a new instance of subclass of Area and put it
|
780
|
+
# in the array determined by the two symbols provided. The valid
|
781
|
+
# symbols for the first two parameters are:
|
782
|
+
#
|
783
|
+
# type : :shipping_restrictions, :address_filters
|
784
|
+
# areas : :allowed_areas, :excluded_areas
|
785
|
+
#
|
786
|
+
# The third parameter clazz is used to specify the type of
|
787
|
+
# Area you want to create. It can be one
|
788
|
+
# of { PostalArea, UsCountryArea, UsStateArea, UsZipArea, WorldArea }.
|
789
|
+
#
|
790
|
+
# Raises a RuntimeError if the parameter clazz is invalid.
|
791
|
+
#
|
792
|
+
# If you passed a block (preferred) then the block is called
|
793
|
+
# with the Area as the only parameter.
|
794
|
+
#
|
795
|
+
# === Example
|
796
|
+
#
|
797
|
+
# method = MerchantCalculatedShipping.new
|
798
|
+
# method.create_area(:shipping_restrictions, :allowed_areas, UsCountryArea) do |area|
|
799
|
+
# area.area = UsCountryArea::ALL
|
800
|
+
# end
|
801
|
+
def create_area(type, areas, clazz, &block)
|
802
|
+
areas_array_name = "@#{type.to_s + '_' + areas.to_s}"
|
803
|
+
areas = instance_variable_get(areas_array_name)
|
804
|
+
raise "Undefined instance variable: #{areas_array_name}" unless areas.nil? == false
|
805
|
+
raise "Invalid Area class: #{clazz}!" unless [ PostalArea, UsCountryArea, UsStateArea, UsZipArea, WorldArea ].include?(clazz)
|
806
|
+
area = clazz.new
|
807
|
+
areas << area
|
808
|
+
|
809
|
+
yield(area) if block_given?
|
810
|
+
|
811
|
+
return area
|
812
|
+
end
|
813
|
+
|
814
|
+
# Creates a new Area, adds it to the internal list of allowed areas for shipping
|
815
|
+
# restrictions. If you passed a block (preferred) then the block is called
|
816
|
+
# with the Area as the only parameter.
|
817
|
+
#
|
818
|
+
# The area to be created depends on the given parameter clazz. It can be one
|
819
|
+
# of { PostalArea, UsCountryArea, UsStateArea, UsZipArea, WorldArea }.
|
820
|
+
#
|
821
|
+
# Raises a RuntimeError if the parameter clazz is invalid.
|
822
|
+
#
|
823
|
+
# === Example
|
824
|
+
#
|
825
|
+
# method = FlatRateShipping.new
|
826
|
+
# method.create_allowed_area(UsCountryArea) do |area|
|
827
|
+
# area.area = UsCountryArea::ALL
|
828
|
+
# end
|
829
|
+
def create_allowed_area(clazz, &block)
|
830
|
+
return create_area(:shipping_restrictions, :allowed_areas, clazz, &block)
|
831
|
+
end
|
832
|
+
|
833
|
+
# Creates a new Area, adds it to the internal list of excluded areas for shipping
|
834
|
+
# restrictions. If you passed a block (preferred) then the block is called
|
835
|
+
# with the Area as the only parameter. The created area is returned in any case.
|
836
|
+
#
|
837
|
+
# The area to be created depends on the given parameter clazz. It can be one
|
838
|
+
# of { PostalArea, UsCountryArea, UsStateArea, UsZipArea, WorldArea }.
|
839
|
+
#
|
840
|
+
# Raises a RuntimeError if the parameter clazz is invalid.
|
841
|
+
#
|
842
|
+
# === Example
|
843
|
+
#
|
844
|
+
# method = FlatRateShipping.new
|
845
|
+
# method.create_excluded_area(UsCountryArea) do |area|
|
846
|
+
# area.area = UsCountryArea::ALL
|
847
|
+
# end
|
848
|
+
def create_excluded_area(clazz, &block)
|
849
|
+
return create_area(:shipping_restrictions, :excluded_areas, clazz, &block)
|
850
|
+
end
|
851
|
+
|
852
|
+
alias :create_shipping_restrictions_allowed_area :create_allowed_area
|
853
|
+
alias :create_shipping_restrictions_excluded_area :create_excluded_area
|
854
|
+
end
|
855
|
+
|
856
|
+
# A class that represents the "pickup" shipping method.
|
857
|
+
class PickupShipping < DeliveryMethod
|
858
|
+
def initialize
|
859
|
+
end
|
860
|
+
end
|
861
|
+
|
862
|
+
# A class that represents the "flat_rate" shipping method.
|
863
|
+
class FlatRateShipping < ShippingMethod
|
864
|
+
# (boolean, optional, default true)
|
865
|
+
attr_accessor :shipping_restrictions_allow_us_po_box
|
866
|
+
|
867
|
+
def initialize
|
868
|
+
super
|
869
|
+
end
|
870
|
+
end
|
871
|
+
|
872
|
+
# A class that represents the "merchant-calculated" shipping method
|
873
|
+
class MerchantCalculatedShipping < ShippingMethod
|
874
|
+
|
875
|
+
# An Array of allowed areas for address-filters of this shipping instance. Use
|
876
|
+
# #create_allowed_area to add to this area but do not change it directly.
|
877
|
+
attr_reader :address_filters_allowed_areas
|
878
|
+
|
879
|
+
# An Array of excluded areas for address-filters of this shipping instance. Use
|
880
|
+
# #create_excluded_area to add to this area but do not change it directly.
|
881
|
+
attr_reader :address_filters_excluded_areas
|
882
|
+
|
883
|
+
# (boolean, optional, default true)
|
884
|
+
attr_accessor :address_filters_allow_us_po_box
|
885
|
+
|
886
|
+
# (boolean, optional, default true)
|
887
|
+
attr_accessor :shipping_restrictions_allow_us_po_box
|
888
|
+
|
889
|
+
def initialize
|
890
|
+
super
|
891
|
+
@address_filters_allowed_areas = Array.new
|
892
|
+
@address_filters_excluded_areas = Array.new
|
893
|
+
end
|
894
|
+
|
895
|
+
# Creates a new Area, adds it to the internal list of allowed areas for
|
896
|
+
# address filters. If you passed a block (preferred) then the block is
|
897
|
+
# called with the Area as the only parameter.
|
898
|
+
#
|
899
|
+
# The area to be created depends on the given parameter clazz. It can be one
|
900
|
+
# of { PostalArea, UsCountryArea, UsStateArea, UsZipArea, WorldArea }.
|
901
|
+
#
|
902
|
+
# Raises a RuntimeError if the parameter clazz is invalid.
|
903
|
+
#
|
904
|
+
# === Example
|
905
|
+
#
|
906
|
+
# method = FlatRateShipping.new
|
907
|
+
# method.create_address_filters_allowed_area(UsCountryArea) do |area|
|
908
|
+
# area.area = UsCountryArea::ALL
|
909
|
+
# end
|
910
|
+
def create_address_filters_allowed_area(clazz, &block)
|
911
|
+
return create_area(:address_filters, :allowed_areas, clazz, &block)
|
912
|
+
end
|
913
|
+
|
914
|
+
# Creates a new Area, adds it to the internal list of excluded areas for
|
915
|
+
# address filters. If you passed a block (preferred) then the block is
|
916
|
+
# called with the Area as the only parameter.
|
917
|
+
#
|
918
|
+
# The area to be created depends on the given parameter clazz. It can be one
|
919
|
+
# of { PostalArea, UsCountryArea, UsStateArea, UsZipArea, WorldArea }.
|
920
|
+
#
|
921
|
+
# Raises a RuntimeError if the parameter clazz is invalid.
|
922
|
+
#
|
923
|
+
# === Example
|
924
|
+
#
|
925
|
+
# method = FlatRateShipping.new
|
926
|
+
# method.create_address_filters_excluded_area(UsCountryArea) do |area|
|
927
|
+
# area.area = UsCountryArea::ALL
|
928
|
+
# end
|
929
|
+
def create_address_filters_excluded_area(clazz, &block)
|
930
|
+
return create_area(:address_filters, :excluded_areas, clazz, &block)
|
931
|
+
end
|
932
|
+
end
|
933
|
+
|
934
|
+
# A class that represents the "merchant-calculated" shipping method
|
935
|
+
class CarrierCalculatedShipping
|
936
|
+
# This encapsulates information about all of the shipping methods
|
937
|
+
# for which Google Checkout should obtain shipping costs.
|
938
|
+
attr_reader :carrier_calculated_shipping_options
|
939
|
+
|
940
|
+
# This encapsulates information about all of the packages that will be
|
941
|
+
# shipped to the buyer. At this time, merchants may only specify
|
942
|
+
# one package per order.
|
943
|
+
attr_reader :shipping_packages
|
944
|
+
|
945
|
+
def initialize()
|
946
|
+
@carrier_calculated_shipping_options = Array.new
|
947
|
+
@shipping_packages = Array.new
|
948
|
+
end
|
949
|
+
|
950
|
+
def create_carrier_calculated_shipping_option(&block)
|
951
|
+
option = CarrierCalculatedShippingOption.new(self)
|
952
|
+
@carrier_calculated_shipping_options << option
|
953
|
+
|
954
|
+
# Pass the newly generated rule to the given block to set its attributes.
|
955
|
+
yield(option) if block_given?
|
956
|
+
|
957
|
+
return option
|
958
|
+
end
|
959
|
+
|
960
|
+
def create_shipping_package(&block)
|
961
|
+
package = ShippingPackage.new(self)
|
962
|
+
@shipping_packages << package
|
963
|
+
|
964
|
+
# Pass the newly generated rule to the given block to set its attributes.
|
965
|
+
yield(package) if block_given?
|
966
|
+
|
967
|
+
return package
|
968
|
+
end
|
969
|
+
|
970
|
+
# Creates a new CarrierCalculatedShipping from the given
|
971
|
+
# REXML::Element instance.
|
972
|
+
# For testing only.
|
973
|
+
def create_from_element(element)
|
974
|
+
result = CarrierCalculatedShipping.new
|
975
|
+
element.elements.each('carrier-calculated-shipping-options/carrier-calculated-shipping-option') do |shipping_option_element|
|
976
|
+
result.carrier_calculated_shipping_options << CarrierCalculatedShippingOption.create_from_element(self, shipping_option_element)
|
977
|
+
end
|
978
|
+
element.elements.each('shipping-packages/shipping-package') do |shipping_package_element|
|
979
|
+
result.shipping_packages << ShippingPackage.create_from_element(self, shipping_package_element)
|
980
|
+
end
|
981
|
+
end
|
982
|
+
|
983
|
+
class CarrierCalculatedShippingOption < DeliveryMethod
|
984
|
+
# Constants for shipping company
|
985
|
+
FEDEX = 'FedEx'
|
986
|
+
UPS = 'UPS'
|
987
|
+
USPS = 'USPS'
|
988
|
+
|
989
|
+
# Constants for carrier pickup
|
990
|
+
DROP_OFF = 'DROP_OFF'
|
991
|
+
REGULAR_PICKUP = 'REGULAR_PICKUP'
|
992
|
+
SPECIAL_PICKUP = 'SPECIAL_PICKUP'
|
993
|
+
|
994
|
+
# The CarrierCalculatedShipping instance that this option belongs to.
|
995
|
+
attr_reader :carrier_calculated_shipping
|
996
|
+
|
997
|
+
# The name of the company that will ship the order.
|
998
|
+
# The only valid values for this tag are FedEx, UPS and USPS.
|
999
|
+
# (String, required)
|
1000
|
+
alias :shipping_company :name
|
1001
|
+
alias :shipping_company= :name=
|
1002
|
+
|
1003
|
+
# The shipping option that is being offered to the buyer
|
1004
|
+
attr_accessor :shipping_type
|
1005
|
+
|
1006
|
+
# This specifies how the package will be transferred from the merchant
|
1007
|
+
# to the shipper. Valid values for this tag are REGULAR_PICKUP,
|
1008
|
+
# SPECIAL_PICKUP and DROP_OFF. The default value for this tag is DROP_OFF.
|
1009
|
+
# (optional)
|
1010
|
+
attr_accessor :carrier_pickup
|
1011
|
+
|
1012
|
+
# The fixed charge that will be added to the total cost of an order
|
1013
|
+
# if the buyer selects the associated shipping option
|
1014
|
+
# (Money, optional)
|
1015
|
+
attr_accessor :additional_fixed_charge
|
1016
|
+
|
1017
|
+
# The percentage amount by which a carrier-calculated shipping rate
|
1018
|
+
# will be adjusted. The tag's value may be positive or negative.
|
1019
|
+
# (Float, optional)
|
1020
|
+
attr_accessor :additional_variable_charge_percent
|
1021
|
+
|
1022
|
+
def initialize(carrier_calculated_shipping)
|
1023
|
+
@carrier_calculated_shipping = carrier_calculated_shipping
|
1024
|
+
#@carrier_pickup = DROP_OFF
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
# Creates a new CarrierCalculatedShippingOption from the given
|
1028
|
+
# REXML::Element instance.
|
1029
|
+
# For testing only.
|
1030
|
+
def self.create_from_element(this_shipping, element)
|
1031
|
+
result = CarrierCalculatedShippingOption.new(this_shipping)
|
1032
|
+
result.shipping_company = element.elements['shipping-company'].text
|
1033
|
+
price = (BigDecimal.new(element.elements['price'].text) * 100).to_i
|
1034
|
+
price_currency = element.elements['price'].attributes['currency']
|
1035
|
+
result.price = Money.new(price, price_currency)
|
1036
|
+
result.shipping_type = element.elements['shipping-type']
|
1037
|
+
result.carrier_pickup = element.elements['carrier-pickup'] rescue nil
|
1038
|
+
result.additional_fixed_charge =
|
1039
|
+
element.elements['additional-fixed-charge'] rescue nil
|
1040
|
+
result.additional_variable_charge_percent =
|
1041
|
+
element.elements['additional-variable-charge-percent'] rescue nil
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
class ShippingPackage
|
1046
|
+
# Constants for delivery address category
|
1047
|
+
RESIDENTIAL = 'RESIDENTIAL'
|
1048
|
+
COMMERCIAL = 'COMMERCIAL'
|
1049
|
+
|
1050
|
+
# The CarrierCalculatedShipping instance that this package belongs to.
|
1051
|
+
attr_reader :carrier_calculated_shipping
|
1052
|
+
|
1053
|
+
# This contains information about the location from which an order
|
1054
|
+
# will be shipped. (AnonymousAddress)
|
1055
|
+
attr_accessor :ship_from
|
1056
|
+
|
1057
|
+
# This indicates whether the shipping method should be applied to
|
1058
|
+
# a residential or a commercial address. Valid values for this tag
|
1059
|
+
# are RESIDENTIAL and COMMERCIAL. (String, optional)
|
1060
|
+
attr_accessor :delivery_address_category
|
1061
|
+
|
1062
|
+
# This contains information about the height of the package being
|
1063
|
+
# shipped to the customer. (Google::Checktou::Dimension, optional)
|
1064
|
+
attr_accessor :height
|
1065
|
+
|
1066
|
+
# This contains information about the length of the package being
|
1067
|
+
# shipped to the customer. (Google::Checktou::Dimension, optional)
|
1068
|
+
attr_accessor :length
|
1069
|
+
|
1070
|
+
# This contains information about the width of the package being
|
1071
|
+
# shipped to the customer. (Google::Checktou::Dimension, optional)
|
1072
|
+
attr_accessor :width
|
1073
|
+
|
1074
|
+
def initialize(carrier_calculated_shipping)
|
1075
|
+
@carrier_calculated_shipping = carrier_calculated_shipping
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
# Creates a new ShippingPackage from the given REXML::Element instance.
|
1079
|
+
# For testing only.
|
1080
|
+
def self.create_from_element(this_shipping, element)
|
1081
|
+
result = ShippingPackage.new(this_shipping)
|
1082
|
+
result.ship_from = ShipFromAddress.create_from_element(element.elements['ship-from'])
|
1083
|
+
result.delivery_address_category = element.elements['delivery-address-category'].text rescue nil
|
1084
|
+
result.height = element.elements['height'].text rescue nil
|
1085
|
+
result.length = element.elements['length'].text rescue nil
|
1086
|
+
result.width = element.elements['width'].text rescue nil
|
1087
|
+
return result
|
1088
|
+
end
|
1089
|
+
end
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
# This is a base class for defining the unit of weight and dimension
|
1093
|
+
class Unit
|
1094
|
+
# This specifies the unit of measurement that corresponds to a shipping
|
1095
|
+
# package's length, width or height. The only valid value for
|
1096
|
+
# this attribute is IN.
|
1097
|
+
attr_accessor :unit
|
1098
|
+
|
1099
|
+
# This specifies the numeric value of a unit of measurement
|
1100
|
+
# corresponding to an item or a shipping package. (float)
|
1101
|
+
attr_accessor :value
|
1102
|
+
|
1103
|
+
def initialize
|
1104
|
+
raise "Google::Checkout::Unit is an abstract class!"
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
# Creates a new Unit from the given REXML::Element instance.
|
1108
|
+
def self.create_from_element(element)
|
1109
|
+
result = self.new(BigDecimal.new(element.attributes['value'].to_s))
|
1110
|
+
return result
|
1111
|
+
end
|
1112
|
+
end
|
1113
|
+
|
1114
|
+
# This defines package dimension
|
1115
|
+
class Dimension < Unit
|
1116
|
+
|
1117
|
+
# Constants for unit
|
1118
|
+
INCH = 'IN'
|
1119
|
+
|
1120
|
+
def initialize(value, unit=INCH)
|
1121
|
+
@unit = unit
|
1122
|
+
@value = BigDecimal.new(value.to_s)
|
1123
|
+
end
|
1124
|
+
end
|
1125
|
+
|
1126
|
+
# This defines item weight
|
1127
|
+
class Weight < Unit
|
1128
|
+
# Constants for unit
|
1129
|
+
LB = 'LB'
|
1130
|
+
|
1131
|
+
def initialize(value, unit=LB)
|
1132
|
+
@unit = unit
|
1133
|
+
@value = BigDecimal.new(value.to_s)
|
1134
|
+
end
|
1135
|
+
end
|
1136
|
+
|
1137
|
+
# This address is used in merchant calculation callback
|
1138
|
+
class AnonymousAddress
|
1139
|
+
|
1140
|
+
# The address ID (String)
|
1141
|
+
attr_accessor :address_id
|
1142
|
+
|
1143
|
+
# The buyer's city name (String).
|
1144
|
+
attr_accessor :city
|
1145
|
+
|
1146
|
+
# The buyers postal/zip code (String).
|
1147
|
+
attr_accessor :postal_code
|
1148
|
+
|
1149
|
+
# The buyer's geographical region (String).
|
1150
|
+
attr_accessor :region
|
1151
|
+
|
1152
|
+
# The buyer's country code (String, 2 chars, ISO 3166).
|
1153
|
+
attr_accessor :country_code
|
1154
|
+
|
1155
|
+
# Creates a new AnonymousAddress from the given REXML::Element instance.
|
1156
|
+
def self.create_from_element(element)
|
1157
|
+
result = AnonymousAddress.new
|
1158
|
+
|
1159
|
+
result.address_id = element.attributes['id']
|
1160
|
+
result.city = element.elements['city'].text
|
1161
|
+
result.country_code = element.elements['country-code'].text
|
1162
|
+
result.postal_code = element.elements['postal-code'].text
|
1163
|
+
result.region = element.elements['region'].text
|
1164
|
+
return result
|
1165
|
+
end
|
1166
|
+
end
|
1167
|
+
|
1168
|
+
# Address instances are used in NewOrderNotification objects for the buyer's billing
|
1169
|
+
# and buyer's shipping address.
|
1170
|
+
class Address < AnonymousAddress
|
1171
|
+
# Contact name (String, optional).
|
1172
|
+
attr_accessor :contact_name
|
1173
|
+
|
1174
|
+
# Second Address line (String).
|
1175
|
+
attr_accessor :address1
|
1176
|
+
|
1177
|
+
# Second Address line (String optional).
|
1178
|
+
attr_accessor :address2
|
1179
|
+
|
1180
|
+
# The buyer's city name (String).
|
1181
|
+
# attr_accessor :city
|
1182
|
+
# Now inherit from AnonymousAddress
|
1183
|
+
|
1184
|
+
# The buyer's company name (String; optional).
|
1185
|
+
attr_accessor :company_name
|
1186
|
+
|
1187
|
+
# The buyer's country code (String, 2 chars, ISO 3166).
|
1188
|
+
# attr_accessor :country_code
|
1189
|
+
# Now inherit from AnonymousAddress
|
1190
|
+
|
1191
|
+
# The buyer's email address (String; optional).
|
1192
|
+
attr_accessor :email
|
1193
|
+
|
1194
|
+
# The buyer's phone number (String; optional).
|
1195
|
+
attr_accessor :fax
|
1196
|
+
|
1197
|
+
# The buyer's phone number (String; Optional, can be enforced in CheckoutCommand).)
|
1198
|
+
attr_accessor :phone
|
1199
|
+
|
1200
|
+
# The buyers postal/zip code (String).
|
1201
|
+
# attr_accessor :postal_code
|
1202
|
+
# Now inherit from AnonymousAddress
|
1203
|
+
|
1204
|
+
|
1205
|
+
# The buyer's geographical region (String).
|
1206
|
+
# attr_accessor :region
|
1207
|
+
# Now inherit from AnonymousAddress
|
1208
|
+
|
1209
|
+
# Creates a new Address from the given REXML::Element instance.
|
1210
|
+
def self.create_from_element(element)
|
1211
|
+
result = Address.new
|
1212
|
+
|
1213
|
+
result.address1 = element.elements['address1'].text
|
1214
|
+
result.address2 = element.elements['address2'].text rescue nil
|
1215
|
+
result.city = element.elements['city'].text
|
1216
|
+
result.company_name = element.elements['company-name'].text rescue nil
|
1217
|
+
result.contact_name = element.elements['contact-name'].text rescue nil
|
1218
|
+
result.country_code = element.elements['country-code'].text
|
1219
|
+
result.email = element.elements['email'].text rescue nil
|
1220
|
+
result.fax = element.elements['fax'].text rescue nil
|
1221
|
+
result.phone = element.elements['phone'].text rescue nil
|
1222
|
+
result.postal_code = element.elements['postal-code'].text
|
1223
|
+
result.region = element.elements['region'].text
|
1224
|
+
|
1225
|
+
return result
|
1226
|
+
end
|
1227
|
+
end
|
1228
|
+
|
1229
|
+
# ItemInfo instances are used in Line-item shipping commands
|
1230
|
+
class ItemInfo
|
1231
|
+
# The merchant item id (String)
|
1232
|
+
attr_reader :merchant_item_id
|
1233
|
+
|
1234
|
+
# An array of tracking data for this item
|
1235
|
+
attr_reader :tracking_data_arr
|
1236
|
+
|
1237
|
+
def initialize(merchant_item_id)
|
1238
|
+
@merchant_item_id = merchant_item_id
|
1239
|
+
@tracking_data_arr = Array.new
|
1240
|
+
end
|
1241
|
+
|
1242
|
+
def create_tracking_data(carrier, tracking_number)
|
1243
|
+
tracking_data = TrackingData.new(carrier, tracking_number)
|
1244
|
+
@tracking_data_arr << tracking_data
|
1245
|
+
return tracking_data
|
1246
|
+
end
|
1247
|
+
end
|
1248
|
+
|
1249
|
+
# TrackingData instances are used in Line-item shipping commands
|
1250
|
+
class TrackingData
|
1251
|
+
# The name of the company responsible for shipping the item. Valid values
|
1252
|
+
# for this tag are DHL, FedEx, UPS, USPS and Other.
|
1253
|
+
attr_reader :carrier
|
1254
|
+
|
1255
|
+
# The shipper's tracking number that is associated with an order
|
1256
|
+
attr_reader :tracking_number
|
1257
|
+
|
1258
|
+
def initialize(carrier, tracking_number)
|
1259
|
+
@carrier = carrier.to_s
|
1260
|
+
@tracking_number = tracking_number.to_s
|
1261
|
+
end
|
1262
|
+
end
|
1263
|
+
|
1264
|
+
# ChargeFee instances are used in the ChargeAmountNotifications
|
1265
|
+
class ChargeFee
|
1266
|
+
# The flat portion of the fee (Money)
|
1267
|
+
attr_accessor :flat
|
1268
|
+
|
1269
|
+
# The percentage of the transaction value (Float)
|
1270
|
+
attr_accessor :percentage
|
1271
|
+
|
1272
|
+
# The total fee (Money)
|
1273
|
+
attr_accessor :total
|
1274
|
+
|
1275
|
+
def self.create_from_element(element)
|
1276
|
+
result = ChargeFee.new
|
1277
|
+
result.flat = Money.new(element.elements['flat'].text.to_f * 100, nil)
|
1278
|
+
result.percentage = element.elements['percentage'].text.to_f
|
1279
|
+
result.total = Money.new(element.elements['total'].text.to_f * 100, nil)
|
1280
|
+
result
|
1281
|
+
end
|
1282
|
+
end
|
1283
|
+
|
1284
|
+
# ParamaterizedUrl instances are used
|
1285
|
+
class ParameterizedUrl
|
1286
|
+
|
1287
|
+
# The third party conversion tracker URL
|
1288
|
+
attr_accessor :url
|
1289
|
+
|
1290
|
+
# Paramters passed to the third party conversion tracker - Read Only
|
1291
|
+
attr_reader :url_parameters
|
1292
|
+
|
1293
|
+
def initialize(url)
|
1294
|
+
@url = url.to_s
|
1295
|
+
@url_parameters = Array.new
|
1296
|
+
end
|
1297
|
+
|
1298
|
+
# UrlParameters can be created (recommended) using this method by passing in a hash
|
1299
|
+
# containing values for the :name of the parameter as is it to be provided to the third
|
1300
|
+
# party conversion tracker, and the :parameter_type that has a valued assigned by Google Checkout
|
1301
|
+
def create_url_parameter(opts)
|
1302
|
+
url_parameter = UrlParameter.new(self,opts)
|
1303
|
+
@url_parameters << url_parameter
|
1304
|
+
|
1305
|
+
return url_parameter
|
1306
|
+
end
|
1307
|
+
|
1308
|
+
end
|
1309
|
+
|
1310
|
+
# Url Paramaters that are available from the Google Checkout API that can be
|
1311
|
+
# passed to the third party conversion tracker
|
1312
|
+
#
|
1313
|
+
# UrlParameter objects require a parameter name, which is the name of the value to be
|
1314
|
+
# provided to the third party conversion tracker, and a parameter type which is
|
1315
|
+
# the name of the value, as assigned by Google Checkout.
|
1316
|
+
#
|
1317
|
+
# The parameter_type must be a string, and must be a valid type, as defined in the subsequant list
|
1318
|
+
# otherwise an Argument Error is thrown.
|
1319
|
+
#
|
1320
|
+
# The :name symbol must have an associated value, and be of the String class, other
|
1321
|
+
# an argument error will be thrown
|
1322
|
+
# Below is a list of defined types, as assigned by Google Checkout.
|
1323
|
+
#
|
1324
|
+
# buyer-id - A Google-assigned value that uniquely identifies a customer email address.
|
1325
|
+
# order-id - A Google-assigned value that uniquely identifies an order. This value is displayed in the Merchant Center for each order. If you have implemented the Notification API, you will also see this value in all Google Checkout notifications.
|
1326
|
+
# order-subtotal - The total cost for all of the items in the order including coupons and discounts but excluding taxes and shipping charges.
|
1327
|
+
# order-subtotal-plus-tax - The total cost for all of the items in the order, including taxes, coupons and discounts, but excluding shipping charges.
|
1328
|
+
# order-subtotal-plus-shipping - The total cost for all of the items in the order, including shipping charges, coupons and discounts, but excluding taxes.
|
1329
|
+
# order-total - The total cost for all of the items in the order, including taxes, shipping charges, coupons and discounts.
|
1330
|
+
# tax-amount - The total amount of taxes charged for an order.
|
1331
|
+
# shipping-amount - The shipping cost associated with an order.
|
1332
|
+
# coupon-amount - The total amount of all coupons factored into the order total.
|
1333
|
+
# billing-city - The city associated with the order's billing address.
|
1334
|
+
# billing-region - The U.S. state associated with the order's billing address.
|
1335
|
+
# billing-postal-code - The five-digit U.S. zip code associated with the order's billing address.
|
1336
|
+
# billing-country-code - The two-letter ISO 3166 country code associated with the order's billing address.
|
1337
|
+
# shipping-city - The city associated with the order's shipping address.
|
1338
|
+
# shipping-region - The U.S. state associated with the order's shipping address.
|
1339
|
+
# shipping-postal-code - The five-digit U.S. zip code associated with the order's shipping address.
|
1340
|
+
# shipping-country-code - The two-letter ISO 3166 country code associated with the order's shipping address.
|
1341
|
+
class UrlParameter
|
1342
|
+
attr_reader :parameterized_url,:name,:parameter_type
|
1343
|
+
|
1344
|
+
VALID_TYPES = ['buyer-id', 'order-id', 'order-subtotal', 'order-subtotal-plus-tax', 'order-subtotal-plus-shipping', 'order-total', 'tax-amount','shipping-amount', 'coupon-amount', 'billing-city', 'billing-region', 'billing-postal-code', 'billing-country-code', 'shipping-city', 'shipping-region', 'shipping-postal-code', 'shipping-country-code'].freeze
|
1345
|
+
|
1346
|
+
def initialize(parameterized_url,opts)
|
1347
|
+
raise(ArgumentError,"url-parameter type can only be #{VALID_TYPES.join(", ")}") unless VALID_TYPES.include?(opts[:type])
|
1348
|
+
raise(ArgumentError, "Missing or invalid parameter name") unless opts[:name].kind_of?(String)
|
1349
|
+
|
1350
|
+
@parameterized_url = parameterized_url
|
1351
|
+
@name = opts[:name]
|
1352
|
+
@parameter_type = opts[:type]
|
1353
|
+
end
|
1354
|
+
end
|
1355
|
+
|
1356
|
+
# financial_state
|
1357
|
+
# REVIEWING - Google Checkout is reviewing the order.
|
1358
|
+
# CHARGEABLE - The order is ready to be charged.
|
1359
|
+
# CHARGING - The order is being charged; you may not refund or cancel an order until is the charge is completed.
|
1360
|
+
# CHARGED - The order has been successfully charged; if the order was only partially charged, the buyer's account page will reflect the partial charge.
|
1361
|
+
# PAYMENT_DECLINED - The charge attempt failed.
|
1362
|
+
# CANCELLED - The seller canceled the order; an order's financial state cannot be changed after the order is canceled.
|
1363
|
+
# CANCELLED_BY_GOOGLE - Google canceled the order. Google may cancel orders due to a failed charge without a replacement credit card being provided within a set period of time or due to a failed risk check. If Google cancels an order, you will be notified of the reason the order was canceled in the <reason> tag of an <order-state-change-notification>.
|
1364
|
+
class FinancialState
|
1365
|
+
REVIEWING = 'REVIEWING'
|
1366
|
+
CHARGEABLE = 'CHARGEABLE'
|
1367
|
+
CHARGING = 'CHARGING'
|
1368
|
+
CHARGED = 'CHARGED'
|
1369
|
+
PAYMENT_DECLINED = 'PAYMENT_DECLINED'
|
1370
|
+
CANCELLED = 'CANCELLED'
|
1371
|
+
CANCELLED_BY_GOOGLE = 'CANCELLED_BY_GOOGLE'
|
1372
|
+
end
|
1373
|
+
|
1374
|
+
# fulfillment_state
|
1375
|
+
# NEW - The order has been received but not prepared for shipping.
|
1376
|
+
# PROCESSING - The order is being prepared for shipping.
|
1377
|
+
# DELIVERED - The seller has shipped the order.
|
1378
|
+
# WILL_NOT_DELIVER - The seller will not ship the order; this status is used for canceled orders.
|
1379
|
+
class FulfillmentState
|
1380
|
+
NEW = 'NEW'
|
1381
|
+
PROCESSING = 'PROCESSING'
|
1382
|
+
DELIVERED = 'DELIVERED'
|
1383
|
+
WILL_NOT_DELIVER = 'WILL_NOT_DELIVER'
|
1384
|
+
end
|
1385
|
+
end
|
1386
|
+
end
|