ianfleeton-paypal-express 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 (92) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.gitignore +22 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +11 -0
  6. data/Gemfile +11 -0
  7. data/LICENSE +20 -0
  8. data/README.rdoc +43 -0
  9. data/Rakefile +19 -0
  10. data/VERSION +1 -0
  11. data/ianfleeton-paypal-express.gemspec +24 -0
  12. data/lib/paypal.rb +86 -0
  13. data/lib/paypal/base.rb +19 -0
  14. data/lib/paypal/exception.rb +4 -0
  15. data/lib/paypal/exception/api_error.rb +94 -0
  16. data/lib/paypal/exception/http_error.rb +12 -0
  17. data/lib/paypal/express.rb +1 -0
  18. data/lib/paypal/express/request.rb +186 -0
  19. data/lib/paypal/express/response.rb +35 -0
  20. data/lib/paypal/ipn.rb +23 -0
  21. data/lib/paypal/nvp/request.rb +66 -0
  22. data/lib/paypal/nvp/response.rb +237 -0
  23. data/lib/paypal/payment/common/amount.rb +13 -0
  24. data/lib/paypal/payment/recurring.rb +43 -0
  25. data/lib/paypal/payment/recurring/activation.rb +14 -0
  26. data/lib/paypal/payment/recurring/billing.rb +39 -0
  27. data/lib/paypal/payment/recurring/summary.rb +11 -0
  28. data/lib/paypal/payment/request.rb +67 -0
  29. data/lib/paypal/payment/request/item.rb +26 -0
  30. data/lib/paypal/payment/response.rb +75 -0
  31. data/lib/paypal/payment/response/address.rb +7 -0
  32. data/lib/paypal/payment/response/info.rb +45 -0
  33. data/lib/paypal/payment/response/item.rb +41 -0
  34. data/lib/paypal/payment/response/payee_info.rb +7 -0
  35. data/lib/paypal/payment/response/payer.rb +7 -0
  36. data/lib/paypal/payment/response/reference.rb +23 -0
  37. data/lib/paypal/payment/response/refund.rb +17 -0
  38. data/lib/paypal/payment/response/refund_info.rb +7 -0
  39. data/lib/paypal/util.rb +27 -0
  40. data/spec/fake_response/BillAgreementUpdate/fetch.txt +1 -0
  41. data/spec/fake_response/BillAgreementUpdate/revoke.txt +1 -0
  42. data/spec/fake_response/CreateBillingAgreement/success.txt +1 -0
  43. data/spec/fake_response/CreateRecurringPaymentsProfile/failure.txt +1 -0
  44. data/spec/fake_response/CreateRecurringPaymentsProfile/success.txt +1 -0
  45. data/spec/fake_response/DoCapture/failure.txt +1 -0
  46. data/spec/fake_response/DoCapture/success.txt +1 -0
  47. data/spec/fake_response/DoExpressCheckoutPayment/failure.txt +1 -0
  48. data/spec/fake_response/DoExpressCheckoutPayment/success.txt +1 -0
  49. data/spec/fake_response/DoExpressCheckoutPayment/success_with_billing_agreement.txt +1 -0
  50. data/spec/fake_response/DoExpressCheckoutPayment/success_with_many_items.txt +1 -0
  51. data/spec/fake_response/DoReferenceTransaction/failure.txt +1 -0
  52. data/spec/fake_response/DoReferenceTransaction/success.txt +1 -0
  53. data/spec/fake_response/DoVoid/success.txt +1 -0
  54. data/spec/fake_response/GetExpressCheckoutDetails/failure.txt +1 -0
  55. data/spec/fake_response/GetExpressCheckoutDetails/success.txt +1 -0
  56. data/spec/fake_response/GetExpressCheckoutDetails/with_billing_accepted_status.txt +1 -0
  57. data/spec/fake_response/GetRecurringPaymentsProfileDetails/failure.txt +1 -0
  58. data/spec/fake_response/GetRecurringPaymentsProfileDetails/success.txt +1 -0
  59. data/spec/fake_response/GetTransactionDetails/failure.txt +1 -0
  60. data/spec/fake_response/GetTransactionDetails/success.txt +1 -0
  61. data/spec/fake_response/IPN/invalid.txt +1 -0
  62. data/spec/fake_response/IPN/valid.txt +1 -0
  63. data/spec/fake_response/ManageRecurringPaymentsProfileStatus/failure.txt +1 -0
  64. data/spec/fake_response/ManageRecurringPaymentsProfileStatus/success.txt +1 -0
  65. data/spec/fake_response/RefundTransaction/full.txt +1 -0
  66. data/spec/fake_response/SetExpressCheckout/failure.txt +1 -0
  67. data/spec/fake_response/SetExpressCheckout/success.txt +1 -0
  68. data/spec/helpers/fake_response_helper.rb +29 -0
  69. data/spec/paypal/exception/api_error_spec.rb +105 -0
  70. data/spec/paypal/exception/http_error_spec.rb +20 -0
  71. data/spec/paypal/express/request_spec.rb +578 -0
  72. data/spec/paypal/express/response_spec.rb +89 -0
  73. data/spec/paypal/ipn_spec.rb +19 -0
  74. data/spec/paypal/nvp/request_spec.rb +113 -0
  75. data/spec/paypal/nvp/response_spec.rb +175 -0
  76. data/spec/paypal/payment/common/amount_spec.rb +36 -0
  77. data/spec/paypal/payment/recurring/activation_spec.rb +19 -0
  78. data/spec/paypal/payment/recurring_spec.rb +170 -0
  79. data/spec/paypal/payment/request/item_spec.rb +27 -0
  80. data/spec/paypal/payment/request_spec.rb +136 -0
  81. data/spec/paypal/payment/response/address_spec.rb +26 -0
  82. data/spec/paypal/payment/response/info_spec.rb +93 -0
  83. data/spec/paypal/payment/response/item_spec.rb +78 -0
  84. data/spec/paypal/payment/response/payee_info_spec.rb +24 -0
  85. data/spec/paypal/payment/response/payer_spec.rb +26 -0
  86. data/spec/paypal/payment/response/reference_info_spec.rb +36 -0
  87. data/spec/paypal/payment/response/refund_info_spec.rb +18 -0
  88. data/spec/paypal/payment/response/refund_spec.rb +28 -0
  89. data/spec/paypal/payment/response_spec.rb +29 -0
  90. data/spec/paypal/util_spec.rb +32 -0
  91. data/spec/spec_helper.rb +25 -0
  92. metadata +319 -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
