rspreedly 0.0.1
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.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +78 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/lib/rspreedly/base.rb +76 -0
- data/lib/rspreedly/complimentary_subscription.rb +5 -0
- data/lib/rspreedly/complimentary_time_extension.rb +5 -0
- data/lib/rspreedly/config.rb +84 -0
- data/lib/rspreedly/error.rb +9 -0
- data/lib/rspreedly/invoice.rb +61 -0
- data/lib/rspreedly/line_item.rb +5 -0
- data/lib/rspreedly/payment_method.rb +7 -0
- data/lib/rspreedly/subscriber.rb +153 -0
- data/lib/rspreedly/subscription_plan.rb +40 -0
- data/lib/rspreedly.rb +29 -0
- data/spec/config_spec.rb +144 -0
- data/spec/fixtures/complimentary_failed_active.xml +1 -0
- data/spec/fixtures/complimentary_failed_inactive.xml +1 -0
- data/spec/fixtures/complimentary_not_valid.xml +3 -0
- data/spec/fixtures/complimentary_success.xml +25 -0
- data/spec/fixtures/create_subscriber.xml +25 -0
- data/spec/fixtures/existing_subscriber.xml +1 -0
- data/spec/fixtures/free_plan_not_elligable.xml +1 -0
- data/spec/fixtures/free_plan_not_free.xml +1 -0
- data/spec/fixtures/free_plan_not_set.xml +1 -0
- data/spec/fixtures/free_plan_success.xml +25 -0
- data/spec/fixtures/invalid_subscriber.xml +1 -0
- data/spec/fixtures/invalid_update.xml +1 -0
- data/spec/fixtures/invoice_created.xml +43 -0
- data/spec/fixtures/invoice_invalid.xml +1 -0
- data/spec/fixtures/no_plans.xml +2 -0
- data/spec/fixtures/no_subscribers.xml +2 -0
- data/spec/fixtures/payment_already_paid.xml +1 -0
- data/spec/fixtures/payment_invalid.xml +1 -0
- data/spec/fixtures/payment_not_found.xml +1 -0
- data/spec/fixtures/payment_success.xml +43 -0
- data/spec/fixtures/plan_disabled.xml +1 -0
- data/spec/fixtures/plan_not_found.xml +1 -0
- data/spec/fixtures/subscriber.xml +25 -0
- data/spec/fixtures/subscriber_not_found.xml +1 -0
- data/spec/fixtures/subscribers.xml +75 -0
- data/spec/fixtures/subscription_plan_list.xml +91 -0
- data/spec/invoice_spec.rb +129 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/subscriber_spec.rb +442 -0
- data/spec/subscription_plan_spec.rb +36 -0
- metadata +107 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Richard Livsey
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
= RSpreedly
|
2
|
+
|
3
|
+
Ruby library to access the Spreedly API (all of it).
|
4
|
+
|
5
|
+
== Why another one?
|
6
|
+
|
7
|
+
There are a few of these knocking about, but I couldn't find one particular to my needs:
|
8
|
+
|
9
|
+
* Well covered with specs (aiming for 100%)
|
10
|
+
* Covers the entire API, not just parts of it
|
11
|
+
* Rubyish/ActiveRecord style access
|
12
|
+
|
13
|
+
== Usage
|
14
|
+
|
15
|
+
Configure your API key and site name for your account:
|
16
|
+
|
17
|
+
RSpreedly::Config.setup do |config|
|
18
|
+
config.api_key = "your-api-key"
|
19
|
+
config.site_name = "your-site-name"
|
20
|
+
end
|
21
|
+
|
22
|
+
List subscribers
|
23
|
+
|
24
|
+
RSpreedly::Subscriber.find(:all).each do |subscriber|
|
25
|
+
# do something
|
26
|
+
end
|
27
|
+
|
28
|
+
CRUD access to subscribers
|
29
|
+
|
30
|
+
sub = RSpreedly::Subscriber.new(:customer_id => 42, :email => "somewhere@example.com")
|
31
|
+
sub.token => nil
|
32
|
+
sub.save
|
33
|
+
sub.token => "6af9994a57e420345897b1abb4c27a9db27fa4d0"
|
34
|
+
|
35
|
+
sub = RSpreedly::Subscriber.find(42)
|
36
|
+
sub.email = "new-email@example.com"
|
37
|
+
sub.save
|
38
|
+
|
39
|
+
sub = RSpreedly::Subscriber.find(69)
|
40
|
+
sub.destroy
|
41
|
+
|
42
|
+
Comp subscriptions
|
43
|
+
|
44
|
+
comp = RSpreedly::ComplimentarySubscription.new(:duration_quantity => 3, :duration_units => "months", :feature_level => "Pro")
|
45
|
+
sub = RSpreedly::Subscriber.find(69)
|
46
|
+
sub.comp_subscription(comp)
|
47
|
+
|
48
|
+
View all plans
|
49
|
+
|
50
|
+
plans = RSpreedly::SubscriptionPlan.find(:all)
|
51
|
+
|
52
|
+
Raise an invoice, and pay it
|
53
|
+
|
54
|
+
invoice = Invoice.new(:subscription_plan_id => 5, :subscriber => sub)
|
55
|
+
invoice.save
|
56
|
+
|
57
|
+
payment = RSpreedly::PaymentMethod::CreditCard(:card_type => 'visa', :number => '123456', ...)
|
58
|
+
invoice.pay(payment)
|
59
|
+
|
60
|
+
See the specs and API docs at Spreedly for more details and the rest of the things it can do.
|
61
|
+
|
62
|
+
https://www.spreedly.com/manual/integration-reference/url-reference/
|
63
|
+
|
64
|
+
== Todo
|
65
|
+
|
66
|
+
* Better specs for data we send to Spreedly.
|
67
|
+
* Better docs.
|
68
|
+
|
69
|
+
== Thanks
|
70
|
+
|
71
|
+
I studied the other Spreedly APIs and there may well be a line or three this library has in common with:
|
72
|
+
|
73
|
+
* http://github.com/terralien/spreedly-gem
|
74
|
+
* http://github.com/erbmicha/spreedly/
|
75
|
+
|
76
|
+
== Copyright
|
77
|
+
|
78
|
+
Copyright (c) 2009 Richard Livsey. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "rspreedly"
|
8
|
+
gem.summary = %Q{Ruby library for the Spreedly API}
|
9
|
+
gem.email = "richard@livsey.org"
|
10
|
+
gem.homepage = "http://github.com/rlivsey/rspreedly"
|
11
|
+
gem.authors = ["Richard Livsey"]
|
12
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
13
|
+
end
|
14
|
+
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'spec/rake/spectask'
|
20
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
21
|
+
spec.libs << 'lib' << 'spec'
|
22
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
23
|
+
end
|
24
|
+
|
25
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
26
|
+
spec.libs << 'lib' << 'spec'
|
27
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
28
|
+
spec.rcov = true
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
task :default => :spec
|
33
|
+
|
34
|
+
require 'rake/rdoctask'
|
35
|
+
Rake::RDocTask.new do |rdoc|
|
36
|
+
if File.exist?('VERSION.yml')
|
37
|
+
config = YAML.load(File.read('VERSION.yml'))
|
38
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
39
|
+
else
|
40
|
+
version = ""
|
41
|
+
end
|
42
|
+
|
43
|
+
rdoc.rdoc_dir = 'rdoc'
|
44
|
+
rdoc.title = "RSpreedly #{version}"
|
45
|
+
rdoc.rdoc_files.include('README*')
|
46
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
47
|
+
end
|
48
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module RSpreedly
|
2
|
+
|
3
|
+
class Base
|
4
|
+
include HTTParty
|
5
|
+
format :xml
|
6
|
+
base_uri "https://spreedly.com/api/v4"
|
7
|
+
|
8
|
+
def self.api_request(type, path, options={})
|
9
|
+
path = "#{RSpreedly::Config.site_name}#{path}"
|
10
|
+
options.merge!({
|
11
|
+
:basic_auth => {:username => RSpreedly::Config.api_key, :password => 'X'},
|
12
|
+
:headers => {"Content-Type" => 'application/xml'}
|
13
|
+
})
|
14
|
+
self.do_request(type, path, options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.do_request(type, path, options)
|
18
|
+
response = self.send(type.to_s, path, options)
|
19
|
+
message = "#{response.code}: #{response.body}"
|
20
|
+
|
21
|
+
case response.code.to_i
|
22
|
+
when 403
|
23
|
+
raise(RSpreedly::Error::Forbidden.new, message)
|
24
|
+
when 422
|
25
|
+
raise(RSpreedly::Error::BadRequest.new, message)
|
26
|
+
when 404
|
27
|
+
raise(RSpreedly::Error::NotFound.new, message)
|
28
|
+
end
|
29
|
+
|
30
|
+
response
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(attrs={})
|
34
|
+
self.attributes = attrs
|
35
|
+
end
|
36
|
+
|
37
|
+
def attributes=(attrs)
|
38
|
+
attrs.each do |k, v|
|
39
|
+
self.send("#{k}=", v)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def api_request(type, path, options={})
|
44
|
+
self.class.api_request(type, path, options)
|
45
|
+
end
|
46
|
+
|
47
|
+
# TODO - do this nicer
|
48
|
+
# rather eew at the moment and hand made XML is not nice
|
49
|
+
def to_xml(opts={})
|
50
|
+
exclude = opts[:exclude] || []
|
51
|
+
|
52
|
+
tag = opts[:tag] || RSpreedly.underscore(self.class.to_s)
|
53
|
+
inner = opts[:inner]
|
54
|
+
outer = opts[:outer]
|
55
|
+
no_tag = opts[:no_tag]
|
56
|
+
|
57
|
+
xml = ""
|
58
|
+
xml << "<#{outer}>" if outer
|
59
|
+
xml << "<#{tag}>" unless no_tag
|
60
|
+
xml << "<#{inner}>" if inner
|
61
|
+
self.instance_variables.each do |var|
|
62
|
+
name = var.gsub('@', '')
|
63
|
+
next if exclude.include?(name.to_sym)
|
64
|
+
value = self.instance_variable_get(var)
|
65
|
+
if value.respond_to?(:to_xml)
|
66
|
+
value = value.to_xml(:no_tag => (RSpreedly.underscore(value.class.to_s) == name))
|
67
|
+
end
|
68
|
+
xml << "<#{name}>#{value}</#{name}>"
|
69
|
+
end
|
70
|
+
xml << "</#{inner}>" if inner
|
71
|
+
xml << "</#{tag}>" unless no_tag
|
72
|
+
xml << "</#{outer}>" if outer
|
73
|
+
xml
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module RSpreedly
|
2
|
+
module Config
|
3
|
+
class << self
|
4
|
+
|
5
|
+
# the configuration hash itself
|
6
|
+
def configuration
|
7
|
+
@configuration ||= defaults
|
8
|
+
end
|
9
|
+
|
10
|
+
def defaults
|
11
|
+
{
|
12
|
+
:logger => defined?(RAILS_DEFAULT_LOGGER) ? RAILS_DEFAULT_LOGGER : Logger.new(STDOUT),
|
13
|
+
:debug => false,
|
14
|
+
:site_name => nil, # your site name
|
15
|
+
:key => nil # your API key
|
16
|
+
}
|
17
|
+
end
|
18
|
+
|
19
|
+
def [](key)
|
20
|
+
configuration[key]
|
21
|
+
end
|
22
|
+
|
23
|
+
def []=(key, val)
|
24
|
+
configuration[key] = val
|
25
|
+
end
|
26
|
+
|
27
|
+
# remove an item from the configuration
|
28
|
+
def delete(key)
|
29
|
+
configuration.delete(key)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return the value of the key, or the default if doesn't exist
|
33
|
+
#
|
34
|
+
# ==== Examples
|
35
|
+
#
|
36
|
+
# RSpreedly::Config.fetch(:monkey, false)
|
37
|
+
# => false
|
38
|
+
#
|
39
|
+
def fetch(key, default)
|
40
|
+
configuration.fetch(key, default)
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_hash
|
44
|
+
configuration
|
45
|
+
end
|
46
|
+
|
47
|
+
# Yields the configuration.
|
48
|
+
#
|
49
|
+
# ==== Examples
|
50
|
+
# RSpreedly::Config.use do |config|
|
51
|
+
# config[:debug] = true
|
52
|
+
# config.something = false
|
53
|
+
# end
|
54
|
+
#
|
55
|
+
def setup
|
56
|
+
yield self
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def clear
|
61
|
+
@configuration = {}
|
62
|
+
end
|
63
|
+
|
64
|
+
def reset
|
65
|
+
@configuration = defaults
|
66
|
+
end
|
67
|
+
|
68
|
+
# allow getting and setting properties via RSpreedly::Config.xxx
|
69
|
+
#
|
70
|
+
# ==== Examples
|
71
|
+
# RSpreedly::Config.debug
|
72
|
+
# RSpreedly::Config.debug = false
|
73
|
+
#
|
74
|
+
def method_missing(method, *args)
|
75
|
+
if method.to_s[-1,1] == '='
|
76
|
+
configuration[method.to_s.tr('=','').to_sym] = *args
|
77
|
+
else
|
78
|
+
configuration[method]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module RSpreedly
|
2
|
+
|
3
|
+
class Invoice < Base
|
4
|
+
|
5
|
+
attr_accessor :subscription_plan_id,
|
6
|
+
:subscriber,
|
7
|
+
:closed,
|
8
|
+
:created_at,
|
9
|
+
:token,
|
10
|
+
:updated_at,
|
11
|
+
:price,
|
12
|
+
:amount,
|
13
|
+
:currency_code,
|
14
|
+
:line_items
|
15
|
+
|
16
|
+
# Create an Invoice (more)
|
17
|
+
# POST /api/v4/[short site name]/invoices.xml
|
18
|
+
def create
|
19
|
+
begin
|
20
|
+
create!
|
21
|
+
rescue RSpreedly::Error::Base
|
22
|
+
# gulp those errors down
|
23
|
+
# TODO - set self.errors or something?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def create!
|
28
|
+
result = api_request(:post, "/invoices.xml", :body => self.to_xml)
|
29
|
+
self.attributes = result["invoice"]
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
alias_method :save, :create
|
34
|
+
alias_method :save!, :create!
|
35
|
+
|
36
|
+
def subscriber=(data)
|
37
|
+
if data.is_a? Hash
|
38
|
+
data = RSpreedly::Subscriber.new(data)
|
39
|
+
end
|
40
|
+
@subscriber = data
|
41
|
+
end
|
42
|
+
|
43
|
+
def line_items=(data)
|
44
|
+
@line_items = []
|
45
|
+
data.each do |item|
|
46
|
+
if item.is_a? Hash
|
47
|
+
item = RSpreedly::LineItem.new(item)
|
48
|
+
end
|
49
|
+
@line_items << item
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Pay an Invoice (more)
|
54
|
+
# PUT /api/v4/[short site name]/invoices/[invoice token]/pay.xml
|
55
|
+
def pay(payment)
|
56
|
+
result = api_request(:put, "/invoices/#{self.token}/pay.xml", :body => payment.to_xml(:outer => 'payment'))
|
57
|
+
self.attributes = result["invoice"]
|
58
|
+
true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
module RSpreedly
|
2
|
+
|
3
|
+
class Subscriber < Base
|
4
|
+
|
5
|
+
attr_accessor :active,
|
6
|
+
:active_until,
|
7
|
+
:billing_first_name,
|
8
|
+
:billing_last_name,
|
9
|
+
:card_expires_before_next_auto_renew,
|
10
|
+
:created_at,
|
11
|
+
:customer_id,
|
12
|
+
:eligible_for_free_trial,
|
13
|
+
:email,
|
14
|
+
:feature_level,
|
15
|
+
:grace_until,
|
16
|
+
:in_grace_period,
|
17
|
+
:lifetime_subscription,
|
18
|
+
:new_customer_id,
|
19
|
+
:on_trial,
|
20
|
+
:payment_method,
|
21
|
+
:ready_to_renew,
|
22
|
+
:recurring,
|
23
|
+
:screen_name,
|
24
|
+
:store_credit,
|
25
|
+
:store_credit_currency_code,
|
26
|
+
:subscription_plan_name,
|
27
|
+
:token,
|
28
|
+
:updated_at
|
29
|
+
|
30
|
+
class << self
|
31
|
+
|
32
|
+
# Get a subscriber’s details
|
33
|
+
# GET /api/v4/[short site name]/subscribers/[subscriber id].xml
|
34
|
+
def find(id)
|
35
|
+
return all if id == :all
|
36
|
+
|
37
|
+
begin
|
38
|
+
data = api_request(:get, "/subscribers/#{id}.xml")
|
39
|
+
Subscriber.new(data["subscriber"])
|
40
|
+
rescue RSpreedly::Error::NotFound
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Get a list of all subscribers (more)
|
46
|
+
# GET /api/v4/[short site name]/subscribers.xml
|
47
|
+
def all
|
48
|
+
response = api_request(:get, "/subscribers.xml")
|
49
|
+
return [] unless response.has_key?("subscribers")
|
50
|
+
response["subscribers"].collect{|data| Subscriber.new(data)}
|
51
|
+
end
|
52
|
+
|
53
|
+
# Clear all subscribers from a *test* site (more)
|
54
|
+
# DELETE /api/v4/[short site name]/subscribers.xml
|
55
|
+
def delete_all
|
56
|
+
!! api_request(:delete, "/subscribers.xml")
|
57
|
+
end
|
58
|
+
|
59
|
+
alias_method :destroy_all, :delete_all
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
def new_record?
|
64
|
+
!self.token
|
65
|
+
end
|
66
|
+
|
67
|
+
def save
|
68
|
+
self.new_record? ? self.create : self.update
|
69
|
+
end
|
70
|
+
|
71
|
+
# Create a subscriber (more)
|
72
|
+
# POST /api/v4/[short site name]/subscribers.xml
|
73
|
+
def create!
|
74
|
+
result = api_request(:post, "/subscribers.xml", :body => self.to_xml)
|
75
|
+
self.attributes = result["subscriber"]
|
76
|
+
true
|
77
|
+
end
|
78
|
+
|
79
|
+
def create
|
80
|
+
begin
|
81
|
+
create!
|
82
|
+
rescue RSpreedly::Error::Base
|
83
|
+
# gulp those errors down
|
84
|
+
# TODO - set self.errors or something?
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Update a Subscriber (more)
|
89
|
+
# PUT /api/v4/[short site name]/subscribers/[subscriber id].xml
|
90
|
+
def update!
|
91
|
+
!! api_request(:put, "/subscribers/#{self.customer_id}.xml", :body => self.to_xml(:exclude => [:customer_id]))
|
92
|
+
end
|
93
|
+
|
94
|
+
def update
|
95
|
+
begin
|
96
|
+
update!
|
97
|
+
rescue RSpreedly::Error::Base
|
98
|
+
# gulp those errors down
|
99
|
+
# TODO - set self.errors or something?
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Delete one subscriber from a *test* site (more)
|
104
|
+
# DELETE /api/v4/[short site name]/subscribers/[subscriber id].xml
|
105
|
+
def destroy
|
106
|
+
begin
|
107
|
+
!! api_request(:delete, "/subscribers/#{self.customer_id}.xml")
|
108
|
+
rescue RSpreedly::Error::NotFound
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
end
|
112
|
+
alias_method :delete, :destroy
|
113
|
+
|
114
|
+
# Give a subscriber a complimentary subscription (more)
|
115
|
+
# POST /api/v4/[short site name]/subscribers/[subscriber id]/complimentary_subscriptions.xml
|
116
|
+
def comp_subscription(subscription)
|
117
|
+
result = api_request(:post, "/subscribers/#{self.customer_id}/complimentary_subscriptions.xml", :body => subscription.to_xml)
|
118
|
+
self.attributes = result["subscriber"]
|
119
|
+
true
|
120
|
+
end
|
121
|
+
|
122
|
+
# Give a subscriber a complimentary time extension (more)
|
123
|
+
# POST /api/v4/[short site name]/subscribers/[subscriber id]/complimentary_time_extension.xml
|
124
|
+
def comp_time_extension(extension)
|
125
|
+
result = api_request(:post, "/subscribers/#{self.customer_id}/complimentary_time_extensions.xml", :body => extension.to_xml)
|
126
|
+
self.attributes = result["subscriber"]
|
127
|
+
true
|
128
|
+
end
|
129
|
+
|
130
|
+
# Programatically Stopping Auto Renew of a Subscriber (more)
|
131
|
+
# POST /api/v4/[short site name]/subscribers/[subscriber id]/stop_auto_renew.xml
|
132
|
+
def stop_auto_renew
|
133
|
+
!! api_request(:post, "/subscribers/#{self.customer_id}/stop_auto_renew.xml")
|
134
|
+
end
|
135
|
+
|
136
|
+
# Programatically Subscribe a Subscriber to a Free Trial Plan (more)
|
137
|
+
# POST /api/v4/[short site name]/subscribers/[subscriber id]/subscribe_to_free_trial.xml
|
138
|
+
def subscribe_to_free_trial(plan)
|
139
|
+
result = api_request(:post, "/subscribers/#{self.customer_id}/subscribe_to_free_trial.xml", :body => plan.to_xml)
|
140
|
+
self.attributes = result["subscriber"]
|
141
|
+
true
|
142
|
+
end
|
143
|
+
|
144
|
+
# Programatically Allow Another Free Trial (more)
|
145
|
+
# POST /api/v4/[short site name]/subscribers/[subscriber id]/allow_free_trial.xml
|
146
|
+
def allow_free_trial
|
147
|
+
result = api_request(:post, "/subscribers/#{self.customer_id}/allow_free_trial.xml")
|
148
|
+
self.attributes = result["subscriber"]
|
149
|
+
true
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module RSpreedly
|
2
|
+
|
3
|
+
class SubscriptionPlan < Base
|
4
|
+
|
5
|
+
attr_accessor :amount,
|
6
|
+
:charge_after_first_period,
|
7
|
+
:charge_later_duration_quantity,
|
8
|
+
:charge_later_duration_units,
|
9
|
+
:created_at,
|
10
|
+
:currency_code,
|
11
|
+
:description,
|
12
|
+
:duration_quantity,
|
13
|
+
:duration_units,
|
14
|
+
:enabled,
|
15
|
+
:feature_level,
|
16
|
+
:force_recurring,
|
17
|
+
:id,
|
18
|
+
:name,
|
19
|
+
:needs_to_be_renewed,
|
20
|
+
:plan_type,
|
21
|
+
:price,
|
22
|
+
:return_url,
|
23
|
+
:terms,
|
24
|
+
:updated_at
|
25
|
+
|
26
|
+
# there's no API method for just getting one plan, so we fake it!
|
27
|
+
def self.find(id)
|
28
|
+
return all if id == :all
|
29
|
+
all.find{|plan| plan.id == id}
|
30
|
+
end
|
31
|
+
|
32
|
+
# Get a list of all subscription plans (more)
|
33
|
+
# GET /api/v4/[short site name]/subscription_plans.xml
|
34
|
+
def self.all
|
35
|
+
response = api_request(:get, "/subscription_plans.xml")
|
36
|
+
return [] unless response.has_key?("subscription_plans")
|
37
|
+
response["subscription_plans"].collect{|data| SubscriptionPlan.new(data)}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/rspreedly.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'httparty'
|
3
|
+
|
4
|
+
require 'rspreedly/error'
|
5
|
+
require 'rspreedly/config'
|
6
|
+
require 'rspreedly/base'
|
7
|
+
require 'rspreedly/invoice'
|
8
|
+
require 'rspreedly/line_item'
|
9
|
+
require 'rspreedly/subscriber'
|
10
|
+
require 'rspreedly/subscription_plan'
|
11
|
+
require 'rspreedly/payment_method'
|
12
|
+
require 'rspreedly/complimentary_subscription'
|
13
|
+
require 'rspreedly/complimentary_time_extension'
|
14
|
+
|
15
|
+
|
16
|
+
module RSpreedly
|
17
|
+
|
18
|
+
# a few utility methods
|
19
|
+
|
20
|
+
# pretty much stolen from Rails
|
21
|
+
def self.underscore(camel_cased_word)
|
22
|
+
camel_cased_word.to_s.gsub(/\w+::/, '').
|
23
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
24
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
25
|
+
tr("-", "_").
|
26
|
+
downcase
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|