subscription_fu 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -6,6 +6,7 @@ gemspec
6
6
  group :development, :test do
7
7
  gem 'rails'
8
8
  gem 'sqlite3'
9
+ gem 'rake', "0.8.7"
9
10
  gem 'haml'
10
11
  gem 'rspec', '>= 2.5.0'
11
12
  gem 'rspec-rails'
@@ -55,7 +55,7 @@ class SubscriptionFu::Subscription < ActiveRecord::Base
55
55
  # billing time data about the subscription
56
56
 
57
57
  def next_billing_date
58
- paypal_recurring_details[:next_billing_date]
58
+ paypal_recurring_details[:next_billing_date] if paypal?
59
59
  end
60
60
 
61
61
  def estimated_next_billing_date
@@ -64,7 +64,7 @@ class SubscriptionFu::Subscription < ActiveRecord::Base
64
64
  end
65
65
 
66
66
  def last_billing_date
67
- paypal_recurring_details[:last_payment_date]
67
+ paypal_recurring_details[:last_payment_date] if paypal?
68
68
  end
69
69
 
70
70
  def successor_start_date(new_plan_name)
@@ -103,8 +103,14 @@ class SubscriptionFu::Subscription < ActiveRecord::Base
103
103
 
104
104
  private
105
105
 
106
+ def paypal?
107
+ ! paypal_profile_id.blank?
108
+ end
109
+
106
110
  def paypal_recurring_details
107
- @paypal_recurring_details ||= (paypal_profile_id.blank? ? {} : SubscriptionFu::Paypal.paypal.recurring_details(paypal_profile_id))
111
+ @paypal_recurring_details ||= begin
112
+ SubscriptionFu::Paypal.recurring_details(paypal_profile_id)
113
+ end
108
114
  end
109
115
 
110
116
  def convert_paypal_status(paypal_status)
@@ -77,9 +77,15 @@ class SubscriptionFu::Transaction < ActiveRecord::Base
77
77
  private
78
78
 
79
79
  def start_checkout_paypal(return_url, cancel_url)
80
- token = SubscriptionFu::Paypal.paypal.start_checkout(return_url, cancel_url, initiator_email, sub_plan.price_with_tax, sub_plan.currency, sub_human_description)
81
- update_attributes!(:identifier => token)
82
- "#{SubscriptionFu.config.paypal_landing_url}?cmd=_express-checkout&token=#{CGI.escape(token)}"
80
+ # TODO: set initiator_email
81
+ pay_req = Paypal::Payment::Request.new(
82
+ :currency_code => sub_plan.currency,
83
+ :billing_type => :RecurringPayments,
84
+ :billing_agreement_description => sub_human_description)
85
+
86
+ response = SubscriptionFu::Paypal.express_request.setup(pay_req, return_url, cancel_url, :no_shipping => true)
87
+ update_attributes!(:identifier => response.token)
88
+ response.redirect_uri
83
89
  end
84
90
 
85
91
  def start_checkout_nogw(return_url, cancel_url)
@@ -91,9 +97,17 @@ class SubscriptionFu::Transaction < ActiveRecord::Base
91
97
  raise "did you call start_checkout first?" if identifier.blank?
92
98
  raise "already activated" if sub_activated?
93
99
 
94
- paypal_profile_id, paypal_status =
95
- SubscriptionFu::Paypal.paypal.create_recurring(identifier, sub_billing_starts_at, sub_plan.price, sub_plan.price_tax, sub_plan.currency, sub_human_description)
96
- subscription.update_attributes!(:paypal_profile_id => paypal_profile_id, :activated_at => Time.now)
100
+ profile = Paypal::Payment::Recurring.new(
101
+ :start_date => sub_billing_starts_at,
102
+ :description => sub_human_description,
103
+ :billing => {
104
+ :period => :Month,
105
+ :frequency => 1,
106
+ :amount => sub_plan.price,
107
+ :tax => sub_plan.price_tax,
108
+ :currency_code => sub_plan.currency } )
109
+ response = SubscriptionFu::Paypal.express_request.subscribe!(identifier, profile)
110
+ subscription.update_attributes!(:paypal_profile_id => response.recurring.identifier, :activated_at => Time.now)
97
111
  complete_activation
98
112
  end
99
113
 
@@ -114,7 +128,7 @@ class SubscriptionFu::Transaction < ActiveRecord::Base
114
128
  # update the record beforehand, because paypal raises an error if
115
129
  # the profile is already cancelled
116
130
  complete_cancellation(opts)
117
- SubscriptionFu::Paypal.paypal.cancel_recurring(sub_paypal_profile_id, sub_cancel_reason)
131
+ SubscriptionFu::Paypal.express_request.renew!(sub_paypal_profile_id, :Cancel, :note => sub_cancel_reason)
118
132
  end
