google4r-checkout 1.0.1 → 1.0.2

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.
@@ -440,9 +440,8 @@ module Google4R #:nodoc:
440
440
  end
441
441
  end
442
442
 
443
- # Abstract class for shipping methods. Do not use this class directly but only
444
- # one of its subclasses.
445
- class ShippingMethod
443
+ # Abstract class for delivery methods
444
+ class DeliveryMethod
446
445
  # The name of the shipping method (string, required).
447
446
  attr_accessor :name
448
447
 
@@ -465,54 +464,78 @@ module Google4R #:nodoc:
465
464
  end
466
465
  end
467
466
 
468
- # A class that represents the "pickup" shipping method.
469
- class PickupShipping < ShippingMethod
470
- def initialize
471
- end
472
- end
473
-
474
- # A class that represents the "flat_rate" shipping method.
475
- class FlatRateShipping < ShippingMethod
476
- # An Array of allowed areas for this flat_rate shipping instance. Use
467
+ # Abstract class for shipping methods. Do not use this class directly but only
468
+ # one of its subclasses.
469
+ class ShippingMethod < DeliveryMethod
470
+ # An Array of allowed areas for shipping-restrictions of this shipping instance. Use
477
471
  # #create_allowed_area to add to this area but do not change it directly.
478
- attr_reader :allowed_areas
472
+ attr_reader :shipping_restrictions_allowed_areas
479
473
 
480
- # An Array of excluded areas for this flat_rate shipping instance. Use
474
+ # An Array of excluded areas for shipping-restrictions of this shipping instance. Use
481
475
  # #create_excluded_area to add to this area but do not change it directly.
482
- attr_reader :excluded_areas
476
+ attr_reader :shipping_restrictions_excluded_areas
483
477
 
484
478
  def initialize
485
- @allowed_areas = Array.new
486
- @excluded_areas = Array.new
479
+ @shipping_restrictions_allowed_areas = Array.new
480
+ @shipping_restrictions_excluded_areas = Array.new
487
481
  end
488
482
 
489
- # Creates a new Area, adds it to the internal list of allowed areas for this
490
- # shipping types. If you passed a block (preferred) then the block is called
491
- # with the Area as the only parameter.c
483
+ # This method create a new instance of subclass of Area and put it
484
+ # in the array determined by the two symbols provided. The valid
485
+ # symbols for the first two parameters are:
492
486
  #
493
- # The area to be created depends on the given parameter clazz. It can be one
487
+ # type : :shipping_restrictions, :address_filters
488
+ # areas : :allowed_areas, :excluded_areas
489
+ #
490
+ # The third parameter clazz is used to specify the type of
491
+ # Area you want to create. It can be one
494
492
  # of { PostalArea, UsCountryArea, UsStateArea, UsZipArea, WorldArea }.
495
493
  #
496
494
  # Raises a RuntimeError if the parameter clazz is invalid.
497
495
  #
496
+ # If you passed a block (preferred) then the block is called
497
+ # with the Area as the only parameter.
498
+ #
498
499
  # === Example
499
500
  #
500
- # method = FlatRateShipping.new
501
- # method.create_allowed_area(UsCountryArea) do |area|
501
+ # method = MerchantCalculatedShipping.new
502
+ # method.create_area(:shipping_restrictions, :allowed_areas, UsCountryArea) do |area|
502
503
  # area.area = UsCountryArea::ALL
503
504
  # end
504
- def create_allowed_area(clazz, &block)
505
+ def create_area(type, areas, clazz, &block)
506
+ areas_array_name = "@#{type.to_s + '_' + areas.to_s}"
507
+ areas = instance_variable_get(areas_array_name)
508
+ raise "Undefined instance variable: #{areas_array_name}" unless areas.nil? == false
505
509
  raise "Invalid Area class: #{clazz}!" unless [ PostalArea, UsCountryArea, UsStateArea, UsZipArea, WorldArea ].include?(clazz)
506
510
  area = clazz.new
507
- @allowed_areas << area
511
+ areas << area
508
512
 
509
513
  yield(area) if block_given?
510
514
 
511
515
  return area
512
516
  end
513
517
 
