google4r-checkout 1.0.3 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,5 +1,20 @@
1
1
  =google4r-checkout Changelog
2
2
 
3
+ == 1.0.6 (2010-04-01)
4
+
5
+ * Added beta Subscriptions API support.
6
+ * Fixed email-delivery XML generation bug.
7
+
8
+ == 1.0.5 (2008-9-17)
9
+
10
+ * Added Order Report API support. Thanks to Daniel Pirone!
11
+ * Added unit tests for OrderReportCommand. Added validation checks fro start_date, end_date, financial_state and fulfillment_state.
12
+
13
+ == 1.0.4 (2008-09-02)
14
+
15
+ * Fixed undefined email_delivery? method bug
16
+ * Added unit test to cover digital content creation
17
+
3
18
  == 1.0.3 (2008-08-08)
4
19
 
5
20
  * Added analytics_data support. Thanks to Will Schwenk!
@@ -49,6 +49,9 @@ module Google4R #:nodoc:
49
49
  CHECKOUT_API_URL = 'api/checkout/v2/merchantCheckout/Merchant/%s'
50
50
 
51
51
  ORDER_PROCESSING_API_URL = 'api/checkout/v2/request/Merchant/%s'
52
+
53
+ ORDER_REPORT_API_URL = 'api/checkout/v2/reports/Merchant/%s'
54
+
52
55
 
53
56
  # The Frontent class that was used to create this CheckoutCommand and whose
54
57
  # configuration will be used.
@@ -79,6 +82,7 @@ module Google4R #:nodoc:
79
82
  # TODO: The send-and-expect-response part should be adaptable to other commands and responses.
80
83
  #++
81
84
  def send_to_google_checkout
85
+ xml_response = (self.class == OrderReportCommand) ? false : true
82
86
  # Create HTTP(S) POST command and set up Basic Authentication.
83
87
  url_str =
84
88
  if frontend.configuration[:use_sandbox] then
@@ -89,6 +93,8 @@ module Google4R #:nodoc:
89
93
  url_str +=
90
94
  if self.class == CheckoutCommand then
91
95
  CHECKOUT_API_URL
96
+ elsif self.class == OrderReportCommand then
97
+ ORDER_REPORT_API_URL
92
98
  else
93
99
  ORDER_PROCESSING_API_URL
94
100
  end
@@ -110,18 +116,23 @@ module Google4R #:nodoc:
110
116
 
111
117
  case result
112
118
  when Net::HTTPSuccess then
113
- xml_doc = REXML::Document.new(result.body)
114
-
115
- case xml_doc.root.name
116
- when 'checkout-redirect'
117
- serial_number = xml_doc.elements['/checkout-redirect'].attributes['serial-number']
118
- redirect_url = xml_doc.elements['/checkout-redirect/redirect-url/text()'].value
119
- return CheckoutRedirectResponse.new(serial_number, redirect_url)
120
- when 'request-received'
121
- serial_number = xml_doc.elements['/request-received'].attributes['serial-number']
122
- return serial_number
119
+ if ( xml_response ) then
120
+ xml_doc = REXML::Document.new(result.body)
121
+
122
+ case xml_doc.root.name
123
+ when 'checkout-redirect'
124
+ serial_number = xml_doc.elements['/checkout-redirect'].attributes['serial-number']
125
+ redirect_url = xml_doc.elements['/checkout-redirect/redirect-url/text()'].value
126
+ return CheckoutRedirectResponse.new(serial_number, redirect_url)
127
+ when 'request-received'
128
+ serial_number = xml_doc.elements['/request-received'].attributes['serial-number']
129
+ return serial_number
130
+ else
131
+ raise "Unknown response:\n--\n#{xml_doc.to_s}\n--"
132
+ end
123
133
  else
124
- raise "Unknown response:\n--\n#{xml_doc.to_s}\n--"
134
+ # handle the CSV output of the order-report-list command
135
+ return result.body
125
136
  end
126
137
  when Net::HTTPClientError then
127
138
  xml_doc = REXML::Document.new(result.body)
@@ -296,6 +307,28 @@ module Google4R #:nodoc:
296
307
  return @redirect_url
297
308
  end
298
309
  end
310
+
311
+ # SubscriptionRequestReceivedResponse instances are returned when a
312
+ # CreateOrderRecurrenceRequestCommand is successfully processed by Google Checkout.
313
+ class SubscriptionRequestReceivedResponse
314
+ # The serial number of the <subscription-request-received> response.
315
+ attr_reader :serial_number
316
+
317
+ # The new order number that was generated for this request.
318
+ attr_reader :new_google_order_number
319
+
320
+ # Create a new SubscriptionRequestReceivedResponse with the given serial number and Google
321
+ # order number. Do not create SubscriptionRequestReceivedResponse instances in your own
322
+ # code. Google4R creates them for you.
323
+ def initialize(serial_number, new_google_order_number)
324
+ @serial_number = serial_number
325
+ @new_google_order_number = new_google_order_number
326
+ end
327
+
328
+ def to_s
329
+ return @new_google_order_number
330
+ end
331
+ end
299
332
 
300
333
  #
301
334
  # The ChargeOrderCommand instructs Google Checkout to charge the buyer for a
@@ -426,6 +459,24 @@ module Google4R #:nodoc:
426
459
  end
427
460
  end
428
461
 
462
+ # The <create-order-recurrence-request> tag contains a request to charge a customer for one or more items in a subscription.
463
+ class CreateOrderRecurrenceRequestCommand < Command
464
+ # The ID that uniquely identifies this order
465
+ attr_accessor :google_order_number
466
+
467
+ attr_reader :shopping_cart
468
+
469
+ # Initialize a new CreateOrderRecurrenceRequestCommand with a fresh ShoppingCart.
470
+ def initialize(frontend)
471
+ super(frontend)
472
+ @shopping_cart = ShoppingCart.new(self)
473
+ end
474
+
475
+ def to_xml
476
+ CreateOrderRecurrenceRequestCommandXmlGenerator.new(self).generate
477
+ end
478
+ end
479
+
429
480
  #
