dfg-paypal 0.8.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.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +25 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +18 -0
  6. data/Gemfile +13 -0
  7. data/Rakefile +19 -0
  8. data/VERSION +1 -0
  9. data/dfg-paypal.gemspec +28 -0
  10. data/lib/paypal.rb +84 -0
  11. data/lib/paypal/base.rb +19 -0
  12. data/lib/paypal/exception.rb +4 -0
  13. data/lib/paypal/exception/api_error.rb +94 -0
  14. data/lib/paypal/exception/http_error.rb +12 -0
  15. data/lib/paypal/express.rb +1 -0
  16. data/lib/paypal/express/request.rb +207 -0
  17. data/lib/paypal/express/response.rb +35 -0
  18. data/lib/paypal/ipn.rb +23 -0
  19. data/lib/paypal/nvp/request.rb +64 -0
  20. data/lib/paypal/nvp/response.rb +234 -0
  21. data/lib/paypal/payment/common/amount.rb +13 -0
  22. data/lib/paypal/payment/recurring.rb +43 -0
  23. data/lib/paypal/payment/recurring/activation.rb +14 -0
  24. data/lib/paypal/payment/recurring/billing.rb +39 -0
  25. data/lib/paypal/payment/recurring/summary.rb +11 -0
  26. data/lib/paypal/payment/request.rb +67 -0
  27. data/lib/paypal/payment/request/item.rb +26 -0
  28. data/lib/paypal/payment/response.rb +73 -0
  29. data/lib/paypal/payment/response/address.rb +7 -0
  30. data/lib/paypal/payment/response/info.rb +45 -0
  31. data/lib/paypal/payment/response/item.rb +41 -0
  32. data/lib/paypal/payment/response/payer.rb +7 -0
  33. data/lib/paypal/payment/response/reference.rb +9 -0
  34. data/lib/paypal/payment/response/refund.rb +13 -0
  35. data/lib/paypal/util.rb +28 -0
  36. data/spec/fake_response/BillAgreementUpdate/fetch.txt +1 -0
  37. data/spec/fake_response/BillAgreementUpdate/revoke.txt +1 -0
  38. data/spec/fake_response/CreateBillingAgreement/success.txt +1 -0
  39. data/spec/fake_response/CreateRecurringPaymentsProfile/failure.txt +1 -0
  40. data/spec/fake_response/CreateRecurringPaymentsProfile/success.txt +1 -0
  41. data/spec/fake_response/DoCapture/failure.txt +1 -0
  42. data/spec/fake_response/DoCapture/success.txt +1 -0
  43. data/spec/fake_response/DoExpressCheckoutPayment/failure.txt +1 -0
  44. data/spec/fake_response/DoExpressCheckoutPayment/success.txt +1 -0
  45. data/spec/fake_response/DoExpressCheckoutPayment/success_with_billing_agreement.txt +1 -0
  46. data/spec/fake_response/DoExpressCheckoutPayment/success_with_many_items.txt +1 -0
  47. data/spec/fake_response/DoReferenceTransaction/failure.txt +1 -0
  48. data/spec/fake_response/DoReferenceTransaction/success.txt +1 -0
  49. data/spec/fake_response/DoVoid/success.txt +1 -0
  50. data/spec/fake_response/GetExpressCheckoutDetails/failure.txt +1 -0
  51. data/spec/fake_response/GetExpressCheckoutDetails/success.txt +1 -0
  52. data/spec/fake_response/GetExpressCheckoutDetails/with_billing_accepted_status.txt +1 -0
  53. data/spec/fake_response/GetRecurringPaymentsProfileDetails/failure.txt +1 -0
  54. data/spec/fake_response/GetRecurringPaymentsProfileDetails/success.txt +1 -0
  55. data/spec/fake_response/GetTransactionDetails/failure.txt +1 -0
  56. data/spec/fake_response/GetTransactionDetails/success.txt +1 -0
  57. data/spec/fake_response/IPN/invalid.txt +1 -0
  58. data/spec/fake_response/IPN/valid.txt +1 -0
  59. data/spec/fake_response/ManageRecurringPaymentsProfileStatus/failure.txt +1 -0
  60. data/spec/fake_response/ManageRecurringPaymentsProfileStatus/success.txt +1 -0
  61. data/spec/fake_response/RefundTransaction/full.txt +1 -0
  62. data/spec/fake_response/SetExpressCheckout/failure.txt +1 -0
  63. data/spec/fake_response/SetExpressCheckout/success.txt +1 -0
  64. data/spec/helpers/fake_response_helper.rb +33 -0
  65. data/spec/paypal/exception/api_error_spec.rb +78 -0
  66. data/spec/paypal/exception/http_error_spec.rb +8 -0
  67. data/spec/paypal/express/request_spec.rb +602 -0
  68. data/spec/paypal/express/response_spec.rb +80 -0
  69. data/spec/paypal/ipn_spec.rb +19 -0
  70. data/spec/paypal/nvp/request_spec.rb +116 -0
  71. data/spec/paypal/nvp/response_spec.rb +146 -0
  72. data/spec/paypal/payment/common/amount_spec.rb +36 -0
  73. data/spec/paypal/payment/recurring/activation_spec.rb +19 -0
  74. data/spec/paypal/payment/recurring_spec.rb +170 -0
  75. data/spec/paypal/payment/request/item_spec.rb +27 -0
  76. data/spec/paypal/payment/request_spec.rb +136 -0
  77. data/spec/paypal/payment/response/address_spec.rb +26 -0
  78. data/spec/paypal/payment/response/info_spec.rb +93 -0
  79. data/spec/paypal/payment/response/item_spec.rb +42 -0
  80. data/spec/paypal/payment/response/payer_spec.rb +26 -0
  81. data/spec/paypal/payment/response_spec.rb +16 -0
  82. data/spec/paypal/util_spec.rb +32 -0
  83. data/spec/spec_helper.rb +25 -0
  84. metadata +225 -0