data/lib/paypal/ipn.rb ADDED
@@ -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,66 @@
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
+ self.subject ||= ''
25
+ end
26
+
27
+ def common_params
28
+ {
29
+ :USER => self.username,
30
+ :PWD => self.password,
31
+ :SIGNATURE => self.signature,
32
+ :SUBJECT => self.subject,
33
+ :VERSION => self.version,
34
+ version: self.version
35
+ }
36
+ end
37
+
38
+ def request(method, params = {})
39
+ handle_response do
40
+ post(method, params)
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def post(method, params)
47
+ RestClient.post(self.class.endpoint, common_params.merge(params).merge(:METHOD => method))
48
+ end
49
+
50
+ def handle_response
51
+ response = yield
52
+ response = CGI.parse(response).inject({}) do |res, (k, v)|
53
+ res.merge!(k.to_sym => v.first)
54
+ end
55
+ case response[:ACK]
56
+ when 'Success', 'SuccessWithWarning'
57
+ response
58
+ else
59
+ raise Exception::APIError.new(response)
60
+ end
61
+ rescue RestClient::Exception => e
62
+ raise Exception::HttpError.new(e.http_code, e.message, e.http_body)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,237 @@
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
+ payee_email: attrs.delete(:PAYEEEMAIL),
161
+ payee_id: attrs.delete(:PAYEEID)
162
+ )
163
+ billing_agreement_info = Payment::Response::Info.attribute_mapping.keys.inject({}) do |billing_agreement_info, key|
164
+ billing_agreement_info.merge! key => attrs.delete(key)
165
+ end
166
+ @billing_agreement.info = Payment::Response::Info.new billing_agreement_info
167
+ @billing_agreement.info.amount = @amount
168
+ end
169
+ if attrs[:REFUNDTRANSACTIONID]
170
+ @refund = Payment::Response::Refund.new(
171
+ :refund_status => attrs.delete(:REFUNDSTATUS),
172
+ :transaction_id => attrs.delete(:REFUNDTRANSACTIONID),
173
+ :amount => {
174
+ :total => attrs.delete(:TOTALREFUNDEDAMOUNT),
175
+ :fee => attrs.delete(:FEEREFUNDAMT),
176
+ :gross => attrs.delete(:GROSSREFUNDAMT),
177
+ :net => attrs.delete(:NETREFUNDAMT)
178
+ }
179
+ )
180
+ end
181
+
182
+ # payment_responses
183
+ payment_responses = []
184
+ attrs.keys.each do |_attr_|
185
+ prefix, index, key = case _attr_.to_s
186
+ when /^PAYMENTREQUEST/, /^PAYMENTREQUESTINFO/
187
+ _attr_.to_s.split('_')
188
+ when /^L_PAYMENTREQUEST/
189
+ _attr_.to_s.split('_')[1..-1]
190
+ end
191
+ if prefix
192
+ payment_responses[index.to_i] ||= {}
193
+ payment_responses[index.to_i][key.to_sym] = attrs.delete(_attr_)
194
+ end
195
+ end
196
+ @payment_responses = payment_responses.collect do |_attrs_|
197
+ Payment::Response.new _attrs_
198
+ end
199
+
200
+ # payment_info
201
+ payment_info = []
202
+ attrs.keys.each do |_attr_|
203
+ prefix, index, key = _attr_.to_s.split('_')
204
+ if prefix == 'PAYMENTINFO'
205
+ payment_info[index.to_i] ||= {}
206
+ payment_info[index.to_i][key.to_sym] = attrs.delete(_attr_)
207
+ end
208
+ end
209
+ @payment_info = payment_info.collect do |_attrs_|
210
+ Payment::Response::Info.new _attrs_
211
+ end
212
+
213
+ # payment_info
214
+ items = []
215
+ attrs.keys.each do |_attr_|
216
+ key, index = _attr_.to_s.scan(/^L_(.+?)(\d+)$/).flatten
217
+ if index
218
+ items[index.to_i] ||= {}
219
+ items[index.to_i][key.to_sym] = attrs.delete(_attr_)
220
+ end
221
+ end
222
+ @items = items.collect do |_attrs_|
223
+ Payment::Response::Item.new _attrs_
224
+ end
225
+
226
+ # remove duplicated parameters
227
+ attrs.delete(:SHIPTOCOUNTRY) # NOTE: Same with SHIPTOCOUNTRYCODE
228
+ attrs.delete(:SALESTAX) # Same as TAXAMT
229
+
230
+ # warn ignored attrs
231
+ attrs.each do |key, value|
232
+ Paypal.log "Ignored Parameter (#{self.class}): #{key}=#{value}", :warn
233
+ end
234
+ end
235
+ end
236
+ end
237
+ 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