430
481
  # XML API Commands for Line-item Shipping
431
482
  #
@@ -465,8 +516,7 @@ module Google4R #:nodoc:
465
516
  # The <cancel-items> command lets you specify that one or more
466
517
  # specific items in an order have been cancelled, meaning they
467
518
  # will not be delivered to the customer.
468
- class CancelItemsCommand < ItemsCommand
469
-
519
+ class CancelItemsCommand < ItemsCommand
470
520
  # The reason that you are canceling one or more line items
471
521
  attr_accessor :reason
472
522
 
@@ -493,5 +543,65 @@ module Google4R #:nodoc:
493
543
  ResetItemsShippingInformationCommandXmlGenerator.new(self).generate
494
544
  end
495
545
  end
546
+
547
+ # The <order-list-request> command lets you to download a list of
548
+ # Google Checkout orders into a comma-separated file.
549
+ # The API will return a list of orders for a period of up to 31 days,
550
+ # and you can limit results to orders that have specific financial or
551
+ # fulfillment order states.
552
+ # http://code.google.com/apis/checkout/developer/Google_Checkout_XML_API_Order_Report_API.html
553
+ class OrderReportCommand < Command
554
+ # The earliest time that an order could have been submitted to be
555
+ # included in the API response (Time)
556
+ attr_reader :start_date
557
+
558
+ # The time before which an order must have been sent to be included
559
+ # in the API response (Time)
560
+ attr_reader :end_date
561
+
562
+ # The financial status of an order
563
+ attr_accessor :financial_state
564
+
565
+ # The fulfillment status of an order
566
+ attr_accessor :fulfillment_state
567
+
568
+ # The time zone that will be associated with the start date and
569
+ # end date for the report
570
+ attr_accessor :date_time_zone
571
+
572
+ def initialize(frontend, start_date, end_date)
573
+ super frontend
574
+ raise 'start_date has to be of type Time' unless start_date.class == Time
575
+ raise 'end_date has to be of type Time' unless start_date.class == Time
576
+ raise 'end_date has to be before start_date' unless
577
+ end_date >= start_date
578
+ @start_date = start_date
579
+ @end_date = end_date
580
+ end
581
+
582
+ def start_date
583
+ return @start_date.strftime('%Y-%m-%dT%H:%M:%S')
584
+ end
585
+
586
+ def end_date
587
+ return @end_date.strftime('%Y-%m-%dT%H:%M:%S')
588
+ end
589
+
590
+ def financial_state=(financial_state)
591
+ raise 'Invalid financial state %s' % financial_state unless
592
+ FinancialState.constants.include?(financial_state)
593
+ @financial_state = financial_state
594
+ end
595
+
596
+ def fulfillment_state=(fulfillment_state)
597
+ raise 'Invalid fulfillment state %s' % fulfillment_state unless
598
+ FulfillmentState.constants.include?(fulfillment_state)
599
+ @fulfillment_state = fulfillment_state
600
+ end
601
+
602
+ def to_xml
603
+ ReturnOrderReportCommandXmlGenerator.new(self).generate
604
+ end
605
+ end
496
606
  end
497
607
  end
@@ -170,6 +170,12 @@ module Google4R #:nodoc:
170
170
  return UnarchiveOrderCommand.new(self)
171
171
  end
172
172
 
173
+ # Factory method to create a new CreateOrderRecurrenceRequestCommand object. Use this method to create
174
+ # your CreateOrderRecurrenceRequestCommand instances.
175
+ def create_create_order_recurrence_request_command
176
+ return CreateOrderRecurrenceRequestCommand.new(self)
177
+ end
178
+
173
179
  # Factory method to create a new ShipItemsCommand object. Use this method to create
174
180
  # your ShipItemsCommand instances.
175
181
  def create_ship_items_command
@@ -199,6 +205,12 @@ module Google4R #:nodoc:
199
205
  def create_reset_items_shipping_information_command
200
206
  return ResetItemsShippingInformationCommand.new(self)
201
207
  end
208
+
209
+ # Factory method that creates a new OrderReportCommand object. Use this method to create
210
+ # your OrderReportCommand instances.
211
+ def create_order_report_command(start_date, end_date)
212
+ return OrderReportCommand.new(self, start_date, end_date)
213
+ end
202
214
  end
203
215
  end
204
216
  end
File without changes
@@ -132,6 +132,8 @@ module Google4R #:nodoc:
132
132
  ChargebackAmountNotification.create_from_element(root, frontend)
133
133
  when 'authorization-amount-notification' then
134
134
  AuthorizationAmountNotification.create_from_element(root, frontend)
135
+ when 'cancelled-subscription-notification' then
136
+ CancelledSubscriptionNotification.create_from_element(root, frontend)
135
137
  else
136
138
  raise UnknownNotificationType, "Unknown notification type: #{root.name}"
137
139
  end
@@ -487,6 +489,33 @@ module Google4R #:nodoc:
487
489
  end
488
490
  end
489
491
 
492
+ # CancelledSubscriptionNotification objects contain information about the
493
+ # cancellation of a subscription, including the item-ids, google order number,
494
+ # reason, and timestamp.
495
+ class CancelledSubscriptionNotification < Notification
496
+
497
+ # The reason for the cancellation (String, can be nil.)
498
+ attr_accessor :reason
499
+
500
+ # The ids of the items being cancelled (Array of Strings)
501
+ attr_accessor :item_ids
502
+
503
+ # The google order number of the subscription being cancelled
504
+ attr_accessor :google_order_number
505
+
506
+ def self.create_from_element(element, frontend)
507
+ csn = CancelledSubscriptionNotification.new(frontend)
508
+
509
+ csn.serial_number = element.attributes['serial-number']
510
+ csn.timestamp = Time.parse(element.elements['timestamp'].text)
511
+ csn.reason = element.elements['reason'].text rescue nil
512
+ csn.item_ids = element.elements['item-ids/item-id/merchant-item-id'].collect {|i| i.text} rescue []
513
+ csn.google_order_number = element.elements['google-order-number'].text
514
+
515
+ return csn
516
+ end
517
+ end
518
+
490
519
  # Container for the valid financial order states as defined in the