119
133
 
120
134
  def complete_cancellation_nogw(opts)
@@ -1,22 +1,23 @@
1
+ require "paypal"
2
+
1
3
  module SubscriptionFu
2
4
  class Config
3
- attr_accessor :plan_class_name, :paypal_nvp_api_url, :paypal_api_user_id, :paypal_api_pwd, :paypal_api_sig, :paypal_landing_url
5
+ attr_accessor :plan_class_name, :paypal_api_user_id, :paypal_api_pwd, :paypal_api_sig
4
6
  attr_reader :available_plans
5
7
 
6
8
  def initialize
7
9
  @available_plans = {}
8
10
  @plan_class_name = "SubscriptionFu::Plan"
9
11
  paypal_use_production!
12
+ ::Paypal.logger = Rails.logger
10
13
  end
11
14
 
12
15
  def paypal_use_sandbox!
13
- self.paypal_nvp_api_url = "https://api-3t.sandbox.paypal.com/nvp"
14
- self.paypal_landing_url = "https://www.sandbox.paypal.com/cgi-bin/webscr"
16
+ ::Paypal.sandbox = true
15
17
  end
16
18
 
17
19
  def paypal_use_production!
18
- self.paypal_nvp_api_url = "https://api-3t.paypal.com/nvp"
19
- self.paypal_landing_url = "https://www.paypal.com/cgi-bin/webscr"
20
+ ::Paypal.sandbox = false
20
21
  end
21
22
 
22
23
  def add_plan(key, price, data = {})
@@ -1,101 +1,19 @@
1
- require "rest-client"
1
+ require "paypal"
2
2
 
3
- class SubscriptionFu::Paypal
3
+ module SubscriptionFu::Paypal
4
+ UTC_TZ = ActiveSupport::TimeZone.new("UTC")
4
5
 
5
- def self.paypal
6
- new(SubscriptionFu.config.paypal_api_user_id,
7
- SubscriptionFu.config.paypal_api_pwd,
8
- SubscriptionFu.config.paypal_api_sig,
9
- SubscriptionFu.config.paypal_nvp_api_url,
10
- Rails.logger)
6
+ def self.express_request
7
+ config = SubscriptionFu.config
8
+ ::Paypal::Express::Request.new(
9
+ :username => config.paypal_api_user_id,
10
+ :password => config.paypal_api_pwd,
11
+ :signature => config.paypal_api_sig)
11
12
  end
12
13
 
13
- class Failure < RuntimeError
14
- attr_reader :request_opts, :response
15
-
16
- def initialize(request_opts, response)
17
- @request_opts = request_opts
18
- @response = response
19
- super "PayPal did not return success: #{@response.inspect}"
20
- end
21
- alias :data :request_opts
22
- end
23
-
24
- def initialize(user, pwd, sig, api_url, logger)
25
- @user = user
26
- @pwd = pwd
27
- @sig = sig
28
- @api_url = api_url
29
- @logger = logger
30
- end
31
-
32
- def start_checkout(return_url, cancel_url, email, maxamt, currency_code, desc)
33
- res = call_paypal('SetExpressCheckout',
34
- 'RETURNURL' => return_url,
35
- 'CANCELURL' => cancel_url,
36
- 'EMAIL' => email,
37
- 'NOSHIPPING' => 1,
38
- 'MAXAMT' => maxamt,
39
- 'PAYMENTREQUEST_0_AMT' => 0,
40
- 'PAYMENTREQUEST_0_CURRENCYCODE' => currency_code,
41
- 'L_BILLINGTYPE0' => 'RecurringPayments',
42
- 'L_BILLINGAGREEMENTDESCRIPTION0' => desc)
43
- res['TOKEN'].first
44
- end
45
-
46
- def create_recurring(token, start_date, amt, taxamt, currency_code, desc)
47
- res = call_paypal('CreateRecurringPaymentsProfile',
48
- 'PROFILESTARTDATE' => start_date.utc.iso8601,
49
- 'BILLINGPERIOD' => 'Month',
50
- 'BILLINGFREQUENCY' => 1,
51
- 'MAXFAILEDPAYMENTS' => 0,
52
- 'AUTOBILLOUTAMT' => 'AddToNextBilling',
53
- 'AMT' => amt,
54
- 'TAXAMT' => taxamt,
55
- 'CURRENCYCODE' => currency_code,
56
- 'DESC' => desc,
57
- 'TOKEN' => token)
58
- [res['PROFILEID'].first, res['PROFILESTATUS'].first || res['STATUS'].first]
59
- end
60
-
61
- def recurring_details(profile_id)
62
- utc = ActiveSupport::TimeZone.new("UTC")
63
- res = call_paypal('GetRecurringPaymentsProfileDetails', 'PROFILEID' => profile_id)
64
- { :id => res['PROFILEID'].first,
65
- :status => res['PROFILESTATUS'].first || res['STATUS'].first,
66
- :next_billing_date => utc.parse(res['NEXTBILLINGDATE'].first.to_s),
67
- :start_date => utc.parse(res['PROFILESTARTDATE'].first.to_s),
68
- :cycles_completed => res['NUMCYCLESCOMPLETED'].first.to_i,
69
- :outstanding_balance => res['OUTSTANDINGBALANCE'].first.to_f,
70
- :last_payment_date => utc.parse(res['LASTPAYMENTDATE'].first.to_s) }
14
+ def self.recurring_details(profile_id)
15
+ res = SubscriptionFu::Paypal.express_request.subscription(profile_id)
16
+ { :next_billing_date => UTC_TZ.parse(res.recurring.summary.next_billing_date.to_s),
17
+ :last_payment_date => UTC_TZ.parse(res.recurring.summary.last_payment_date.to_s), }
71
18
  end