514
- # Creates a new Area, adds it to the internal list of excluded areas for this
515
- # shipping types. If you passed a block (preferred) then the block is called
518
+ # Creates a new Area, adds it to the internal list of allowed areas for this
519
+ # shipping type. If you passed a block (preferred) then the block is called
520
+ # with the Area as the only parameter.
521
+ #
522
+ # The area to be created depends on the given parameter clazz. It can be one
523
+ # of { PostalArea, UsCountryArea, UsStateArea, UsZipArea, WorldArea }.
524
+ #
525
+ # Raises a RuntimeError if the parameter clazz is invalid.
526
+ #
527
+ # === Example
528
+ #
529
+ # method = FlatRateShipping.new
530
+ # method.create_allowed_area(UsCountryArea) do |area|
531
+ # area.area = UsCountryArea::ALL
532
+ # end
533
+ def create_allowed_area(clazz, &block)
534
+ return create_area(:shipping_restrictions, :allowed_areas, clazz, &block)
535
+ end
536
+
537
+ # Creates a new Area, adds it to the internal list of excluded areas for shipping
538
+ # restrictions. If you passed a block (preferred) then the block is called
516
539
  # with the Area as the only parameter. The created area is returned in any case.
517
540
  #
518
541
  # The area to be created depends on the given parameter clazz. It can be one
@@ -527,14 +550,131 @@ module Google4R #:nodoc:
527
550
  # area.area = UsCountryArea::ALL
528
551
  # end
529
552
  def create_excluded_area(clazz, &block)
530
- raise "Invalid Area class: #{clazz}!" unless [ PostalArea, UsCountryArea, UsStateArea, UsZipArea, WorldArea ].include?(clazz)
553
+ return create_area(:shipping_restrictions, :excluded_areas, clazz, &block)
554
+ end
555
+ end
556
+
557
+ # A class that represents the "pickup" shipping method.
558
+ class PickupShipping < DeliveryMethod
559
+ def initialize
560
+ end
561
+ end
562
+
563
+ # A class that represents the "flat_rate" shipping method.
564
+ class FlatRateShipping < ShippingMethod
565
+ def initialize
566
+ super
567
+ end
568
+ end
569
+
570
+ # A class that represents the "merchant-calculated" shipping method
571
+ class MerchantCalculatedShipping < ShippingMethod
572
+
573
+ # An Array of allowed areas for address-filters of this shipping instance. Use
574
+ # #create_allowed_area to add to this area but do not change it directly.
575
+ attr_reader :address_filters_allowed_areas
576
+
577
+ # An Array of excluded areas for address-filters of this shipping instance. Use
578
+ # #create_excluded_area to add to this area but do not change it directly.
579
+ attr_reader :address_filters_excluded_areas
580
+
581
+ def initialize
582
+ super
583
+ @address_filters_allowed_areas = Array.new
584
+ @address_filters_excluded_areas = Array.new
585
+ end
586
+
587
+ end
588
+
589
+ # This address is used in merchant calculation callback
590
+ class AnonymousAddress
591
+
592
+ # The address ID (String)
593
+ attr_accessor :address_id
594
+
595
+ # The buyer's city name (String).
596
+ attr_accessor :city
597
+
598
+ # The buyers postal/zip code (String).
599
+ attr_accessor :postal_code
600
+
601
+ # The buyer's geographical region (String).
602
+ attr_accessor :region
603
+
604
+ # The buyer's country code (String, 2 chars, ISO 3166).
605
+ attr_accessor :country_code
606
+
607
+ # Creates a new AnonymousAddress from the given REXML::Element instance.
608
+ def self.create_from_element(element)
609
+ result = AnonymousAddress.new
610
+
611
+ result.address_id = element.attributes['id']
612
+ result.city = element.elements['city'].text
613
+ result.country_code = element.elements['country-code'].text
614
+ result.postal_code = element.elements['postal-code'].text
615
+ result.region = element.elements['region'].text
616
+ return result
617
+ end
618
+ end
531
619
 