491
520
  # Google Checkout API.
492
521
  module FinancialOrderState
@@ -266,6 +266,26 @@ module Google4R #:nodoc:
266
266
  return @digital_content
267
267
  end
268
268
 
269
+ # Subscription information for this item. Optional.
270
+ attr_reader :subscription
271
+
272
+ def create_subscription(subscription=nil, &block)
273
+
274
+ if @subscription.nil?
275
+ if subscription.nil?
276
+ @subscription = Subscription.new
277
+ else
278
+ @subscription = subscription
279
+ end
280
+ end
281
+
282
+ if block_given?
283
+ yield @subscription
284
+ end
285
+
286
+ return @subscription
287
+ end
288
+
269
289
  # Create a new Item in the given Cart. You should not instantize this class directly
270
290
  # but use Cart#create_item instead.
271
291
  def initialize(shopping_cart)
@@ -365,6 +385,179 @@ module Google4R #:nodoc:
365
385
  return result
366
386
  end
367
387
  end
388
+
389
+ class Subscription
390
+
391
+ # Constants for period
392
+ DAILY = 'DAILY'
393
+ WEEKLY = 'WEEKLY'
394
+ SEMI_MONTHLY = 'SEMI_MONTHLY'
395
+ MONTHLY = 'MONTHLY'
396
+ EVERY_TWO_MONTHS = 'EVERY_TWO_MONTHS'
397
+ QUARTERLY = 'QUARTERLY'
398
+ YEARLY = 'YEARLY'
399
+
400
+ # Constants for type
401
+ MERCHANT = 'merchant'
402
+ GOOGLE = 'google'
403
+
404
+ # Optional. The no-charge-after attribute specifies the latest date and time that
405
+ # you can charge the customer for the subscription. This element can help you to
406
+ # ensure that you do not overcharge your customers.
407
+ attr_accessor :no_charge_after
408
+
409
+ # Required. The period attribute specifies how frequently you will charge the
410
+ # customer for the subscription. Valid values for this attribute are DAILY,
411
+ # WEEKLY, SEMI_MONTHLY, MONTHLY, EVERY_TWO_MONTHS, QUARTERLY, and YEARLY.
412
+ attr_reader :period
413
+
414
+ def period=(period)
415
+ unless [DAILY, WEEKLY, SEMI_MONTHLY, MONTHLY, EVERY_TWO_MONTHS, QUARTERLY, YEARLY].include?(period)
416
+ raise "period can only be set to DAILY, WEEKLY, SEMI_MONTHLY, MONTHLY, EVERY_TWO_MONTHS, QUARTERLY, or YEARLY"
417
+ end
418
+ @period = period
419
+ end
420
+
421
+ # Optional. The start-date attribute specifies the date that the subscription's
422
+ # recurrence period will begin. Like all dates in Checkout, this is in ISO 8601
423
+ # format. If you set the <unit-price> tag's value to a nonzero value, then the
424
+ # start-date for the subscription will automatically be set to the time that is
425
+ # exactly one recurrence period after the order is placed.
426
+ attr_accessor :start_date
427
+
428
+ # Required. The type attribute identifies the type of subscription that you are
429
+ # creating. The valid values for this attribute are merchant and google, and this
430
+ # specifies who handles the recurrences. The merchant value specifies
431
+ # Merchant-Handled recurrences, and the google value specifies Google-Handled
432
+ # recurrences.
433
+ attr_reader :type
434
+
435
+ def type=(type)
436
+ unless [MERCHANT, GOOGLE].include?(type)
437
+ raise "type can only be set to MERCHANT or GOOGLE"
438
+ end
439
+ @type = type
440
+ end
441
+
442
+ # Container for payments
443
+ attr_reader :payments
444
+
445
+ def add_payment(&block)
446
+ payment = SubscriptionPayment.new(self)
447
+ @payments << payment
448
+
449
+ # Pass the newly generated payment to the given block to set its attributes.
450
+ yield(payment) if block_given?
451
+
452
+ return payment
453
+ end
454
+
455
+ # Container for recurrent items
456
+ attr_reader :recurrent_items
457
+
458
+ def add_recurrent_item(&block)
459
+ item = RecurrentItem.new(self)
460
+ @recurrent_items << item
461
+
462
+ # Pass the newly generated item to the given block to set its attributes.
463
+ yield(item) if block_given?
464
+
465
+ return item
466
+ end
467
+
468
+ def initialize
469
+ @payments = []
470
+ @recurrent_items = []
471
+ end
472
+
473
+ def self.create_from_element(element)
474
+ result = Subscription.new
475
+ result.no_charge_after = Time.iso8601(element.attributes['no-charge-after']) rescue nil
476
+ result.period = element.attributes['period'] rescue nil
477
+ result.start_date = Time.iso8601(element.attributes['start-date']) rescue nil
478
+ result.type = element.attributes['type'] rescue nil
479
+
480
+ element.elements['payments/subscription-payment'].each do |payment_element|
481
+ result.payments << SubscriptionPayment.create_from_element(subscription, payment_element)
482
+ end
483
+
484
+ element.elements['recurrent-item'].each do |item_element|
485
+ result.recurrent_items << Item.create_from_element(item_element)
486
+ end
487
+
488
+ return result
489
+ end
490
+
491
+ class SubscriptionPayment
492
+
493
+ attr_accessor :subscription
494
+
495
+ # Optional. The times attribute indicates how many times you will charge the
496
+ # customer for a defined subscription payment. A subscription may have multiple
497
+ # payment schedules, and the times attribute lets you indicate how many times
498
+ # each charge will be assessed. For example, you might charge the customer a
499
+ # reduced rate for the first three months of a subscription and then charge the
500
+ # standard rate each month thereafter.
501
+ attr_accessor :times
502
+
503
+ # The maximum amount that you will be allowed to charge the customer, including
504
+ # tax, for all recurrences (Money instance, required).
505
+ attr_reader :maximum_charge
506
+
507
+ def initialize(subscription)
508
+ @subscription = subscription
509
+ end
510
+
511
+ # Sets the maximum charge for this subscription payment. money must respond to
512
+ # :cents and :currency as the Money class does.
513
+ def maximum_charge=(money)
514
+ if not (money.respond_to?(:cents) and money.respond_to?(:currency)) then
515
+ raise "Invalid price - does not respond to :cents and :currency - #{money.inspect}."
516
+ end
517
+
518
+ @maximum_charge = money
519
+ end
520
+
521
+ def self.create_from_element(subscription, element)
522
+ result = SubscriptionPayment.new
523
+ result.subscription = subscription
524
+ result.times = element.attributes['times'].to_i rescue nil
525
+
526
+ maximum_charge = (element.elements['maximum-charge'].text.to_f * 100).to_i
527
+ maximum_charge_currency = element.elements['maximum-charge'].attributes['currency']
528
+ result.maximum_charge = Money.new(maximum_charge, maximum_charge_currency)
529
+
530
+ return result
531
+ end
532
+ end
533
+
534
+ class RecurrentItem < Item
535
+
536
+ attr_accessor :subscription
537
+
538
+ def initialize(subscription)
539
+ @subscription = subscription
540
+ end
541
+
542
+ def self.create_from_element(element, subscription)
543
+ item = super(element, nil)
544
+
545
+ result = RecurrentItem.new(subscription)
546
+ result.description = item.description
547
+ result.digital_content = item.digital_content
548
+ result.id = item.id
549
+ result.name = item.name
550
+ result.private_data = item.private_data
551
+ result.quantity = item.quantity
552
+ result.tax_table = item.tax_table
553
+ result.unit_price = item.unit_price
554
+ result.weight = item.weight
555
+
556
+ return result
557
+ end
558
+
559
+ end
560
+ end
368
561
  end
