google4r-checkout 1.0.2 → 1.0.3
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 +16 -0
- data/lib/google4r/checkout/commands.rb +101 -61
- data/lib/google4r/checkout/frontend.rb +30 -0
- data/lib/google4r/checkout/merchant_calculation.rb +4 -0
- data/lib/google4r/checkout/notifications.rb +53 -129
- data/lib/google4r/checkout/shared.rb +382 -7
- data/lib/google4r/checkout/utils.rb +94 -0
- data/lib/google4r/checkout/xml_generation.rb +229 -17
- data/test/integration/checkout_command_test.rb +72 -11
- data/test/unit/backorder_items_command_test.rb +83 -0
- data/test/unit/cancel_items_command_test.rb +89 -0
- data/test/unit/carrier_calculated_shipping_test.rb +57 -0
- data/test/unit/checkout_command_test.rb +6 -1
- data/test/unit/checkout_command_xml_generator_test.rb +1 -0
- data/test/unit/command_test.rb +3 -2
- data/test/unit/digital_content_test.rb +105 -0
- data/test/unit/frontend_test.rb +70 -10
- data/test/unit/item_info_test.rb +69 -0
- data/test/unit/item_test.rb +13 -1
- data/test/unit/merchant_calculated_shipping_test.rb +39 -3
- data/test/unit/notification_acknowledgement_test.rb +25 -1
- data/test/unit/reset_items_shipping_information_command_test.rb +83 -0
- data/test/unit/return_items_command_test.rb +83 -0
- data/test/unit/ship_items_command_test.rb +101 -0
- data/test/unit/tracking_data_test.rb +54 -0
- metadata +13 -3
@@ -202,6 +202,17 @@ module Google4R #:nodoc:
|
|
202
202
|
@unit_price = money
|
203
203
|
end
|
204
204
|
|
205
|
+
# The weigth of the cart item (Weight, required when carrier calculated
|
206
|
+
# shipping is used)
|
207
|
+
attr_reader :weight
|
208
|
+
|
209
|
+
# Sets the weight of this item
|
210
|
+
def weight=(weight)
|
211
|
+
raise "Invalid object type for weight" unless weight.kind_of? Weight
|
212
|
+
@weight = weight
|
213
|
+
end
|
214
|
+
|
215
|
+
|
205
216
|
# Number of units that this item represents (integer, required).
|
206
217
|
attr_accessor :quantity
|
207
218
|
|
@@ -234,7 +245,27 @@ module Google4R #:nodoc:
|
|
234
245
|
|
235
246
|
@tax_table = table
|
236
247
|
end
|
237
|
-
|
248
|
+
|
249
|
+
# DigitalContent information for this item. Optional.
|
250
|
+
attr_reader :digital_content
|
251
|
+
|
252
|
+
def create_digital_content(digital_content=nil, &block)
|
253
|
+
|
254
|
+
if @digital_content.nil?
|
255
|
+
if digital_content.nil?
|
256
|
+
@digital_content = DigitalContent.new
|
257
|
+
else
|
258
|
+
@digital_content = digital_content
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
if block_given?
|
263
|
+
yield @digital_content
|
264
|
+
end
|
265
|
+
|
266
|
+
return @digital_content
|
267
|
+
end
|
268
|
+
|
238
269
|
# Create a new Item in the given Cart. You should not instantize this class directly
|
239
270
|
# but use Cart#create_item instead.
|
240
271
|
def initialize(shopping_cart)
|
@@ -249,6 +280,11 @@ module Google4R #:nodoc:
|
|
249
280
|
result.description = element.elements['item-description'].text
|
250
281
|
result.quantity = element.elements['quantity'].text.to_i
|
251
282
|
result.id = element.elements['merchant-item-id'].text rescue nil
|
283
|
+
|
284
|
+
weight_element = element.elements['item-weight']
|
285
|
+
if not weight_element.nil?
|
286
|
+
result.weight = Weight.create_from_element(weight_element)
|
287
|
+
end
|
252
288
|
|
253
289
|
data_element = element.elements['merchant-private-item-data']
|
254
290
|
if not data_element.nil? then
|
@@ -265,8 +301,70 @@ module Google4R #:nodoc:
|
|
265
301
|
unit_price_currency = element.elements['unit-price'].attributes['currency']
|
266
302
|
result.unit_price = Money.new(unit_price, unit_price_currency)
|
267
303
|
|
304
|
+
digital_content_element = element.elements['digital-content']
|
305
|
+
if not digital_content_element.nil?
|
306
|
+
result.create_digital_content(DigitalContent.create_from_element(digital_content_element))
|
307
|
+
end
|
308
|
+
|
268
309
|
return result
|
269
310
|
end
|
311
|
+
|
312
|
+
# A DigitalContent item represents the information relating to online delivery of digital items
|
313
|
+
#
|
314
|
+
# You should never initialize it directly but use Item#digital_content instead
|
315
|
+
#
|
316
|
+
# See http://code.google.com/apis/checkout/developer/Google_Checkout_Digital_Delivery.html
|
317
|
+
# for information on Google Checkout's idea of digital content.
|
318
|
+
#
|
319
|
+
# item.digital_content do |dc|
|
320
|
+
# dc.optimistic!
|
321
|
+
# dc.description = %{Here's some information on how to get your content}
|
322
|
+
# end
|
323
|
+
class DigitalContent
|
324
|
+
|
325
|
+
# Constants for display-disposition
|
326
|
+
OPTIMISTIC = 'OPTIMISTIC'
|
327
|
+
PESSIMISTIC = 'PESSIMISTIC'
|
328
|
+
|
329
|
+
# A description of how the user should access the digital content
|
330
|
+
# after completing the order (string, required for description-based
|
331
|
+
# delivery, otherwise optional)
|
332
|
+
attr_accessor :description
|
333
|
+
|
334
|
+
# Either 'OPTIMISTIC' or 'PESSIMISTIC'. If OPTIMISTIC, then Google
|
335
|
+
# will display instructions for accessing the digital content as soon
|
336
|
+
#as the buyer confirms the order. Optional, but default is PESSIMISTIC
|
337
|
+
attr_reader :display_disposition
|
338
|
+
|
339
|
+
def display_disposition=(disposition)
|
340
|
+
raise "display_disposition can only be set to PESSIMISTIC or OPTIMISTIC" unless disposition == OPTIMISTIC || disposition == PESSIMISTIC
|
341
|
+
@display_disposition = disposition
|
342
|
+
end
|
343
|
+
|
344
|
+
# A boolean identifying whether email delivery is used for this item.
|
345
|
+
attr_accessor :email_delivery
|
346
|
+
|
347
|
+
# A key required by the user to access this digital content after completing the order (string, optional)
|
348
|
+
attr_accessor :key
|
349
|
+
|
350
|
+
# A URL required by the user to access this digital content after completing the order (string, optional)
|
351
|
+
attr_accessor :url
|
352
|
+
|
353
|
+
def initialize
|
354
|
+
@display_disposition = PESSIMISTIC
|
355
|
+
end
|
356
|
+
|
357
|
+
# Creates a new DigitalContent object from a REXML::Element object
|
358
|
+
def self.create_from_element(element)
|
359
|
+
result = DigitalContent.new
|
360
|
+
result.description = element.elements['description'].text rescue nil
|
361
|
+
result.display_disposition = element.elements['display-disposition'].text rescue nil
|
362
|
+
result.email_delivery = element.elements['email-delivery'].text rescue nil # TODO need to convert to boolean?
|
363
|
+
result.key = element.elements['key'].text rescue nil
|
364
|
+
result.url = element.elements['url'].text rescue nil
|
365
|
+
return result
|
366
|
+
end
|
367
|
+
end
|
270
368
|
end
|
271
369
|
|
272
370
|
# A TaxTable is an ordered array of TaxRule objects. You should create the TaxRule
|
@@ -391,8 +489,7 @@ module Google4R #:nodoc:
|
|
391
489
|
#
|
392
490
|
# country_code should be a two-letter ISO 3166 country code
|
393
491
|
# postal_code_pattern should be a full or partial postcode string, using * as a wildcard
|
394
|
-
def initialize(country_code, postal_code_pattern=nil)
|
395
|
-
|
492
|
+
def initialize(country_code=nil, postal_code_pattern=nil)
|
396
493
|
@country_code = country_code
|
397
494
|
@postal_code_pattern = postal_code_pattern
|
398
495
|
end
|
@@ -405,7 +502,7 @@ module Google4R #:nodoc:
|
|
405
502
|
|
406
503
|
# You can optionally initialize the Area with its value.
|
407
504
|
def initialize(state=nil)
|
408
|
-
|
505
|
+
@state = state unless state.nil?
|
409
506
|
end
|
410
507
|
|
411
508
|
# Writer for the state attribute. value must match /^[A-Z]{2,2}$/.
|
@@ -515,8 +612,8 @@ module Google4R #:nodoc:
|
|
515
612
|
return area
|
516
613
|
end
|
517
614
|
|
518
|
-
# Creates a new Area, adds it to the internal list of allowed areas for
|
519
|
-
#
|
615
|
+
# Creates a new Area, adds it to the internal list of allowed areas for shipping
|
616
|
+
# restrictions. If you passed a block (preferred) then the block is called
|
520
617
|
# with the Area as the only parameter.
|
521
618
|
#
|
522
619
|
# The area to be created depends on the given parameter clazz. It can be one
|
@@ -551,7 +648,10 @@ module Google4R #:nodoc:
|
|
551
648
|
# end
|
552
649
|
def create_excluded_area(clazz, &block)
|
553
650
|
return create_area(:shipping_restrictions, :excluded_areas, clazz, &block)
|
554
|
-
end
|
651
|
+
end
|
652
|
+
|
653
|
+
alias :create_shipping_restrictions_allowed_area :create_allowed_area
|
654
|
+
alias :create_shipping_restrictions_excluded_area :create_excluded_area
|
555
655
|
end
|
556
656
|
|
557
657
|
# A class that represents the "pickup" shipping method.
|
@@ -584,6 +684,246 @@ module Google4R #:nodoc:
|
|
584
684
|
@address_filters_excluded_areas = Array.new
|
585
685
|
end
|
586
686
|
|
687
|
+
# Creates a new Area, adds it to the internal list of allowed areas for
|
688
|
+
# address filters. If you passed a block (preferred) then the block is
|
689
|
+
# called with the Area as the only parameter.
|
690
|
+
#
|
691
|
+
# The area to be created depends on the given parameter clazz. It can be one
|
692
|
+
# of { PostalArea, UsCountryArea, UsStateArea, UsZipArea, WorldArea }.
|
693
|
+
#
|
694
|
+
# Raises a RuntimeError if the parameter clazz is invalid.
|
695
|
+
#
|
696
|
+
# === Example
|
697
|
+
#
|
698
|
+
# method = FlatRateShipping.new
|
699
|
+
# method.create_allowed_area(UsCountryArea) do |area|
|
700
|
+
# area.area = UsCountryArea::ALL
|
701
|
+
# end
|
702
|
+
def create_address_filters_allowed_area(clazz, &block)
|
703
|
+
return create_area(:address_filters, :allowed_areas, clazz, &block)
|
704
|
+
end
|
705
|
+
|
706
|
+
# Creates a new Area, adds it to the internal list of excluded areas for
|
707
|
+
# address filters. If you passed a block (preferred) then the block is
|
708
|
+
# called with the Area as the only parameter.
|
709
|
+
#
|
710
|
+
# The area to be created depends on the given parameter clazz. It can be one
|
711
|
+
# of { PostalArea, UsCountryArea, UsStateArea, UsZipArea, WorldArea }.
|
712
|
+
#
|
713
|
+
# Raises a RuntimeError if the parameter clazz is invalid.
|
714
|
+
#
|
715
|
+
# === Example
|
716
|
+
#
|
717
|
+
# method = FlatRateShipping.new
|
718
|
+
# method.create_allowed_area(UsCountryArea) do |area|
|
719
|
+
# area.area = UsCountryArea::ALL
|
720
|
+
# end
|
721
|
+
def create_address_filters_allowed_area(clazz, &block)
|
722
|
+
return create_area(:address_filters, :allowed_areas, clazz, &block)
|
723
|
+
end
|
724
|
+
end
|
725
|
+
|
726
|
+
# A class that represents the "merchant-calculated" shipping method
|
727
|
+
class CarrierCalculatedShipping
|
728
|
+
# This encapsulates information about all of the shipping methods
|
729
|
+
# for which Google Checkout should obtain shipping costs.
|
730
|
+
attr_reader :carrier_calculated_shipping_options
|
731
|
+
|
732
|
+
# This encapsulates information about all of the packages that will be
|
733
|
+
# shipped to the buyer. At this time, merchants may only specify
|
734
|
+
# one package per order.
|
735
|
+
attr_reader :shipping_packages
|
736
|
+
|
737
|
+
def initialize()
|
738
|
+
@carrier_calculated_shipping_options = Array.new
|
739
|
+
@shipping_packages = Array.new
|
740
|
+
end
|
741
|
+
|
742
|
+
def create_carrier_calculated_shipping_option(&block)
|
743
|
+
option = CarrierCalculatedShippingOption.new(self)
|
744
|
+
@carrier_calculated_shipping_options << option
|
745
|
+
|
746
|
+
# Pass the newly generated rule to the given block to set its attributes.
|
747
|
+
yield(option) if block_given?
|
748
|
+
|
749
|
+
return option
|
750
|
+
end
|
751
|
+
|
752
|
+
def create_shipping_package(&block)
|
753
|
+
package = ShippingPackage.new(self)
|
754
|
+
@shipping_packages << package
|
755
|
+
|
756
|
+
# Pass the newly generated rule to the given block to set its attributes.
|
757
|
+
yield(package) if block_given?
|
758
|
+
|
759
|
+
return package
|
760
|
+
end
|
761
|
+
|
762
|
+
# Creates a new CarrierCalculatedShipping from the given
|
763
|
+
# REXML::Element instance.
|
764
|
+
# For testing only.
|
765
|
+
def create_from_element(element)
|
766
|
+
result = CarrierCalculatedShipping.new
|
767
|
+
element.elements.each('carrier-calculated-shipping-options/carrier-calculated-shipping-option') do |shipping_option_element|
|
768
|
+
result.carrier_calculated_shipping_options << CarrierCalculatedShippingOption.create_from_element(self, shipping_option_element)
|
769
|
+
end
|
770
|
+
element.elements.each('shipping-packages/shipping-package') do |shipping_package_element|
|
771
|
+
result.shipping_packages << ShippingPackage.create_from_element(self, shipping_package_element)
|
772
|
+
end
|
773
|
+
end
|
774
|
+
|
775
|
+
class CarrierCalculatedShippingOption < DeliveryMethod
|
776
|
+
# Constants for shipping company
|
777
|
+
FEDEX = 'FedEx'
|
778
|
+
UPS = 'UPS'
|
779
|
+
USPS = 'USPS'
|
780
|
+
|
781
|
+
# Constants for carrier pickup
|
782
|
+
DROP_OFF = 'DROP_OFF'
|
783
|
+
REGULAR_PICKUP = 'REGULAR_PICKUP'
|
784
|
+
SPECIAL_PICKUP = 'SPECIAL_PICKUP'
|
785
|
+
|
786
|
+
# The CarrierCalculatedShipping instance that this option belongs to.
|
787
|
+
attr_reader :carrier_calculated_shipping
|
788
|
+
|
789
|
+
# The name of the company that will ship the order.
|
790
|
+
# The only valid values for this tag are FedEx, UPS and USPS.
|
791
|
+
# (String, required)
|
792
|
+
alias :shipping_company :name
|
793
|
+
alias :shipping_company= :name=
|
794
|
+
|
795
|
+
# The shipping option that is being offered to the buyer
|
796
|
+
attr_accessor :shipping_type
|
797
|
+
|
798
|
+
# This specifies how the package will be transferred from the merchant
|
799
|
+
# to the shipper. Valid values for this tag are REGULAR_PICKUP,
|
800
|
+
# SPECIAL_PICKUP and DROP_OFF. The default value for this tag is DROP_OFF.
|
801
|
+
# (optional)
|
802
|
+
attr_accessor :carrier_pickup
|
803
|
+
|
804
|
+
# The fixed charge that will be added to the total cost of an order
|
805
|
+
# if the buyer selects the associated shipping option
|
806
|
+
# (Money, optional)
|
807
|
+
attr_accessor :additional_fixed_charge
|
808
|
+
|
809
|
+
# The percentage amount by which a carrier-calculated shipping rate
|
810
|
+
# will be adjusted. The tag's value may be positive or negative.
|
811
|
+
# (Float, optional)
|
812
|
+
attr_accessor :additional_variable_charge_percent
|
813
|
+
|
814
|
+
def initialize(carrier_calculated_shipping)
|
815
|
+
@carrier_calculated_shipping = carrier_calculated_shipping
|
816
|
+
#@carrier_pickup = DROP_OFF
|
817
|
+
end
|
818
|
+
|
819
|
+
# Creates a new CarrierCalculatedShippingOption from the given
|
820
|
+
# REXML::Element instance.
|
821
|
+
# For testing only.
|
822
|
+
def self.create_from_element(this_shipping, element)
|
823
|
+
result = CarrierCalculatedShippingOption.new(this_shipping)
|
824
|
+
result.shipping_company = element.elements['shipping-company'].text
|
825
|
+
price = (element.elements['price'].text.to_f * 100).to_i
|
826
|
+
price_currency = element.elements['price'].attributes['currency']
|
827
|
+
result.price = Money.new(price, price_currency)
|
828
|
+
result.shipping_type = element.elements['shipping-type']
|
829
|
+
result.carrier_pickup = element.elements['carrier-pickup'] rescue nil
|
830
|
+
result.additional_fixed_charge =
|
831
|
+
element.elements['additional-fixed-charge'] rescue nil
|
832
|
+
result.additional_variable_charge_percent =
|
833
|
+
element.elements['additional-variable-charge-percent'] rescue nil
|
834
|
+
end
|
835
|
+
end
|
836
|
+
|
837
|
+
class ShippingPackage
|
838
|
+
# Constants for delivery address category
|
839
|
+
RESIDENTIAL = 'RESIDENTIAL'
|
840
|
+
COMMERCIAL = 'COMMERCIAL'
|
841
|
+
|
842
|
+
# The CarrierCalculatedShipping instance that this package belongs to.
|
843
|
+
attr_reader :carrier_calculated_shipping
|
844
|
+
|
845
|
+
# This contains information about the location from which an order
|
846
|
+
# will be shipped. (AnonymousAddress)
|
847
|
+
attr_accessor :ship_from
|
848
|
+
|
849
|
+
# This indicates whether the shipping method should be applied to
|
850
|
+
# a residential or a commercial address. Valid values for this tag
|
851
|
+
# are RESIDENTIAL and COMMERCIAL. (String, optional)
|
852
|
+
attr_accessor :delivery_address_category
|
853
|
+
|
854
|
+
# This contains information about the height of the package being
|
855
|
+
# shipped to the customer. (Google::Checktou::Dimension, optional)
|
856
|
+
attr_accessor :height
|
857
|
+
|
858
|
+
# This contains information about the length of the package being
|
859
|
+
# shipped to the customer. (Google::Checktou::Dimension, optional)
|
860
|
+
attr_accessor :length
|
861
|
+
|
862
|
+
# This contains information about the width of the package being
|
863
|
+
# shipped to the customer. (Google::Checktou::Dimension, optional)
|
864
|
+
attr_accessor :width
|
865
|
+
|
866
|
+
def initialize(carrier_calculated_shipping)
|
867
|
+
@carrier_calculated_shipping = carrier_calculated_shipping
|
868
|
+
end
|
869
|
+
|
870
|
+
# Creates a new ShippingPackage from the given REXML::Element instance.
|
871
|
+
# For testing only.
|
872
|
+
def self.create_from_element(this_shipping, element)
|
873
|
+
result = ShippingPackage.new(this_shipping)
|
874
|
+
result.ship_from = ShipFromAddress.create_from_element(element.elements['ship-from'])
|
875
|
+
result.delivery_address_category = element.elements['delivery-address-category'].text rescue nil
|
876
|
+
result.height = element.elements['height'].text rescue nil
|
877
|
+
result.length = element.elements['length'].text rescue nil
|
878
|
+
result.width = element.elements['width'].text rescue nil
|
879
|
+
return result
|
880
|
+
end
|
881
|
+
end
|
882
|
+
end
|
883
|
+
|
884
|
+
# This is a base class for defining the unit of weight and dimension
|
885
|
+
class Unit
|
886
|
+
# This specifies the unit of measurement that corresponds to a shipping
|
887
|
+
# package's length, width or height. The only valid value for
|
888
|
+
# this attribute is IN.
|
889
|
+
attr_accessor :unit
|
890
|
+
|
891
|
+
# This specifies the numeric value of a unit of measurement
|
892
|
+
# corresponding to an item or a shipping package. (float)
|
893
|
+
attr_accessor :value
|
894
|
+
|
895
|
+
def initialize
|
896
|
+
raise "Google::Checkout::Unit is an abstract class!"
|
897
|
+
end
|
898
|
+
|
899
|
+
# Creates a new Unit from the given REXML::Element instance.
|
900
|
+
def self.create_from_element(element)
|
901
|
+
result = self.new(element.attributes['value'].to_f)
|
902
|
+
return result
|
903
|
+
end
|
904
|
+
end
|
905
|
+
|
906
|
+
# This defines package dimension
|
907
|
+
class Dimension < Unit
|
908
|
+
|
909
|
+
# Constants for unit
|
910
|
+
INCH = 'IN'
|
911
|
+
|
912
|
+
def initialize(value, unit=INCH)
|
913
|
+
@unit = unit
|
914
|
+
@value = value.to_f
|
915
|
+
end
|
916
|
+
end
|
917
|
+
|
918
|
+
# This defines item weight
|
919
|
+
class Weight < Unit
|
920
|
+
# Constants for unit
|
921
|
+
LB = 'LB'
|
922
|
+
|
923
|
+
def initialize(value, unit=LB)
|
924
|
+
@unit = unit
|
925
|
+
@value = value.to_f
|
926
|
+
end
|
587
927
|
end
|
588
928
|
|
589
929
|
# This address is used in merchant calculation callback
|
@@ -677,5 +1017,40 @@ module Google4R #:nodoc:
|
|
677
1017
|
return result
|
678
1018
|
end
|
679
1019
|
end
|
1020
|
+
|
1021
|
+
# ItemInfo instances are used in Line-item shipping commands
|
1022
|
+
class ItemInfo
|
1023
|
+
# The merchant item id (String)
|
1024
|
+
attr_reader :merchant_item_id
|
1025
|
+
|
1026
|
+
# An array of tracking data for this item
|
1027
|
+
attr_reader :tracking_data_arr
|
1028
|
+
|
1029
|
+
def initialize(merchant_item_id)
|
1030
|
+
@merchant_item_id = merchant_item_id
|
1031
|
+
@tracking_data_arr = Array.new
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
def create_tracking_data(carrier, tracking_number)
|
1035
|
+
tracking_data = TrackingData.new(carrier, tracking_number)
|
1036
|
+
@tracking_data_arr << tracking_data
|
1037
|
+
return tracking_data
|
1038
|
+
end
|
1039
|
+
end
|
1040
|
+
|
1041
|
+
# TrackingData instances are used in Line-item shipping commands
|
1042
|
+
class TrackingData
|
1043
|
+
# The name of the company responsible for shipping the item. Valid values
|
1044
|
+
# for this tag are DHL, FedEx, UPS, USPS and Other.
|
1045
|
+
attr_reader :carrier
|
1046
|
+
|
1047
|
+
# The shipper's tracking number that is associated with an order
|
1048
|
+
attr_reader :tracking_number
|
1049
|
+
|
1050
|
+
def initialize(carrier, tracking_number)
|
1051
|
+
@carrier = carrier.to_s
|
1052
|
+
@tracking_number = tracking_number.to_s
|
1053
|
+
end
|
1054
|
+
end
|
680
1055
|
end
|
681
1056
|
end
|