72
-
73
- def cancel_recurring(profile_id, reason)
74
- call_paypal('ManageRecurringPaymentsProfileStatus',
75
- 'PROFILEID' => profile_id,
76
- 'ACTION' => 'Cancel',
77
- 'NOTE' => I18n.t(reason, :scope => [:subscription_fu, :subscription, :cancel_notes]))
78
- end
79
-
80
- private
81
-
82
- def call_paypal(method, opts)
83
- full_opts = paypal_api_opts(method, opts)
84
- CGI.parse(RestClient.post(@api_url, full_opts)).tap do |result|
85
- if result['ACK'].first != 'Success'
86
- @logger.warn("PayPal did not return success for call to #{method}")
87
- @logger.info(" called with: #{full_opts.inspect}")
88
- @logger.info(" result: #{result.inspect}")
89
- raise Failure.new(full_opts, result)
90
- else
91
- @logger.info("PayPal returned success for call to #{method}")
92
- @logger.info(" result: #{result.inspect}")
93
- end
94
- end
95
- end
96
-
97
- def paypal_api_opts(method, opts)
98
- opts.merge('USER' => @user, 'PWD' => @pwd, 'SIGNATURE' => @sig, 'VERSION' => '65.0', 'METHOD' => method)
99
- end
100
-
101
19
  end
@@ -1,3 +1,3 @@
1
1
  module SubscriptionFu
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -74,7 +74,7 @@ module PaypalTestHelper
74
74
  end
75
75
 
76
76
  def paypal_profile_res(profile, status, opts = {})
77
- paypal_res(opts.merge("PROFILEID"=>profile,"STATUS"=>status))
77
+ paypal_res(opts.merge("PROFILEID"=>profile,"STATUS"=>status,"REGULARAMT"=>"0"))
78
78
  end
79
79
 
80
80
  end
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
16
16
  s.rubyforge_project = "subscriptionfu"
17
17
 
18
18
  s.add_dependency 'rails', '>= 3.0.3'
19
- s.add_dependency 'rest-client', '>= 1.6.1'
19
+ s.add_dependency 'paypal-express', '~> 0.3.0'
20
20
 
21
21
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
22
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: subscription_fu
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.0
5
+ version: 0.2.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Paul McMahon
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2011-05-20 00:00:00 +09:00
14
+ date: 2011-05-29 00:00:00 +09:00
15
15
  default_executable:
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
@@ -26,14 +26,14 @@ dependencies:
26
26
  type: :runtime
27
27
  version_requirements: *id001
28
28
  - !ruby/object:Gem::Dependency
29
- name: rest-client
29
+ name: paypal-express
30
30
  prerelease: false
31
31
  requirement: &id002 !ruby/object:Gem::Requirement
32
32
  none: false
33
33
  requirements:
34
- - - ">="
34
+ - - ~>
35
35
  - !ruby/object:Gem::Version
36
- version: 1.6.1
36
+ version: 0.3.0
37
37
  type: :runtime
38
38
  version_requirements: *id002
39
39
  description: SubscriptionFu helps with building services which have paid subscriptions. It includes the models to store subscription status, and provides integration with PayPal for paid subscriptions.
@@ -126,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
126
126
  requirements: []
127
127
 
128
128
  rubyforge_project: subscriptionfu
129
- rubygems_version: 1.6.2
129
+ rubygems_version: 1.5.2
130
130
  signing_key:
131
131
  specification_version: 3
132
132
  summary: Rails support for handling free/paid subscriptions