369
562
 
370
563
  # A TaxTable is an ordered array of TaxRule objects. You should create the TaxRule
@@ -1052,5 +1245,35 @@ module Google4R #:nodoc:
1052
1245
  @tracking_number = tracking_number.to_s
1053
1246
  end
1054
1247
  end
1248
+
1249
+ # financial_state
1250
+ # REVIEWING - Google Checkout is reviewing the order.
1251
+ # CHARGEABLE - The order is ready to be charged.
1252
+ # CHARGING - The order is being charged; you may not refund or cancel an order until is the charge is completed.
1253
+ # CHARGED - The order has been successfully charged; if the order was only partially charged, the buyer's account page will reflect the partial charge.
1254
+ # PAYMENT_DECLINED - The charge attempt failed.
1255
+ # CANCELLED - The seller canceled the order; an order's financial state cannot be changed after the order is canceled.
1256
+ # 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>.
1257
+ class FinancialState
1258
+ REVIEWING = 'REVIEWING'
1259
+ CHARGEABLE = 'CHARGEABLE'
1260
+ CHARGING = 'CHARGING'
1261
+ CHARGED = 'CHARGED'
1262
+ PAYMENT_DECLINED = 'PAYMENT_DECLINED'
1263
+ CANCELLED = 'CANCELLED'
1264
+ CANCELLED_BY_GOOGLE = 'CANCELLED_BY_GOOGLE'
1265
+ end
1266
+
1267
+ # fulfillment_state
1268
+ # NEW - The order has been received but not prepared for shipping.
1269
+ # PROCESSING - The order is being prepared for shipping.
1270
+ # DELIVERED - The seller has shipped the order.
1271
+ # WILL_NOT_DELIVER - The seller will not ship the order; this status is used for canceled orders.
1272
+ class FulfillmentState
1273
+ NEW = 'NEW'
1274
+ PROCESSING = 'PROCESSING'
1275
+ DELIVERED = 'DELIVERED'
1276
+ WILL_NOT_DELIVER = 'WILL_NOT_DELIVER'
1277
+ end
1055
1278
  end
1056
1279
  end
@@ -30,6 +30,7 @@
30
30
 
31
31
  require 'stringio'
32
32
  require 'rexml/document'
33
+ require 'time'
33
34
 
34
35
  module Google4R #:nodoc:
35
36
  module Checkout #:nodoc:
@@ -67,11 +68,13 @@ module Google4R #:nodoc:
67
68
  SendBuyerMessageCommand => 'send-buyer-message',
68
69
  ArchiveOrderCommand => 'archive-order',
69
70
  UnarchiveOrderCommand => 'unarchive-order',
71
+ CreateOrderRecurrenceRequestCommand => 'create-order-recurrence-request',
70
72
  ShipItemsCommand => 'ship-items',
71
73
  BackorderItemsCommand => 'backorder-items',
72
74
  CancelItemsCommand => 'cancel-items',
73
75
  ReturnItemsCommand => 'return-items',
74
- ResetItemsShippingInformationCommand => 'reset-items-shipping-information'
76
+ ResetItemsShippingInformationCommand => 'reset-items-shipping-information',
77
+ OrderReportCommand => 'order-list-request',
75
78
  }
76
79
 
77
80
  def initialize(command)
@@ -289,6 +292,66 @@ module Google4R #:nodoc:
289
292
  if not item.digital_content.nil? then
290
293
  self.process_digital_content(item_element, item.digital_content)
291
294
  end