532
- area = clazz.new
533
- @excluded_areas << area
620
+ # Address instances are used in NewOrderNotification objects for the buyer's billing
621
+ # and buyer's shipping address.
622
+ class Address < AnonymousAddress
623
+ # Contact name (String, optional).
624
+ attr_accessor :contact_name
625
+
626
+ # Second Address line (String).
627
+ attr_accessor :address1
628
+
629
+ # Second Address line (String optional).
630
+ attr_accessor :address2
631
+
632
+ # The buyer's city name (String).
633
+ # attr_accessor :city
634
+ # Now inherit from AnonymousAddress
635
+
636
+ # The buyer's company name (String; optional).
637
+ attr_accessor :company_name
638
+
639
+ # The buyer's country code (String, 2 chars, ISO 3166).
640
+ # attr_accessor :country_code
641
+ # Now inherit from AnonymousAddress
642
+
643
+ # The buyer's email address (String; optional).
644
+ attr_accessor :email
645
+
646
+ # The buyer's phone number (String; optional).
647
+ attr_accessor :fax
648
+
649
+ # The buyer's phone number (String; Optional, can be enforced in CheckoutCommand).)
650
+ attr_accessor :phone
651
+
652
+ # The buyers postal/zip code (String).
653
+ # attr_accessor :postal_code
654
+ # Now inherit from AnonymousAddress
655
+
656
+
657
+ # The buyer's geographical region (String).
658
+ # attr_accessor :region
659
+ # Now inherit from AnonymousAddress
660
+
661
+ # Creates a new Address from the given REXML::Element instance.
662
+ def self.create_from_element(element)
663
+ result = Address.new
534
664
 
535
- yield(area) if block_given?
665
+ result.address1 = element.elements['address1'].text
666
+ result.address2 = element.elements['address2'].text rescue nil
667
+ result.city = element.elements['city'].text
668
+ result.company_name = element.elements['company-name'].text rescue nil
669
+ result.contact_name = element.elements['contact-name'].text rescue nil
670
+ result.country_code = element.elements['country-code'].text
671
+ result.email = element.elements['email'].text rescue nil
672
+ result.fax = element.elements['fax'].text rescue nil
673
+ result.phone = element.elements['phone'].text rescue nil
674
+ result.postal_code = element.elements['postal-code'].text
675
+ result.region = element.elements['region'].text
536
676
 
537
- return area
677
+ return result
538
678
  end
539
679
  end
540
680
  end
@@ -1,7 +1,8 @@
1
1
  #--
2
2
  # Project: google4r
3
3
  # File: lib/google4r/checkout/xml_generation.rb
4
- # Author: Manuel Holtgrewe <purestorm at ggnore dot net>
4
+ # Authors: Manuel Holtgrewe <purestorm at ggnore dot net>
5
+ # Tony Chan <api.htchan at gmail dot com>
5
6
  # Copyright: (c) 2007 by Manuel Holtgrewe
6
7
  # License: MIT License as follows:
7
8
  #
@@ -33,9 +34,20 @@ require 'rexml/document'
33
34
  module Google4R #:nodoc:
34
35
  module Checkout #:nodoc:
35
36
 
37
+ class XmlGenerator
38
+ # Base method to generate the XML for a particular command
39
+ def generate
40
+ @document = REXML::Document.new
41
+
42
+ declaration = REXML::XMLDecl.new
43
+ declaration.encoding = 'utf-8'
44
+ @document << declaration
45
+ end
46
+ end
47
+
36
48
  # Abstract super class for all CommandXmlGenerators
37
49
  # It should never be instantiated directly
38
- class CommandXmlGenerator
50
+ class CommandXmlGenerator < XmlGenerator
39
51
 
40
52
  # The list of command tag names
41
53
  COMMAND_TO_TAG =
@@ -54,19 +66,14 @@ module Google4R #:nodoc:
54
66
  }
55
67
 
56
68
  def initialize(command)
69
+ super()
57
70
  @command = command
58
71
  end
59
-
72
+
60
73
  # Base method to generate the XML for a particular command
61
74
  def generate
62
- @document = REXML::Document.new
63
-
64
- declaration = REXML::XMLDecl.new
65
- declaration.encoding = 'utf-8'
66
- @document << declaration
67
-
75
+ super()
68
76
  self.process_command(@command)
69
-
70
77
  io = StringIO.new
71
78
  @document.write(io, 0) # TODO: Maybe replace 0 by -1 so no spaces are inserted?
72
79
  return io.string
@@ -138,6 +145,26 @@ module Google4R #:nodoc:
138
145
  "false"
139
146
  end
140
147
  end
