didil-paypal-recurring 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +2 -0
  5. data/Gemfile.lock +46 -0
  6. data/README.rdoc +144 -0
  7. data/Rakefile +5 -0
  8. data/docs/PP_NVPAPI_DeveloperGuide.pdf +0 -0
  9. data/docs/PP_WPP_IntegrationGuide.pdf +0 -0
  10. data/lib/paypal-recurring.rb +1 -0
  11. data/lib/paypal/recurring.rb +110 -0
  12. data/lib/paypal/recurring/base.rb +286 -0
  13. data/lib/paypal/recurring/cacert.pem +3987 -0
  14. data/lib/paypal/recurring/notification.rb +84 -0
  15. data/lib/paypal/recurring/request.rb +211 -0
  16. data/lib/paypal/recurring/response.rb +29 -0
  17. data/lib/paypal/recurring/response/base.rb +62 -0
  18. data/lib/paypal/recurring/response/checkout.rb +11 -0
  19. data/lib/paypal/recurring/response/details.rb +26 -0
  20. data/lib/paypal/recurring/response/manage_profile.rb +12 -0
  21. data/lib/paypal/recurring/response/payment.rb +24 -0
  22. data/lib/paypal/recurring/response/profile.rb +71 -0
  23. data/lib/paypal/recurring/response/refund.rb +23 -0
  24. data/lib/paypal/recurring/utils.rb +26 -0
  25. data/lib/paypal/recurring/version.rb +10 -0
  26. data/paypal-recurring.gemspec +27 -0
  27. data/spec/fixtures/checkout/failure.yml +38 -0
  28. data/spec/fixtures/checkout/success.yml +38 -0
  29. data/spec/fixtures/create_profile/failure.yml +38 -0
  30. data/spec/fixtures/create_profile/success.yml +38 -0
  31. data/spec/fixtures/details/cancelled.yml +38 -0
  32. data/spec/fixtures/details/failure.yml +38 -0
  33. data/spec/fixtures/details/success.yml +38 -0
  34. data/spec/fixtures/ipn/express_checkout.json +35 -0
  35. data/spec/fixtures/ipn/recurring_payment.json +44 -0
  36. data/spec/fixtures/ipn/recurring_payment_profile_created.json +31 -0
  37. data/spec/fixtures/ipn/recurring_payment_profile_created_with_initial_amount.json +33 -0
  38. data/spec/fixtures/ipn/recurring_payment_skipped.json +30 -0
  39. data/spec/fixtures/ipn/recurring_payment_with_initial_amount.json +44 -0
  40. data/spec/fixtures/notification/failure.yml +50 -0
  41. data/spec/fixtures/notification/success.yml +50 -0
  42. data/spec/fixtures/payment/failure.yml +38 -0
  43. data/spec/fixtures/payment/success.yml +38 -0
  44. data/spec/fixtures/profile/cancel/failure.yml +38 -0
  45. data/spec/fixtures/profile/cancel/success.yml +38 -0
  46. data/spec/fixtures/profile/failure.yml +38 -0
  47. data/spec/fixtures/profile/reactivate/failure.yml +38 -0
  48. data/spec/fixtures/profile/reactivate/success.yml +38 -0
  49. data/spec/fixtures/profile/success.yml +38 -0
  50. data/spec/fixtures/profile/suspend/failure.yml +38 -0
  51. data/spec/fixtures/profile/suspend/success.yml +38 -0
  52. data/spec/fixtures/refund/failure.yml +38 -0
  53. data/spec/fixtures/refund/success.yml +38 -0
  54. data/spec/fixtures/update_profile/failure.yml +38 -0
  55. data/spec/fixtures/update_profile/profile.yml +38 -0
  56. data/spec/fixtures/update_profile/success.yml +38 -0
  57. data/spec/paypal/notification_spec.rb +106 -0
  58. data/spec/paypal/recurring_spec.rb +81 -0
  59. data/spec/paypal/request_spec.rb +136 -0
  60. data/spec/paypal/response/base_spec.rb +19 -0
  61. data/spec/paypal/response/checkout_details_spec.rb +50 -0
  62. data/spec/paypal/response/checkout_spec.rb +32 -0
  63. data/spec/paypal/response/create_recurring_profile_spec.rb +41 -0
  64. data/spec/paypal/response/manage_profile_spec.rb +62 -0
  65. data/spec/paypal/response/profile_spec.rb +43 -0
  66. data/spec/paypal/response/refund_spec.rb +33 -0
  67. data/spec/paypal/response/request_payment_spec.rb +35 -0
  68. data/spec/paypal/response/update_recurring_profile_spec.rb +48 -0
  69. data/spec/spec_helper.rb +27 -0
  70. metadata +209 -0