295
+
296
+ if not (item.kind_of? Item::Subscription::RecurrentItem or item.subscription.nil?) then
297
+ self.process_subscription(item_element, item.subscription)
298
+ end
299
+ end
300
+
301
+ # Adds a <subscription> element to a parent (<item>) element
302
+ def process_subscription(parent, subscription)
303
+ subscription_element = parent.add_element('subscription')
304
+
305
+ if not subscription.no_charge_after.nil? then
306
+ subscription_element.attributes['no-charge-after'] = subscription.no_charge_after.xmlschema
307
+ end
308
+
309
+ if not subscription.period.nil? then
310
+ subscription_element.attributes['period'] = subscription.period.to_s
311
+ end
312
+
313
+ if not subscription.start_date.nil? then
314
+ subscription_element.attributes['start-date'] = subscription.start_date.xmlschema
315
+ end
316
+
317
+ if not subscription.type.nil? then
318
+ subscription_element.attributes['type'] = subscription.type.to_s
319
+ end
320
+
321
+ if subscription.payments.length > 0
322
+ payments_element = subscription_element.add_element('payments')
323
+
324
+ subscription.payments.each do |payment|
325
+ self.process_subscription_payment(payments_element, payment)
326
+ end
327
+ end
328
+
329
+ if subscription.recurrent_items.length > 0
330
+ # this is a little bit of a hack; we use the normal way of generating items
331
+ # for a shopping cart, and then rename the elements to 'recurrent-item'
332
+ # after the fact
333
+
334
+ subscription.recurrent_items.each do |item|
335
+ self.process_item(subscription_element, item)
336
+ end
337
+
338
+ subscription_element.elements.each('item') do |item_element|
339
+ item_element.name = 'recurrent-item'
340
+ end
341
+ end
342
+ end
343
+
344
+ # Adds a <subcription-payment> element to a parent (<payments>) element
345
+ def process_subscription_payment(parent, payment)
346
+ payment_element = parent.add_element('subscription-payment')
347
+
348
+ if not payment.times.nil? then
349
+ payment_element.attributes['times'] = payment.times.to_s
350
+ end
351
+
352
+ if not payment.maximum_charge.nil? then
353
+ payment_element.add_element('maximum-charge', { 'currency' => payment.maximum_charge.currency }).text = payment.maximum_charge.to_s
354
+ end
292
355
  end
293
356
 
294
357
  # Adds a <digital-content> element to a parent (<item>) element
@@ -299,7 +362,7 @@ module Google4R #:nodoc:
299
362
  digital_content_element.add_element('description').text = digital_content.description.to_s
300
363
  end
301
364
 
302
- if digital_content.email_delivery? then
365
+ if not digital_content.email_delivery.nil? then
303
366
  digital_content_element.add_element('email-delivery').text = digital_content.email_delivery.to_s
304
367
  end
305
368
 
@@ -432,17 +495,17 @@ module Google4R #:nodoc:
432
495
  if not package.height.nil?
433
496
  height_element = element.add_element('height')
434
497
  height_element.add_attribute('unit', package.height.unit)
435
- height_element.add_attribute('value', package.height.value)
498
+ height_element.add_attribute('value', package.height.value.to_s)
436
499
  end
437
500
  if not package.length.nil?
438
501
  length_element = element.add_element('length')
439
502
  length_element.add_attribute('unit', package.length.unit)
440
- length_element.add_attribute('value', package.length.value)
503
+ length_element.add_attribute('value', package.length.value.to_s)
441
504
  end
442
505
  if not package.width.nil?
443
506
  width_element = element.add_element('width')
444
507
  width_element.add_attribute('unit', package.width.unit)
445
- width_element.add_attribute('value', package.width.value)
508
+ width_element.add_attribute('value', package.width.value.to_s)
446
509
  end
447
510
  end
448
511
 
@@ -685,6 +748,19 @@ module Google4R #:nodoc:
685
748
  end
686
749
  end
687
750
 
751
+ class CreateOrderRecurrenceRequestCommandXmlGenerator < CheckoutCommandXmlGenerator
752
+
753
+ protected
754
+
755
+ def process_command(command)
756
+ root = @document.add_element("create-order-recurrence-request" , { 'xmlns' => 'http://checkout.google.com/schema/2' })
757
+
758
+ root.attributes['google-order-number'] = command.google_order_number
759
+
760
+ self.process_shopping_shopping_cart(root, command.shopping_cart)
761
+ end
762
+ end
763
+
688
764
  class MerchantCalculationResultsXmlGenerator < XmlGenerator
689
765
 
690
766
  def initialize(merchant_calculation_results)
@@ -841,5 +917,39 @@ module Google4R #:nodoc:
841
917
 
842
918
  class ResetItemsShippingInformationCommandXmlGenerator < ItemsCommandXmlGenerator
843
919
  end
920
+
921
+ class ReturnOrderReportCommandXmlGenerator < CommandXmlGenerator
922
+ def initialize(command)
923
+ @command = command
924
+ end
925
+
926
+ protected
927
+
928
+ def process_command(command)
929
+ root = super
930
+ # TODO - sanity check format ?
931
+ root.add_attribute('start-date', command.start_date.to_s)
932
+ root.add_attribute('end-date', command.end_date.to_s)
933
+ flow_element = root
934
+
935
+ # <financial-state>
936
+ if command.financial_state then
937
+ financial_state_element = flow_element.add_element('financial-state')
938
+ financial_state_element.text = command.financial_state.to_s
939
+ end
940
+
941
+ # <fulfillment-state>
942
+ if command.fulfillment_state then
943
+ fulfillment_state_element = flow_element.add_element('fulfillment-state')
944
+ fulfillment_state_element.text = command.fulfillment_state.to_s
945
+ end
946
+
947
+ # <date-time-zone>
948
+ if command.date_time_zone then
949
+ dtz_element = flow_element.add_element('date-time-zone')
950
+ dtz_element.text = command.date_time_zone.to_s
951
+ end
952
+ end
953
+ end
844
954
  end
845
955
  end
@@ -62,6 +62,85 @@ class Google4R::Checkout::CheckoutCommandIntegrationTest < Test::Unit::TestCase
62
62
  # the redirect URL
63
63
  #puts @command.to_xml
64
64
  #puts result