148
+
149
+ # <merchant-calculations>
150
+ if not command.merchant_calculations_url.nil? then
151
+ merchant_calculations = flow_element.add_element('merchant-calculations')
152
+ merchant_calculations.add_element('merchant-calculations-url').text =
153
+ command.merchant_calculations_url
154
+ if not command.accept_merchant_coupons.nil? then
155
+ merchant_calculations.add_element('accept-merchant-coupons').text =
156
+ command.accept_merchant_coupons.to_s
157
+ end
158
+ if not command.accept_gift_certificates.nil? then
159
+ merchant_calculations.add_element('accept-gift-certificates').text =
160
+ command.accept_gift_certificates.to_s
161
+ end
162
+ end
163
+
164
+ # <platform-id>
165
+ if not command.platform_id.nil? then
166
+ flow_element.add_element('platform-id').text = command.platform_id
167
+ end
141
168
 
142
169
  # <shipping-methods>
143
170
  shippings_element = flow_element.add_element('shipping-methods')
@@ -234,41 +261,67 @@ module Google4R #:nodoc:
234
261
  # Adds an item for the given shipping method.
235
262
  def process_shipping_method(parent, shipping_method)
236
263
  if shipping_method.kind_of? PickupShipping then
237
- process_pickup_shipping(parent, shipping_method)
264
+ process_pickup(parent, shipping_method)
238
265
  elsif shipping_method.kind_of? FlatRateShipping then
239
- process_flat_rate_shipping(parent, shipping_method)
266
+ process_shipping('flat-rate-shipping', parent, shipping_method)
267
+ elsif shipping_method.kind_of? MerchantCalculatedShipping then
268
+ process_shipping('merchant-calculated-shipping', parent, shipping_method)
240
269
  else
241
270
  raise "Unknown ShippingMethod type of #{shipping_method.inspect}!"
242
271
  end
243
272
  end
244
273
 
245
- def process_flat_rate_shipping(parent, shipping)
246
- element = parent.add_element('flat-rate-shipping')
274
+ def process_shipping(shipping_type, parent, shipping)
275
+ element = parent.add_element(shipping_type)
247
276
  element.add_attribute('name', shipping.name)
248
277
  element.add_element('price', { 'currency' => shipping.price.currency }).text = shipping.price.to_s
249
278
 
250
- if shipping.excluded_areas.length + shipping.allowed_areas.length > 0 then
251
- restrictions_tag = element.add_element('shipping-restrictions')
279
+ if shipping.shipping_restrictions_excluded_areas.length +
280
+ shipping.shipping_restrictions_allowed_areas.length > 0 then
281
+ shipping_restrictions_tag = element.add_element('shipping-restrictions')
252
282
 
253
- if shipping.allowed_areas.length > 0 then
254
- allowed_tag = restrictions_tag.add_element('allowed-areas')
283
+ if shipping.shipping_restrictions_allowed_areas.length > 0 then
284
+ allowed_tag = shipping_restrictions_tag.add_element('allowed-areas')
255
285
 
256
- shipping.allowed_areas.each do |area|
286
+ shipping.shipping_restrictions_allowed_areas.each do |area|
257
287
  self.process_area(allowed_tag, area)
258
288
  end
259
289
  end
260
290
 
261
- if shipping.excluded_areas.length > 0 then
262
- excluded_tag = restrictions_tag.add_element('excluded-areas')
291
+ if shipping.shipping_restrictions_excluded_areas.length > 0 then
292
+ excluded_tag = shipping_restrictions_tag.add_element('excluded-areas')
263
293
 
264
- shipping.excluded_areas.each do |area|
294
+ shipping.shipping_restrictions_excluded_areas.each do |area|
265
295
  self.process_area(excluded_tag, area)
266
296
  end
267
297
  end
268
298
  end
299
+
300
+ if shipping.kind_of? MerchantCalculatedShipping then
301
+ if shipping.address_filters_excluded_areas.length +
302
+ shipping.address_filters_allowed_areas.length > 0 then
303
+ address_filters_tag = element.add_element('address-filters')
304
+
305
+ if shipping.address_filters_allowed_areas.length > 0 then
306
+ allowed_tag = address_filters_tag.add_element('allowed-areas')
307
+
308
+ shipping.address_filters_allowed_areas.each do |area|
309
+ self.process_area(allowed_tag, area)
310
+ end
311
+ end
312
+
313
+ if shipping.address_filters_excluded_areas.length > 0 then
314
+ excluded_tag = address_filters_tag.add_element('excluded-areas')
315
+
316
+ shipping.address_filters_excluded_areas.each do |area|
317
+ self.process_area(excluded_tag, area)
318
+ end
319
+ end
320
+ end
321
+ end
269
322
  end