@@ -0,0 +1,84 @@
1
+ module PayPal
2
+ module Recurring
3
+ class Notification
4
+ extend PayPal::Recurring::Utils
5
+
6
+ attr_reader :params
7
+
8
+ mapping({
9
+ :type => :txn_type,
10
+ :transaction_id => :txn_id,
11
+ :fee => [:mc_fee, :payment_fee],
12
+ :reference => [:rp_invoice_id, :custom, :invoice],
13
+ :payment_id => :recurring_payment_id,
14
+ :amount => [:amount, :mc_gross, :payment_gross],
15
+ :currency => :mc_currency,
16
+ :status => :payment_status,
17
+ :pending_reason => :pending_reason,
18
+ :profile_status => :profile_status,
19
+ :payment_date => :payment_date,
20
+ :time_created => :time_created,
21
+ :seller_id => :receiver_id,
22
+ :email => :receiver_email,
23
+ :initial_amount => :initial_payment_amount,
24
+ :payer_email => :payer_email
25
+ })
26
+
27
+ def initialize(params = {})
28
+ self.params = params
29
+ end
30
+
31
+ def params=(params)
32
+ @params = params.inject({}) do |buffer, (name,value)|
33
+ buffer.merge(name.to_sym => value)
34
+ end
35
+ end
36
+
37
+ def express_checkout?
38
+ type == "express_checkout"
39
+ end
40
+
41
+ def recurring_payment?
42
+ type == "recurring_payment"
43
+ end
44
+
45
+ def recurring_payment_profile?
46
+ type == "recurring_payment_profile_created"
47
+ end
48
+
49
+ def request
50
+ @request ||= PayPal::Recurring::Request.new.tap do |request|
51
+ request.uri = URI.parse("#{PayPal::Recurring.site_endpoint}?cmd=_notify-validate")
52
+ end
53
+ end
54
+
55
+ def response
56
+ @response ||= request.post(params.merge(:cmd => "_notify-validate"))
57
+ end
58
+
59
+ def valid?
60
+ completed? && verified? && email == PayPal::Recurring.email && seller_id == PayPal::Recurring.seller_id
61
+ end
62
+
63
+ def completed?
64
+ status == "Completed"
65
+ end
66
+
67
+ def next_payment_date
68
+ self.class.convert_to_time(params[:next_payment_date]) if params[:next_payment_date]
69
+ end
70
+
71
+ def paid_at
72
+ self.class.convert_to_time(payment_date) if payment_date
73
+ end
74
+
75
+ def created_at
76
+ self.class.convert_to_time(time_created) if time_created
77
+ end
78
+
79
+ def verified?
80
+ response.body == "VERIFIED"
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,211 @@
1
+ module PayPal
2
+ module Recurring
3
+ class Request
4
+ METHODS = {
5
+ :checkout => "SetExpressCheckout",
6
+ :payment => "DoExpressCheckoutPayment",
7
+ :details => "GetExpressCheckoutDetails",
8
+ :create_profile => "CreateRecurringPaymentsProfile",
9
+ :profile => "GetRecurringPaymentsProfileDetails",
10
+ :manage_profile => "ManageRecurringPaymentsProfileStatus",
11
+ :update_profile => "UpdateRecurringPaymentsProfile",
12
+ :refund => "RefundTransaction"
13
+ }
14
+
15
+ INITIAL_AMOUNT_ACTIONS = {
16
+ :cancel => "CancelOnFailure",
17
+ :continue => "ContinueOnFailure"
18
+ }
19
+
20
+ ACTIONS = {
21
+ :cancel => "Cancel",
22
+ :suspend => "Suspend",
23
+ :reactivate => "Reactivate"
24
+ }
25
+
26
+ PERIOD = {
27
+ :daily => "Day",
28
+ :weekly => "Weekly",
29
+ :monthly => "Month",
30
+ :yearly => "Year"
31
+ }
32
+
33
+ TRIAL_PERIOD = {
34
+ :daily => "Day",
35
+ :weekly => "Weekly",
36
+ :monthly => "Month",
37
+ :yearly => "Year"
38
+ }
39
+
40
+ OUTSTANDING = {
41
+ :next_billing => "AddToNextBilling",
42
+ :no_auto => "NoAutoBill"
43
+ }
44
+
45
+ REFUND_TYPE = {
46
+ :full => "Full",
47
+ :partial => "Partial",
48
+ :external => "ExternalDispute",
49
+ :other => "Other"
50
+ }
51
+
52
+ ATTRIBUTES = {
53
+ :action => "ACTION",
54
+ :amount => ["PAYMENTREQUEST_0_AMT", "AMT"],
55
+ :billing_type => "L_BILLINGTYPE0",
56
+ :cancel_url => "CANCELURL",
57
+ :currency => ["PAYMENTREQUEST_0_CURRENCYCODE", "CURRENCYCODE"],
58
+ :description => ["DESC", "PAYMENTREQUEST_0_DESC", "L_BILLINGAGREEMENTDESCRIPTION0"],
59
+ :note => "NOTE",
60
+ :item_category => "L_PAYMENTREQUEST_0_ITEMCATEGORY0",
61
+ :item_name => "L_PAYMENTREQUEST_0_NAME0",
62
+ :item_amount => "L_PAYMENTREQUEST_0_AMT0",
63
+ :item_quantity => "L_PAYMENTREQUEST_0_QTY0",
64
+ :email => "EMAIL",
65
+ :failed => "MAXFAILEDPAYMENTS",
66
+ :frequency => "BILLINGFREQUENCY",
67
+ :initial_amount => "INITAMT",
68
+ :initial_amount_action => "FAILEDINITAMTACTION",
69
+ :ipn_url => ["PAYMENTREQUEST_0_NOTIFYURL", "NOTIFYURL"],
70
+ :locale => "LOCALECODE",
71
+ :method => "METHOD",
72
+ :no_shipping => "NOSHIPPING",
73
+ :outstanding => "AUTOBILLOUTAMT",
74
+ :password => "PWD",
75
+ :payer_id => "PAYERID",
76
+ :payment_action => "PAYMENTREQUEST_0_PAYMENTACTION",
77
+ :period => "BILLINGPERIOD",
78
+ :profile_id => "PROFILEID",
79
+ :reference => ["PROFILEREFERENCE", "PAYMENTREQUEST_0_CUSTOM", "PAYMENTREQUEST_0_INVNUM"],
80
+ :refund_type => "REFUNDTYPE",
81
+ :return_url => "RETURNURL",
82
+ :signature => "SIGNATURE",
83
+ :start_at => "PROFILESTARTDATE",
84
+ :token => "TOKEN",
85
+ :transaction_id => "TRANSACTIONID",
86
+ :trial_amount => "TRIALAMT",
87
+ :trial_frequency => "TRIALBILLINGFREQUENCY",
88
+ :trial_length => "TRIALTOTALBILLINGCYCLES",
89
+ :trial_period => "TRIALBILLINGPERIOD",
90
+ :username => "USER",
91
+ :version => "VERSION",
92
+ :brand_name => "BRANDNAME",
93
+ :page_style => "PAGESTYLE",
94
+ }
95
+
96
+ CA_FILE = File.dirname(__FILE__) + "/cacert.pem"
97
+
98
+ attr_accessor :uri
99
+
100
+ # Do a POST request to PayPal API.
101
+ # The +method+ argument is the name of the API method you want to invoke.
102
+ # For instance, if you want to request a new checkout token, you may want
103
+ # to do something like:
104
+ #
105
+ # response = request.run(:express_checkout)
106
+ #
107
+ # We normalize the methods name. For a list of what's being covered, refer to
108
+ # PayPal::Recurring::Request::METHODS constant.
109
+ #
110
+ # The params hash can use normalized names. For a list, check the
111
+ # PayPal::Recurring::Request::ATTRIBUTES constant.
112
+ #
113
+ def run(method, params = {})
114
+ params = prepare_params(params.merge(:method => METHODS.fetch(method, method.to_s)))
115
+ response = post(params)
116
+ Response.process(method, response)
117
+ end
118
+
119
+ #
120
+ #
121
+ def request
122
+ @request ||= Net::HTTP::Post.new(uri.request_uri).tap do |http|
123
+ http["User-Agent"] = "PayPal::Recurring/#{PayPal::Recurring::Version::STRING}"
124
+ end
125
+ end
126
+
127
+ #
128
+ #
129
+ def post(params = {})
130
+ request.form_data = params
131
+ client.request(request)
132
+ end
133
+
134
+ # Join params and normalize attribute names.
135
+ #
136
+ def prepare_params(params) # :nodoc:
137
+ normalize_params default_params.merge(params)
138
+ end
139
+
140
+ # Parse current API url.
141
+ #
142
+ def uri # :nodoc:
143
+ @uri ||= URI.parse(PayPal::Recurring.api_endpoint)
144
+ end
145
+
146
+ def client
147
+ @client ||= begin
148
+ Net::HTTP.new(uri.host, uri.port).tap do |http|
149
+ http.use_ssl = true
150
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
151
+ http.ca_file = CA_FILE
152
+ end
153
+ end
154
+ end
155
+
156
+ def default_params
157
+ {
158
+ :username => PayPal::Recurring.username,
159
+ :password => PayPal::Recurring.password,
160
+ :signature => PayPal::Recurring.signature,
161
+ :version => PayPal::Recurring.api_version
162
+ }
163
+ end
164
+
165
+ def normalize_params(params)
166
+ params.inject({}) do |buffer, (name, value)|
167
+ attr_names = [ATTRIBUTES[name.to_sym]].flatten.compact
168
+ attr_names << name if attr_names.empty?
169
+
170
+ attr_names.each do |attr_name|
171
+ buffer[attr_name.to_sym] = respond_to?("build_#{name}") ? send("build_#{name}", value) : value
172
+ end
173
+
174
+ buffer
175
+ end
176
+ end
177
+
178
+ def build_period(value) # :nodoc:
179
+ PERIOD.fetch(value.to_sym, value) if value
180
+ end
181
+
182
+ def build_trial_period(value)
183
+ TRIAL_PERIOD.fetch(value.to_sym, value) if value
184
+ end
185
+
186
+ def build_start_at(value) # :nodoc:
187
+ value.respond_to?(:strftime) ? value.strftime("%Y-%m-%dT%H:%M:%SZ") : value
188
+ end
189
+
190
+ def build_outstanding(value) # :nodoc:
191
+ OUTSTANDING.fetch(value.to_sym, value) if value
192
+ end
193
+
194
+ def build_refund_type(value) # :nodoc:
195
+ REFUND_TYPE.fetch(value.to_sym, value) if value
196
+ end
197
+
198
+ def build_action(value) # :nodoc:
199
+ ACTIONS.fetch(value.to_sym, value) if value
200
+ end
201
+
202
+ def build_initial_amount_action(value) # :nodoc:
203
+ INITIAL_AMOUNT_ACTIONS.fetch(value.to_sym, value) if value
204
+ end
205
+
206
+ def build_locale(value) # :nodoc:
207
+ value.to_s.upcase
208
+ end
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,29 @@
1
+ module PayPal
2
+ module Recurring
3
+ module Response
4
+ autoload :Base, "paypal/recurring/response/base"
5
+ autoload :Checkout, "paypal/recurring/response/checkout"
6
+ autoload :Details, "paypal/recurring/response/details"
7
+ autoload :Payment, "paypal/recurring/response/payment"
8
+ autoload :ManageProfile, "paypal/recurring/response/manage_profile"
9
+ autoload :Profile, "paypal/recurring/response/profile"
10
+ autoload :Refund, "paypal/recurring/response/refund"
11
+
12
+ RESPONDERS = {
13
+ :checkout => "Checkout",
14
+ :details => "Details",
15
+ :payment => "Payment",
16
+ :profile => "Profile",
17
+ :create_profile => "ManageProfile",
18
+ :manage_profile => "ManageProfile",
19
+ :update_profile => "ManageProfile",
20
+ :refund => "Refund"
21
+ }
22
+
23
+ def self.process(method, response)
24
+ response_class = PayPal::Recurring::Response.const_get(RESPONDERS[method])
25
+ response_class.new(response)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,62 @@
1
+ module PayPal
2
+ module Recurring
3
+ module Response
4
+ class Base
5
+ extend PayPal::Recurring::Utils
6
+
7
+ attr_accessor :response
8
+
9
+ mapping(
10
+ :token => :TOKEN,
11
+ :ack => :ACK,
12
+ :version => :VERSION,
13
+ :build => :BUILD,
14
+ :correlaction_id => :CORRELATIONID,
15
+ :requested_at => :TIMESTAMP
16
+ )
17
+
18
+ def initialize(response = nil)
19
+ @response = response
20
+ end
21
+
22
+ def params
23
+ @params ||= CGI.parse(response.body).inject({}) do |buffer, (name, value)|
24
+ buffer.merge(name.to_sym => value.first)
25
+ end
26
+ end
27
+
28
+ def errors
29
+ @errors ||= begin
30
+ index = 0
31
+ [].tap do |errors|
32
+ while params[:"L_ERRORCODE#{index}"]
33
+ errors << {
34
+ :code => params[:"L_ERRORCODE#{index}"],
35
+ :messages => [
36
+ params[:"L_SHORTMESSAGE#{index}"],
37
+ params[:"L_LONGMESSAGE#{index}"]
38
+ ]
39
+ }
40
+
41
+ index += 1
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ def success?
48
+ ack == "Success"
49
+ end
50
+
51
+ def valid?
52
+ errors.empty? && success?
53
+ end
54
+
55
+ private
56
+ def build_requested_at(stamp) # :nodoc:
57
+ Time.parse(stamp)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,11 @@
1
+ module PayPal
2
+ module Recurring
3
+ module Response
4
+ class Checkout < Base
5
+ def checkout_url
6
+ "#{PayPal::Recurring.site_endpoint}?cmd=_express-checkout&token=#{token}&useraction=commit"
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ module PayPal
2
+ module Recurring
3
+ module Response
4
+ class Details < Base
5
+ mapping(
6
+ :status => :CHECKOUTSTATUS,
7
+ :email => :EMAIL,
8
+ :email => :EMAIL,
9
+ :payer_id => :PAYERID,
10
+ :payer_status => :PAYERSTATUS,
11
+ :first_name => :FIRSTNAME,
12
+ :last_name => :LASTNAME,
13
+ :country => :COUNTRYCODE,
14
+ :currency => :CURRENCYCODE,
15
+ :amount => :AMT,
16
+ :description => :DESC,
17
+ :ipn_url => :NOTIFYURL
18
+ )
19
+
20
+ def agreed?
21
+ params[:BILLINGAGREEMENTACCEPTEDSTATUS] == "1"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ module PayPal
2
+ module Recurring
3
+ module Response
4
+ class ManageProfile < Base
5
+ mapping(
6
+ :profile_id => :PROFILEID,
7
+ :status => :PROFILESTATUS
8
+ )
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ module PayPal
2
+ module Recurring
3
+ module Response
4
+ class Payment < Base
5
+ mapping(
6
+ :status => :PAYMENTINFO_0_PAYMENTSTATUS,
7
+ :amount => :PAYMENTINFO_0_AMT,
8
+ :fees => :PAYMENTINFO_0_FEEAMT,
9
+ :transaction_id => :PAYMENTINFO_0_TRANSACTIONID,
10
+ :seller_id => :PAYMENTINFO_0_SECUREMERCHANTACCOUNTID,
11
+ :reference => [:PROFILEREFERENCE, :PAYMENTREQUEST_0_CUSTOM, :PAYMENTREQUEST_0_INVNUM]
12
+ )
13
+
14
+ def completed?
15
+ params[:PAYMENTINFO_0_PAYMENTSTATUS] == "Completed"
16
+ end
17
+
18
+ def approved?
19
+ params[:PAYMENTINFO_0_ACK] == "Success"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end