65
+
66
+ assert_kind_of CheckoutRedirectResponse, result
67
+ end
68
+
69
+ def test_sending_to_google_works_with_google_handled_subscription
70
+ setup_command(@command)
71
+
72
+ @command.shopping_cart.create_item do |item|
73
+ item.name = "Test subscription"
74
+ item.description = "12 month subscription"
75
+ item.unit_price = Money.us_dollar(0)
76
+ item.quantity = 1
77
+ item.private_data = { :id => 123456 }
78
+
79
+ item.create_subscription do |subscription|
80
+ subscription.type = "google"
81
+ subscription.period = "MONTHLY"
82
+
83
+ subscription.add_payment do |payment|
84
+ payment.times = 12
85
+ payment.maximum_charge = Money.us_dollar(1200)
86
+ end
87
+
88
+ subscription.add_recurrent_item do |rec_item|
89
+ rec_item.name = "Usage of My Awesome Website for One Month"
90
+ rec_item.description = "Your flat charge for accessing my web site"
91
+ rec_item.quantity = 1
92
+ rec_item.unit_price = Money.us_dollar(1200)
93
+
94
+ rec_item.create_digital_content do |content|
95
+ content.display_disposition = "OPTIMISTIC"
96
+ content.url = "http://mywebsite.example.com"
97
+ content.description = "Pie is found at this web site!"
98
+ end
99
+ end
100
+
101
+ item.create_digital_content do |content|
102
+ content.display_disposition = "OPTIMISTIC"
103
+ content.description = "Congratulations! Your subscription is being set up. Feel free to log onto" +
104
+ "<a href=\"http://mywebsite.example.com\">My website</a>."
105
+ end
106
+ end
107
+ end
108
+
109
+ result = @command.send_to_google_checkout
110
+ assert_kind_of CheckoutRedirectResponse, result
111
+ end
112
+
113
+ def test_sending_to_google_works_with_merchant_handled_subscription
114
+ setup_command(@command)
115
+
116
+ @command.shopping_cart.create_item do |item|
117
+ item.name = "Test subscription"
118
+ item.description = "12 month subscription"
119
+ item.unit_price = Money.us_dollar(0)
120
+ item.quantity = 1
121
+ item.private_data = { :id => 123456 }
122
+
123
+ item.create_subscription do |subscription|
124
+ subscription.type = "merchant"
125
+ subscription.period = "MONTHLY"
126
+ subscription.start_date = Time.new
127
+ subscription.start_date += (60 * 60 * 24 * 30)
128
+ subscription.no_charge_after = subscription.start_date + (60 * 60 * 24 * 365)
129
+
130
+ subscription.add_payment do |payment|
131
+ payment.times = 12
132
+ payment.maximum_charge = Money.us_dollar(1200)
133
+ end
134
+
135
+ item.create_digital_content do |content|
136
+ content.display_disposition = "OPTIMISTIC"
137
+ content.description = "Congratulations! Your subscription is being set up. Feel free to log onto" +
138
+ "<a href=\"http://mywebsite.example.com\">My website</a>."
139
+ end
140
+ end
141
+ end
142
+
143
+ result = @command.send_to_google_checkout
65
144
  assert_kind_of CheckoutRedirectResponse, result
66
145
  end
67
146
 
@@ -158,6 +237,16 @@ class Google4R::Checkout::CheckoutCommandIntegrationTest < Test::Unit::TestCase
158
237
  item.quantity = i * 3
159
238
  item.id = "test-#{i}-123456789"
160
239
  item.weight = Weight.new(2.2)
240
+ if (i == 5)
241
+ item.create_digital_content do |dc|
242
+ dc.display_disposition =
243
+ Google4R::Checkout::Item::DigitalContent::OPTIMISTIC
244
+ dc.description = "Information on how to get your content"
245
+ dc.url = "http://my.domain.com/downloads"
246
+ dc.key = "abcde12345"
247
+ dc.email_delivery = false
248
+ end
249
+ end
161
250
  end
162
251
  end
163
252
  end
@@ -55,7 +55,8 @@ class Google4R::Checkout::FrontendTest < Test::Unit::TestCase
55
55
  :create_add_tracking_data_command, :create_archive_order_command,
56
56
  :create_unarchive_order_command, :create_ship_items_command,
57
57
  :create_backorder_items_command, :create_return_items_command,
58
- :create_cancel_items_command, :create_reset_items_shipping_information_command
58
+ :create_cancel_items_command, :create_reset_items_shipping_information_command,
59
+ :create_order_report_command
59
60
  ].each do |symbol|
60
61
  assert_respond_to @frontend, symbol
61
62
  end
@@ -130,7 +131,14 @@ class Google4R::Checkout::FrontendTest < Test::Unit::TestCase
130
131
  end
131
132
 
132
133
  def test_create_reset_items_shipping_information_command_works_correctly
133
- assert_kind_of ResetItemsShippingInformationCommand, @frontend.create_reset_items_shipping_information_command
134
+ assert_kind_of ResetItemsShippingInformationCommand,
135
+ @frontend.create_reset_items_shipping_information_command
134
136
  end
135
137
 
138
+ def test_create_order_report_command_works_correctly
139
+ assert_kind_of OrderReportCommand,
140
+ @frontend.create_order_report_command(
141
+ Time.utc(2007, 9, 1, 0, 0, 0),
142
+ Time.utc(2007, 9, 30, 23, 59, 59))
143
+ end
136
144
  end