270
323
 
271
- def process_pickup_shipping(parent, shipping)
324
+ def process_pickup(parent, shipping)
272
325
  element = parent.add_element('pickup')
273
326
  element.add_attribute('name', shipping.name)
274
327
  element.add_element('price', { 'currency' => shipping.price.currency }).text = shipping.price.to_s
@@ -483,7 +536,7 @@ module Google4R #:nodoc:
483
536
  end
484
537
 
485
538
  class SendBuyerMessageCommandXmlGenerator < CommandXmlGenerator
486
-
539
+
487
540
  protected
488
541
 
489
542
  def process_command(command)
@@ -513,5 +566,68 @@ module Google4R #:nodoc:
513
566
  end
514
567
  end
515
568
 
569
+ class MerchantCalculationResultsXmlGenerator < XmlGenerator
570
+
571
+ def initialize(merchant_calculation_results)
572
+ @merchant_calculation_results = merchant_calculation_results
573
+ end
574
+
575
+ def generate()
576
+ super()
577
+ process_results(@merchant_calculation_results.merchant_calculation_results)
578
+ io = StringIO.new
579
+ @document.write(io, 0) # TODO: Maybe replace 0 by -1 so no spaces are inserted?
580
+ return io.string
581
+ end
582
+
583
+ protected
584
+
585
+ def process_results(merchant_calculation_results)
586
+ root = @document.add_element("merchant-calculation-results" , { 'xmlns' => 'http://checkout.google.com/schema/2' })
587
+ results = root.add_element("results")
588
+ for merchant_calculation_result in merchant_calculation_results do
589
+ process_result(results, merchant_calculation_result)
590
+ end
591
+ end
592
+
593
+ def process_result(parent, merchant_calculation_result)
594
+ element = parent.add_element("result")
595
+ element.add_attribute("shipping-name", merchant_calculation_result.shipping_name)
596
+ element.add_attribute("address-id", merchant_calculation_result.address_id)
597
+ shipping_rate = element.add_element("shipping-rate")
598
+ shipping_rate.text = merchant_calculation_result.shipping_rate.to_s
599
+ shipping_rate.add_attribute("currency", merchant_calculation_result.shipping_rate.currency)
600
+ element.add_element("shippable").text = merchant_calculation_result.shippable.to_s
601
+ if (!merchant_calculation_result.total_tax.nil?)
602
+ total_tax = element.add_element("total-tax")
603
+ total_tax.text = merchant_calculation_result.total_tax.to_s
604
+ total_tax.add_attribute("currency", merchant_calculation_result.total_tax.currency)
605
+ end
606
+ process_code_results(element, merchant_calculation_result.merchant_code_results)
607
+ end
608
+
609
+ def process_code_results(parent, merchant_code_results)
610
+ element = parent.add_element("merchant-code-results")
611
+ for merchant_code_result in merchant_code_results do
612
+ process_merchant_code_result(element, merchant_code_result)
613
+ end
614
+ end
615
+
616
+ def process_merchant_code_result(parent, merchant_code_result)
617
+ if merchant_code_result.kind_of?(CouponResult)
618
+ element = parent.add_element("coupon-result")
619
+ elsif merchant_code_result.kind_of?(GiftCertificateResult)
620
+ element = parent.add_element("gift-certificate-result")
621
+ else
622
+ raise "Code of unknown type: #{merchant_code_result.inspect}."
623
+ end
624
+ element.add_element("valid").text = merchant_code_result.valid.to_s
625
+ element.add_element("code").text = merchant_code_result.code.to_s
626
+ calculated_amount = element.add_element("calculated-amount")
627
+ calculated_amount.text = merchant_code_result.calculated_amount.to_s
628
+ calculated_amount.add_attribute("currency", merchant_code_result.calculated_amount.currency)
629
+ element.add_element("message").text = merchant_code_result.message
630
+ end
631
+ end
516
632
  end
517
633
  end