@@ -0,0 +1,35 @@
1
+ module Paypal
2
+ module Express
3
+ class Response < NVP::Response
4
+ attr_accessor :pay_on_paypal, :mobile
5
+
6
+ def initialize(response, options = {})
7
+ super response
8
+ @pay_on_paypal = options[:pay_on_paypal]
9
+ @mobile = options[:mobile]
10
+ end
11
+
12
+ def redirect_uri
13
+ endpoint = URI.parse Paypal.endpoint
14
+ endpoint.query = query(:with_cmd).to_query
15
+ endpoint.to_s
16
+ end
17
+
18
+ def popup_uri
19
+ endpoint = URI.parse Paypal.popup_endpoint
20
+ endpoint.query = query.to_query
21
+ endpoint.to_s
22
+ end
23
+
24
+ private
25
+
26
+ def query(with_cmd = false)
27
+ _query_ = {:token => self.token}
28
+ _query_.merge!(:cmd => '_express-checkout') if with_cmd
29
+ _query_.merge!(:cmd => '_express-checkout-mobile') if mobile
30
+ _query_.merge!(:useraction => 'commit') if pay_on_paypal
31
+ _query_
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ module Paypal
2
+ module IPN
3
+ def self.endpoint
4
+ _endpoint_ = URI.parse Paypal.endpoint
5
+ _endpoint_.query = {
6
+ :cmd => '_notify-validate'
7
+ }.to_query
8
+ _endpoint_.to_s
9
+ end
10
+
11
+ def self.verify!(raw_post)
12
+ response = RestClient.post(
13
+ endpoint, raw_post
14
+ )
15
+ case response.body
16
+ when 'VERIFIED'
17
+ true
18
+ else
19
+ raise Exception::APIError.new(response.body)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,64 @@
1
+ module Paypal
2
+ module NVP
3
+ class Request < Base
4
+ attr_required :username, :password, :signature
5
+ attr_optional :subject
6
+ attr_accessor :version
7
+
8
+ ENDPOINT = {
9
+ :production => 'https://api-3t.paypal.com/nvp',
10
+ :sandbox => 'https://api-3t.sandbox.paypal.com/nvp'
11
+ }
12
+
13
+ def self.endpoint
14
+ if Paypal.sandbox?
15
+ ENDPOINT[:sandbox]
16
+ else
17
+ ENDPOINT[:production]
18
+ end
19
+ end
20
+
21
+ def initialize(attributes = {})
22
+ @version = Paypal.api_version
23
+ super
24
+ end
25
+
26
+ def common_params
27
+ {
28
+ :USER => self.username,
29
+ :PWD => self.password,
30
+ :SIGNATURE => self.signature,
31
+ :SUBJECT => self.subject,
32
+ :VERSION => self.version
33
+ }
34
+ end
35
+
36
+ def request(method, params = {})
37
+ handle_response do
38
+ post(method, params)
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def post(method, params)
45
+ RestClient.post(self.class.endpoint, common_params.merge(params).merge(:METHOD => method))
46
+ end
47
+
48
+ def handle_response
49
+ response = yield
50
+ response = CGI.parse(response).inject({}) do |res, (k, v)|
51
+ res.merge!(k.to_sym => v.first)
52
+ end
53
+ case response[:ACK]
54
+ when 'Success', 'SuccessWithWarning'
55
+ response
56
+ else
57
+ raise Exception::APIError.new(response)
58
+ end
59
+ rescue RestClient::Exception => e
60
+ raise Exception::HttpError.new(e.http_code, e.message, e.http_body)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,234 @@
1
+ module Paypal
2
+ module NVP
3
+ class Response < Base
4
+ cattr_reader :attribute_mapping
5
+ @@attribute_mapping = {
6
+ :ACK => :ack,
7
+ :BUILD => :build,
8
+ :BILLINGAGREEMENTACCEPTEDSTATUS => :billing_agreement_accepted_status,
9
+ :CHECKOUTSTATUS => :checkout_status,
10
+ :CORRELATIONID => :correlation_id,
11
+ :COUNTRYCODE => :country_code,
12
+ :CURRENCYCODE => :currency_code,
13
+ :DESC => :description,
14
+ :NOTIFYURL => :notify_url,
15
+ :TIMESTAMP => :timestamp,
16
+ :TOKEN => :token,
17
+ :VERSION => :version,
18
+ # Some of the attributes below are duplicates of what
19
+ # exists in the payment response, but paypal doesn't
20
+ # prefix these with PAYMENTREQUEST when issuing a
21
+ # GetTransactionDetails response.
22
+ :RECEIVEREMAIL => :receiver_email,
23
+ :RECEIVERID => :receiver_id,
24
+ :SUBJECT => :subject,
25
+ :TRANSACTIONID => :transaction_id,
26
+ :TRANSACTIONTYPE => :transaction_type,
27
+ :PAYMENTTYPE => :payment_type,
28
+ :ORDERTIME => :order_time,
29
+ :PAYMENTSTATUS => :payment_status,
30
+ :PENDINGREASON => :pending_reason,
31
+ :REASONCODE => :reason_code,
32
+ :PROTECTIONELIGIBILITY => :protection_eligibility,
33
+ :PROTECTIONELIGIBILITYTYPE => :protection_eligibility_type,
34
+ :ADDRESSOWNER => :address_owner,
35
+ :ADDRESSSTATUS => :address_status,
36
+ :INVNUM => :invoice_number,
37
+ :CUSTOM => :custom
38
+ }
39
+ attr_accessor *@@attribute_mapping.values
40
+ attr_accessor :shipping_options_is_default, :success_page_redirect_requested, :insurance_option_selected
41
+ attr_accessor :amount, :description, :ship_to, :bill_to, :payer, :recurring, :billing_agreement, :refund
42
+ attr_accessor :payment_responses, :payment_info, :items
43
+ alias_method :colleration_id, :correlation_id # NOTE: I made a typo :p
44
+
45
+ def initialize(attributes = {})
46
+ attrs = attributes.dup
47
+ @@attribute_mapping.each do |key, value|
48
+ self.send "#{value}=", attrs.delete(key)
49
+ end
50
+ @shipping_options_is_default = attrs.delete(:SHIPPINGOPTIONISDEFAULT) == 'true'
51
+ @success_page_redirect_requested = attrs.delete(:SUCCESSPAGEREDIRECTREQUESTED) == 'true'
52
+ @insurance_option_selected = attrs.delete(:INSURANCEOPTIONSELECTED) == 'true'
53
+ @amount = Payment::Common::Amount.new(
54
+ :total => attrs.delete(:AMT),
55
+ :item => attrs.delete(:ITEMAMT),
56
+ :handing => attrs.delete(:HANDLINGAMT),
57
+ :insurance => attrs.delete(:INSURANCEAMT),
58
+ :ship_disc => attrs.delete(:SHIPDISCAMT),
59
+ :shipping => attrs.delete(:SHIPPINGAMT),
60
+ :tax => attrs.delete(:TAXAMT),
61
+ :fee => attrs.delete(:FEEAMT)
62
+ )
63
+ @ship_to = Payment::Response::Address.new(
64
+ :owner => attrs.delete(:SHIPADDRESSOWNER),
65
+ :status => attrs.delete(:SHIPADDRESSSTATUS),
66
+ :name => attrs.delete(:SHIPTONAME),
67
+ :zip => attrs.delete(:SHIPTOZIP),
68
+ :street => attrs.delete(:SHIPTOSTREET),
69
+ :street2 => attrs.delete(:SHIPTOSTREET2),
70
+ :city => attrs.delete(:SHIPTOCITY),
71
+ :state => attrs.delete(:SHIPTOSTATE),
72
+ :country_code => attrs.delete(:SHIPTOCOUNTRYCODE),
73
+ :country_name => attrs.delete(:SHIPTOCOUNTRYNAME),
74
+ )
75
+ @bill_to = Payment::Response::Address.new(
76
+ :owner => attrs.delete(:ADDRESSID),
77
+ :status => attrs.delete(:ADDRESSSTATUS),
78
+ :name => attrs.delete(:BILLINGNAME),
79
+ :zip => attrs.delete(:ZIP),
80
+ :street => attrs.delete(:STREET),
81
+ :street2 => attrs.delete(:STREET2),
82
+ :city => attrs.delete(:CITY),
83
+ :state => attrs.delete(:STATE),
84
+ :country_code => attrs.delete(:COUNTRY)
85
+ )
86
+ if attrs[:PAYERID]
87
+ @payer = Payment::Response::Payer.new(
88
+ :identifier => attrs.delete(:PAYERID),
89
+ :status => attrs.delete(:PAYERSTATUS),
90
+ :first_name => attrs.delete(:FIRSTNAME),
91
+ :last_name => attrs.delete(:LASTNAME),
92
+ :email => attrs.delete(:EMAIL),
93
+ :company => attrs.delete(:BUSINESS),
94
+ :phone_number => attrs.delete(:PHONENUM)
95
+ )
96
+ end
97
+ if attrs[:PROFILEID]
98
+ @recurring = Payment::Recurring.new(
99
+ :identifier => attrs.delete(:PROFILEID),
100
+ # NOTE:
101
+ # CreateRecurringPaymentsProfile returns PROFILESTATUS
102
+ # GetRecurringPaymentsProfileDetails returns STATUS
103
+ :description => @description,
104
+ :status => attrs.delete(:STATUS) || attrs.delete(:PROFILESTATUS),
105
+ :start_date => attrs.delete(:PROFILESTARTDATE),
106
+ :name => attrs.delete(:SUBSCRIBERNAME),
107
+ :reference => attrs.delete(:PROFILEREFERENCE),
108
+ :auto_bill => attrs.delete(:AUTOBILLOUTAMT),
109
+ :max_fails => attrs.delete(:MAXFAILEDPAYMENTS),
110
+ :aggregate_amount => attrs.delete(:AGGREGATEAMT),
111
+ :aggregate_optional_amount => attrs.delete(:AGGREGATEOPTIONALAMT),
112
+ :final_payment_date => attrs.delete(:FINALPAYMENTDUEDATE)
113
+ )
114
+ if attrs[:BILLINGPERIOD]
115
+ @recurring.billing = Payment::Recurring::Billing.new(
116
+ :amount => @amount,
117
+ :currency_code => @currency_code,
118
+ :period => attrs.delete(:BILLINGPERIOD),
119
+ :frequency => attrs.delete(:BILLINGFREQUENCY),
120
+ :total_cycles => attrs.delete(:TOTALBILLINGCYCLES),
121
+ :trial => {
122
+ :period => attrs.delete(:TRIALBILLINGPERIOD),
123
+ :frequency => attrs.delete(:TRIALBILLINGFREQUENCY),
124
+ :total_cycles => attrs.delete(:TRIALTOTALBILLINGCYCLES),
125
+ :currency_code => attrs.delete(:TRIALCURRENCYCODE),
126
+ :amount => attrs.delete(:TRIALAMT),
127
+ :tax_amount => attrs.delete(:TRIALTAXAMT),
128
+ :shipping_amount => attrs.delete(:TRIALSHIPPINGAMT),
129
+ :paid => attrs.delete(:TRIALAMTPAID)
130
+ }
131
+ )
132
+ end
133
+ if attrs[:REGULARAMT]
134
+ @recurring.regular_billing = Payment::Recurring::Billing.new(
135
+ :amount => attrs.delete(:REGULARAMT),
136
+ :shipping_amount => attrs.delete(:REGULARSHIPPINGAMT),
137
+ :tax_amount => attrs.delete(:REGULARTAXAMT),
138
+ :currency_code => attrs.delete(:REGULARCURRENCYCODE),
139
+ :period => attrs.delete(:REGULARBILLINGPERIOD),
140
+ :frequency => attrs.delete(:REGULARBILLINGFREQUENCY),
141
+ :total_cycles => attrs.delete(:REGULARTOTALBILLINGCYCLES),
142
+ :paid => attrs.delete(:REGULARAMTPAID)
143
+ )
144
+ @recurring.summary = Payment::Recurring::Summary.new(
145
+ :next_billing_date => attrs.delete(:NEXTBILLINGDATE),
146
+ :cycles_completed => attrs.delete(:NUMCYCLESCOMPLETED),
147
+ :cycles_remaining => attrs.delete(:NUMCYCLESREMAINING),
148
+ :outstanding_balance => attrs.delete(:OUTSTANDINGBALANCE),
149
+ :failed_count => attrs.delete(:FAILEDPAYMENTCOUNT),
150
+ :last_payment_date => attrs.delete(:LASTPAYMENTDATE),
151
+ :last_payment_amount => attrs.delete(:LASTPAYMENTAMT)
152
+ )
153
+ end
154
+ end
155
+ if attrs[:BILLINGAGREEMENTID]
156
+ @billing_agreement = Payment::Response::Reference.new(
157
+ :identifier => attrs.delete(:BILLINGAGREEMENTID),
158
+ :description => attrs.delete(:BILLINGAGREEMENTDESCRIPTION),
159
+ :status => attrs.delete(:BILLINGAGREEMENTSTATUS)
160
+ )
161
+ billing_agreement_info = Payment::Response::Info.attribute_mapping.keys.inject({}) do |billing_agreement_info, key|
162
+ billing_agreement_info.merge! key => attrs.delete(key)
163
+ end
164
+ @billing_agreement.info = Payment::Response::Info.new billing_agreement_info
165
+ @billing_agreement.info.amount = @amount
166
+ end
167
+ if attrs[:REFUNDTRANSACTIONID]
168
+ @refund = Payment::Response::Refund.new(
169
+ :transaction_id => attrs.delete(:REFUNDTRANSACTIONID),
170
+ :amount => {
171
+ :total => attrs.delete(:TOTALREFUNDEDAMOUNT),
172
+ :fee => attrs.delete(:FEEREFUNDAMT),
173
+ :gross => attrs.delete(:GROSSREFUNDAMT),
174
+ :net => attrs.delete(:NETREFUNDAMT)
175
+ }
176
+ )
177
+ end
178
+
179
+ # payment_responses
180
+ payment_responses = []
181
+ attrs.keys.each do |_attr_|
182
+ prefix, index, key = case _attr_.to_s
183
+ when /^PAYMENTREQUEST/, /^PAYMENTREQUESTINFO/
184
+ _attr_.to_s.split('_')
185
+ when /^L_PAYMENTREQUEST/
186
+ _attr_.to_s.split('_')[1..-1]
187
+ end
188
+ if prefix
189
+ payment_responses[index.to_i] ||= {}
190
+ payment_responses[index.to_i][key.to_sym] = attrs.delete(_attr_)
191
+ end
192
+ end
193
+ @payment_responses = payment_responses.collect do |_attrs_|
194
+ Payment::Response.new _attrs_
195
+ end
196
+
197
+ # payment_info
198
+ payment_info = []
199
+ attrs.keys.each do |_attr_|
200
+ prefix, index, key = _attr_.to_s.split('_')
201
+ if prefix == 'PAYMENTINFO'
202
+ payment_info[index.to_i] ||= {}
203
+ payment_info[index.to_i][key.to_sym] = attrs.delete(_attr_)
204
+ end
205
+ end
206
+ @payment_info = payment_info.collect do |_attrs_|
207
+ Payment::Response::Info.new _attrs_
208
+ end
209
+
210
+ # payment_info
211
+ items = []
212
+ attrs.keys.each do |_attr_|
213
+ key, index = _attr_.to_s.scan(/^L_(.+?)(\d+)$/).flatten
214
+ if index
215
+ items[index.to_i] ||= {}
216
+ items[index.to_i][key.to_sym] = attrs.delete(_attr_)
217
+ end
218
+ end
219
+ @items = items.collect do |_attrs_|
220
+ Payment::Response::Item.new _attrs_
221
+ end
222
+
223
+ # remove duplicated parameters
224
+ attrs.delete(:SHIPTOCOUNTRY) # NOTE: Same with SHIPTOCOUNTRYCODE
225
+ attrs.delete(:SALESTAX) # Same as TAXAMT
226
+
227
+ # warn ignored attrs
228
+ attrs.each do |key, value|
229
+ Paypal.log "Ignored Parameter (#{self.class}): #{key}=#{value}", :warn
230
+ end
231
+ end
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,13 @@
1
+ module Paypal
2
+ module Payment
3
+ module Common
4
+ class Amount < Base
5
+ attr_optional :total, :item, :fee, :handing, :insurance, :ship_disc, :shipping, :tax, :gross, :net
6
+
7
+ def numeric_attribute?(key)
8
+ true
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,43 @@
1
+ module Paypal
2
+ module Payment
3
+ class Recurring < Base
4
+ attr_optional :start_date, :description, :identifier, :status, :name, :reference, :max_fails, :auto_bill, :aggregate_amount, :aggregate_optional_amount, :final_payment_date
5
+ attr_accessor :activation, :billing, :regular_billing, :summary
6
+
7
+ def initialize(attributes = {})
8
+ super
9
+ @activation = Activation.new attributes[:activation] if attributes[:activation]
10
+ @billing = Billing.new attributes[:billing] if attributes[:billing]
11
+ @regular_billing = Billing.new attributes[:regular_billing] if attributes[:regular_billing]
12
+ @summary = Summary.new attributes[:summary] if attributes[:summary]
13
+ end
14
+
15
+ def to_params
16
+ params = [
17
+ self.billing,
18
+ self.activation
19
+ ].compact.inject({}) do |params, attribute|
20
+ params.merge! attribute.to_params
21
+ end
22
+ if self.start_date.is_a?(Time)
23
+ self.start_date = self.start_date.to_s(:db)
24
+ end
25
+ params.merge!(
26
+ :DESC => self.description,
27
+ :MAXFAILEDPAYMENTS => self.max_fails,
28
+ :AUTOBILLOUTAMT => self.auto_bill,
29
+ :PROFILESTARTDATE => self.start_date,
30
+ :SUBSCRIBERNAME => self.name,
31
+ :PROFILEREFERENCE => self.reference
32
+ )
33
+ params.delete_if do |k, v|
34
+ v.blank?
35
+ end
36
+ end
37
+
38
+ def numeric_attribute?(key)
39
+ super || [:max_fails, :failed_count].include?(key)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,14 @@
1
+ module Paypal
2
+ module Payment
3
+ class Recurring::Activation < Base
4
+ attr_optional :initial_amount, :failed_action
5
+
6
+ def to_params
7
+ {
8
+ :INITAMT => Util.formatted_amount(self.initial_amount),
9
+ :FAILEDINITAMTACTION => self.failed_action
10
+ }
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,39 @@
1
+ module Paypal
2
+ module Payment
3
+ class Recurring::Billing < Base
4
+ attr_optional :period, :frequency, :paid, :currency_code, :total_cycles
5
+ attr_accessor :amount, :trial
6
+
7
+ def initialize(attributes = {})
8
+ @amount = if attributes[:amount].is_a?(Common::Amount)
9
+ attributes[:amount]
10
+ else
11
+ Common::Amount.new(
12
+ :total => attributes[:amount],
13
+ :tax => attributes[:tax_amount],
14
+ :shipping => attributes[:shipping_amount]
15
+ )
16
+ end
17
+ @trial = Recurring::Billing.new(attributes[:trial]) if attributes[:trial].present?
18
+ super
19
+ end
20
+
21
+ def to_params
22
+ trial_params = (trial.try(:to_params) || {}).inject({}) do |trial_params, (key, value)|
23
+ trial_params.merge(
24
+ :"TRIAL#{key}" => value
25
+ )
26
+ end
27
+ trial_params.merge(
28
+ :BILLINGPERIOD => self.period,
29
+ :BILLINGFREQUENCY => self.frequency,
30
+ :TOTALBILLINGCYCLES => self.total_cycles,
31
+ :AMT => Util.formatted_amount(self.amount.total),
32
+ :CURRENCYCODE => self.currency_code,
33
+ :SHIPPINGAMT => Util.formatted_amount(self.amount.shipping),
34
+ :TAXAMT => Util.formatted_amount(self.amount.tax)
35
+ )
36
+ end
37
+ end
38
+ end
39
+ end