@@ -0,0 +1,111 @@
1
+ #--
2
+ # Project: google_checkout4r
3
+ # File: test/unit/order_report_command_test.rb
4
+ # Author: Tony Chan <api.htchan at gmail dot com>
5
+ # Copyright: (c) 2007 by Dan Dukeson
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
+
28
+ require File.expand_path(File.dirname(__FILE__)) + '/../test_helper'
29
+
30
+ require 'google4r/checkout'
31
+
32
+ require 'test/frontend_configuration'
33
+
34
+ # Tests for the CancelItemsCommand class.
35
+ class Google4R::Checkout::OrderReportCommandTest < Test::Unit::TestCase
36
+ include Google4R::Checkout
37
+
38
+ def setup
39
+ @frontend = Frontend.new(FRONTEND_CONFIGURATION)
40
+ @command = @frontend.create_order_report_command(
41
+ Time.utc(2007, 9, 1, 0, 0, 0),
42
+ Time.utc(2007, 9, 30, 23, 59, 59))
43
+ @command.financial_state = 'CHARGED'
44
+ @command.fulfillment_state = 'NEW'
45
+ @command.date_time_zone = 'America/New_York'
46
+
47
+ @sample_xml=%Q{<?xml version='1.0' encoding='UTF-8'?>
48
+ <order-list-request end-date='2007-09-30T23:59:59' start-date='2007-09-01T00:00:00' xmlns='http://checkout.google.com/schema/2'>
49
+ <financial-state>CHARGED</financial-state>
50
+ <fulfillment-state>NEW</fulfillment-state>
51
+ <date-time-zone>America/New_York</date-time-zone>
52
+ </order-list-request>}
53
+ end
54
+
55
+ def test_behaves_correctly
56
+ [ :start_date, :end_date,
57
+ :financial_state, :financial_state=,
58
+ :fulfillment_state, :fulfillment_state=,
59
+ :date_time_zone, :date_time_zone= ].each do |symbol|
60
+ assert_respond_to @command, symbol
61
+ end
62
+ end
63
+
64
+ def test_to_xml
65
+ assert_strings_equal(@sample_xml, @command.to_xml)
66
+ end
67
+
68
+ def test_accessors
69
+ assert_equal('2007-09-01T00:00:00', @command.start_date)
70
+ assert_equal('2007-09-30T23:59:59', @command.end_date)
71
+ assert_equal('CHARGED', @command.financial_state)
72
+ assert_equal('NEW', @command.fulfillment_state)
73
+ assert_equal('America/New_York', @command.date_time_zone)
74
+ end
75
+
76
+ def test_good_dates
77
+ assert_nothing_raised RuntimeError do
78
+ @frontend.create_order_report_command(
79
+ Time.utc(2007, 9, 1, 0, 0, 0),
80
+ Time.utc(2007, 9, 30, 23, 59, 59))
81
+ end
82
+ end
83
+
84
+ def test_dates_should_not_be_string
85
+ assert_raise RuntimeError do
86
+ @frontend.create_order_report_command(
87
+ '2007-09-01T00:00:00',
88
+ '2007-09-30T23:59:59')
89
+ end
90
+ end
91
+
92
+ def test_end_date_before_start_date
93
+ assert_raise RuntimeError do
94
+ @frontend.create_order_report_command(
95
+ Time.utc(2007, 9, 1, 0, 0, 0),
96
+ Time.utc(2006, 9, 30, 23, 59, 59))
97
+ end
98
+ end
99
+
100
+ def test_financial_state
101
+ assert_raise RuntimeError do
102
+ @command.financial_state = 'DUMMY'
103
+ end
104
+ end
105
+
106
+ def test_fulfillment_state
107
+ assert_raise RuntimeError do
108
+ @command.fulfillment_state = 'DUMMY'
109
+ end
110
+ end
111
+ end
metadata CHANGED
@@ -1,125 +1,149 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.4
3
- specification_version: 1
4
2
  name: google4r-checkout
5
3
  version: !ruby/object:Gem::Version
6
- version: 1.0.3
7
- date: 2008-08-12 00:00:00 -07:00
8
- summary: Ruby library to access the Google Checkout service and implement notification handlers.
9
- require_paths:
10
- - lib
11
- email:
12
- homepage:
13
- rubyforge_project:
14
- description: Ruby library to access the Google Checkout service and implement notification handlers.
15
- autorequire: ""
16
- default_executable:
17
- bindir: bin
18
- has_rdoc: false
19
- required_ruby_version: !ruby/object:Gem::Version::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: 1.8.4
24
- version:
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 6
9
+ version: 1.0.6
25
10
  platform: ruby
26
- signing_key:
27
- cert_chain:
28
- post_install_message:
29
11
  authors:
30
12
  - Tony Chan
13
+ autorequire: ""
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-01 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: money
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 7
30
+ - 1
31
+ version: 1.7.1
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description: Ruby library to access the Google Checkout service and implement notification handlers.
35
+ email:
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - README
42
+ - LICENSE
43
+ - CHANGES
31
44
  files:
32
- - lib/google4r/checkout/commands.rb
45
+ - lib/google4r/checkout.rb
33
46
  - lib/google4r/checkout/frontend.rb
34
- - lib/google4r/checkout/merchant_calculation.rb
35
- - lib/google4r/checkout/notifications.rb
36
47
  - lib/google4r/checkout/shared.rb
48
+ - lib/google4r/checkout/notifications.rb
37
49
  - lib/google4r/checkout/utils.rb
38
50
  - lib/google4r/checkout/xml_generation.rb
39
- - lib/google4r/checkout.rb
51
+ - lib/google4r/checkout/commands.rb
52
+ - lib/google4r/checkout/merchant_calculation.rb
40
53
  - var/cacert.pem
41
54
  - README
42
55
  - LICENSE
43
56
  - CHANGES
57
+ has_rdoc: true
58
+ homepage:
59
+ licenses: []
60
+
61
+ post_install_message:
62
+ rdoc_options: []
63
+
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 1
72
+ - 8
73
+ - 4
74
+ version: 1.8.4
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ segments:
80
+ - 0
81
+ version: "0"
82
+ requirements: []
83
+
84
+ rubyforge_project:
85
+ rubygems_version: 1.3.6
86
+ signing_key:
87
+ specification_version: 3
88
+ summary: Ruby library to access the Google Checkout service and implement notification handlers.
44
89
  test_files:
45
90
  - test/integration/checkout_command_test.rb
46
- - test/unit/add_merchant_order_number_command_test.rb
47
- - test/unit/add_tracking_data_command_test.rb
48
- - test/unit/address_test.rb
49
- - test/unit/anonymous_address_test.rb
50
- - test/unit/archive_order_command_test.rb
51
- - test/unit/area_test.rb
52
- - test/unit/authorization_amount_notification_test.rb
91
+ - test/unit/order_adjustment_test.rb
92
+ - test/unit/pickup_shipping_test.rb
93
+ - test/unit/merchant_code_test.rb
94
+ - test/unit/chargeback_amount_notification_test.rb
53
95
  - test/unit/authorize_order_command_test.rb
96
+ - test/unit/merchant_calculation_results_test.rb
97
+ - test/unit/risk_information_notification_test.rb
98
+ - test/unit/ship_items_command_test.rb
99
+ - test/unit/tax_table_test.rb
54
100
  - test/unit/backorder_items_command_test.rb
101
+ - test/unit/flat_rate_shipping_test.rb
102
+ - test/unit/refund_order_command_test.rb
103
+ - test/unit/merchant_code_result_test.rb
55
104
  - test/unit/callback_handler_test.rb
56
- - test/unit/cancel_items_command_test.rb
57
- - test/unit/cancel_order_command_test.rb
58
- - test/unit/carrier_calculated_shipping_test.rb
59
- - test/unit/charge_amount_notification_test.rb
60
105
  - test/unit/charge_order_command_test.rb
61
- - test/unit/chargeback_amount_notification_test.rb
62
- - test/unit/checkout_command_test.rb
63
- - test/unit/checkout_command_xml_generator_test.rb
64
- - test/unit/command_test.rb
65
- - test/unit/deliver_order_command_test.rb
66
- - test/unit/delivery_method_test.rb
67
- - test/unit/digital_content_test.rb
68
- - test/unit/flat_rate_shipping_test.rb
106
+ - test/unit/charge_amount_notification_test.rb
107
+ - test/unit/carrier_calculated_shipping_test.rb
108
+ - test/unit/return_items_command_test.rb
109
+ - test/unit/add_merchant_order_number_command_test.rb
110
+ - test/unit/authorization_amount_notification_test.rb
69
111
  - test/unit/frontend_test.rb
112
+ - test/unit/add_tracking_data_command_test.rb
113
+ - test/unit/address_test.rb
70
114
  - test/unit/item_info_test.rb
115
+ - test/unit/order_state_change_notification_test.rb
116
+ - test/unit/us_state_area_test.rb
117
+ - test/unit/notification_handler_test.rb
118
+ - test/unit/us_country_area_test.rb
119
+ - test/unit/shopping_cart_test.rb
120
+ - test/unit/reset_items_shipping_information_command_test.rb
121
+ - test/unit/order_report_command_test.rb
122
+ - test/unit/send_buyer_message_command_test.rb
71
123
  - test/unit/item_test.rb
72
- - test/unit/marketing_preferences_test.rb
124
+ - test/unit/deliver_order_command_test.rb
125
+ - test/unit/cancel_order_command_test.rb
126
+ - test/unit/archive_order_command_test.rb
127
+ - test/unit/world_area_test.rb
128
+ - test/unit/new_order_notification_test.rb
129
+ - test/unit/private_data_parser_test.rb
73
130
  - test/unit/merchant_calculated_shipping_test.rb
74
- - test/unit/merchant_calculation_callback_test.rb
131
+ - test/unit/cancel_items_command_test.rb
132
+ - test/unit/checkout_command_test.rb
133
+ - test/unit/area_test.rb
75
134
  - test/unit/merchant_calculation_result_test.rb
76
- - test/unit/merchant_calculation_results_test.rb
77
- - test/unit/merchant_code_result_test.rb
78
- - test/unit/merchant_code_test.rb
79
- - test/unit/new_order_notification_test.rb
135
+ - test/unit/marketing_preferences_test.rb
80
136
  - test/unit/notification_acknowledgement_test.rb
81
- - test/unit/notification_handler_test.rb
82
- - test/unit/order_adjustment_test.rb
83
- - test/unit/order_state_change_notification_test.rb
84
- - test/unit/pickup_shipping_test.rb
85
- - test/unit/postal_area_test.rb
86
- - test/unit/private_data_parser_test.rb
87
137
  - test/unit/refund_amount_notification_test.rb
88
- - test/unit/refund_order_command_test.rb
89
- - test/unit/reset_items_shipping_information_command_test.rb
90
- - test/unit/return_items_command_test.rb
91
- - test/unit/risk_information_notification_test.rb
92
- - test/unit/send_buyer_message_command_test.rb
93
- - test/unit/ship_items_command_test.rb
94
- - test/unit/shipping_adjustment_test.rb
95
- - test/unit/shopping_cart_test.rb
96
138
  - test/unit/tax_rule_test.rb
97
- - test/unit/tax_table_test.rb
98
- - test/unit/tracking_data_test.rb
99
139
  - test/unit/unarchive_order_command_test.rb
100
- - test/unit/us_country_area_test.rb
101
- - test/unit/us_state_area_test.rb
140
+ - test/unit/delivery_method_test.rb
141
+ - test/unit/checkout_command_xml_generator_test.rb
142
+ - test/unit/shipping_adjustment_test.rb
143
+ - test/unit/tracking_data_test.rb
144
+ - test/unit/postal_area_test.rb
145
+ - test/unit/anonymous_address_test.rb
102
146
  - test/unit/us_zip_area_test.rb
103
- - test/unit/world_area_test.rb
104
- rdoc_options: []
105
-
106
- extra_rdoc_files:
107
- - README
108
- - LICENSE
109
- - CHANGES
110
- executables: []
111
-
112
- extensions: []
113
-
114
- requirements: []
115
-
116
- dependencies:
117
- - !ruby/object:Gem::Dependency
118
- name: money
119
- version_requirement:
120
- version_requirements: !ruby/object:Gem::Version::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: 1.7.1
125
- version:
147
+ - test/unit/digital_content_test.rb
148
+ - test/unit/command_test.rb
149
+ - test/unit/merchant_calculation_callback_test.rb