stefl-chargify 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.gitignore +23 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +20 -0
  4. data/Gemfile.lock +51 -0
  5. data/LICENSE +20 -0
  6. data/README.markdown +46 -0
  7. data/Rakefile +33 -0
  8. data/VERSION +1 -0
  9. data/changelog.md +30 -0
  10. data/lib/chargify/base.rb +89 -0
  11. data/lib/chargify/config.rb +86 -0
  12. data/lib/chargify/customer.rb +101 -0
  13. data/lib/chargify/error.rb +24 -0
  14. data/lib/chargify/parser.rb +13 -0
  15. data/lib/chargify/product.rb +38 -0
  16. data/lib/chargify/product_family.rb +47 -0
  17. data/lib/chargify/subscription.rb +154 -0
  18. data/lib/chargify/transaction.rb +14 -0
  19. data/lib/chargify.rb +18 -0
  20. data/spec/fixtures/charge_subscription.json +5 -0
  21. data/spec/fixtures/charge_subscription_missing_parameters.json +4 -0
  22. data/spec/fixtures/component.json +11 -0
  23. data/spec/fixtures/components.json +24 -0
  24. data/spec/fixtures/customer.json +12 -0
  25. data/spec/fixtures/customers.json +12 -0
  26. data/spec/fixtures/deleted_subscription.json +1 -0
  27. data/spec/fixtures/invalid_subscription.json +48 -0
  28. data/spec/fixtures/list_metered_subscriptions.json +3 -0
  29. data/spec/fixtures/migrate_subscription.json +51 -0
  30. data/spec/fixtures/new_customer.json +12 -0
  31. data/spec/fixtures/product.json +17 -0
  32. data/spec/fixtures/products.json +17 -0
  33. data/spec/fixtures/subscription.json +49 -0
  34. data/spec/fixtures/subscription_not_found.json +1 -0
  35. data/spec/fixtures/subscriptions.json +49 -0
  36. data/spec/spec_helper.rb +27 -0
  37. data/spec/support/fakeweb_stubs.rb +33 -0
  38. data/spec/unit/chargify/config_spec.rb +147 -0
  39. data/spec/unit/chargify/customer_spec.rb +186 -0
  40. data/spec/unit/chargify/parser_spec.rb +7 -0
  41. data/spec/unit/chargify/product_spec.rb +40 -0
  42. data/spec/unit/chargify/subscription_spec.rb +432 -0
  43. data/spec/unit/chargify/transaction_spec.rb +11 -0
  44. data/stefl-chargify.gemspec +102 -0
  45. metadata +180 -0
@@ -0,0 +1,154 @@
1
+ module Chargify
2
+ class Subscription < Base
3
+
4
+ class << self
5
+
6
+ def all
7
+ result = api_request(:get, "/subscriptions.json")
8
+ result.map{|p| Hashie::Mash.new p['subscription']}
9
+ end
10
+
11
+ def find!(id)
12
+ return all if id == :all
13
+
14
+ result = api_request(:get, "/subscriptions/#{id}.json")
15
+ Hashie::Mash.new(result).subscription
16
+ end
17
+
18
+ def find(id)
19
+ find!(id)
20
+ rescue Chargify::Error::Base => e
21
+ return nil
22
+ end
23
+
24
+ def create!(subscription_attributes={})
25
+ result = api_request(:post, "/subscriptions.json", :body => {:subscription => subscription_attributes})
26
+ response = Hashie::Mash.new(result)
27
+ response.subscription
28
+ end
29
+
30
+ def create(subscription_attributes={})
31
+ create!(subscription_attributes)
32
+ rescue Chargify::Error::Base => e
33
+ return false
34
+ end
35
+
36
+ def update!(sub_id, subscription_attributes={})
37
+ result = api_request(:put, "/subscriptions/#{sub_id}.json", :body => {:subscription => subscription_attributes})
38
+ response = Hashie::Mash.new(result)
39
+ response.subscription
40
+ end
41
+
42
+ def update(sub_id, subscription_attributes={})
43
+ update!(sub_id, subscription_attributes)
44
+ rescue Chargify::Error::Base => e
45
+ return false
46
+ end
47
+
48
+ def cancel!(sub_id, message="")
49
+ result = api_request(:delete, "/subscriptions/#{sub_id}.json", :body => {:subscription => {:cancellation_message => message} })
50
+ true if result.code == 200
51
+ end
52
+
53
+ def cancel(sub_id, message="")
54
+ cancel!(sub_id, message)
55
+ rescue Chargify::Error::Base => e
56
+ return false
57
+ end
58
+
59
+ def reactivate!(sub_id)
60
+ result = api_request(:put, "/subscriptions/#{sub_id}/reactivate.json", :body => "")
61
+ response = Hashie::Mash.new(result)
62
+ response.subscription
63
+ end
64
+
65
+ def reactivate(sub_id)
66
+ reactivate!(sub_id)
67
+ rescue Chargify::Error::Base => e
68
+ return false
69
+ end
70
+
71
+ def charge!(sub_id, subscription_attributes={})
72
+ result = api_request(:post, "/subscriptions/#{sub_id}/charges.json", :body => { :charge => subscription_attributes })
73
+ response = Hashie::Mash.new(result)
74
+ response.charge
75
+ end
76
+
77
+ def charge(sub_id, subscription_attributes={})
78
+ charge!(sub_id, subscription_attributes)
79
+ rescue Chargify::Error::Base => e
80
+ return false
81
+ end
82
+
83
+ def migrate!(sub_id, product_id)
84
+ result = api_request(:post, "/subscriptions/#{sub_id}/migrations.json", :body => {:product_id => product_id })
85
+ response = Hashie::Mash.new(result)
86
+ response.subscription
87
+ end
88
+
89
+ def migrate(sub_id, product_id)
90
+ migrate!(sub_id, product_id)
91
+ rescue Chargify::Error::Base => e
92
+ return false
93
+ end
94
+
95
+ def transactions!(sub_id, options={})
96
+ result = api_request(:get, "/subscriptions/#{sub_id}/transactions.json", :query => options)
97
+ result.map{|t| Hashie::Mash.new t['transaction']}
98
+ end
99
+
100
+ def transactions(sub_id, options={})
101
+ transactions!(sub_id, options)
102
+ rescue Chargify::Error::Base => e
103
+ return false
104
+ end
105
+
106
+ def components!(subscription_id)
107
+ result = api_request(:get, "/subscriptions/#{subscription_id}/components.json")
108
+ result.map{|c| Hashie::Mash.new c['component']}
109
+ end
110
+
111
+ def components(subscription_id)
112
+ components!(subscription_id)
113
+ rescue Chargify::Error::Base => e
114
+ return false
115
+ end
116
+
117
+ def find_component!(subscription_id, component_id)
118
+ result = api_request(:get, "/subscriptions/#{subscription_id}/components/#{component_id}.json")
119
+ Hashie::Mash.new(result).component
120
+ end
121
+
122
+ def find_component(subscription_id, component_id)
123
+ find_component!(subscription_id, component_id)
124
+ rescue Chargify::Error::Base => e
125
+ return false
126
+ end
127
+
128
+ def update_component!(subscription_id, component_id, quantity)
129
+ result = api_request(:put, "/subscriptions/#{subscription_id}/components/#{component_id}.json", :body => {:component => {:allocated_quantity => quantity}})
130
+ Hashie::Mash.new(result)
131
+ end
132
+
133
+ def update_component(subscription_id, component_id, quantity)
134
+ update_component!(subscription_id, component_id, quantity)
135
+ rescue Chargify::Error::Base => e
136
+ return false
137
+ end
138
+
139
+ def component_usage!(subscription_id, component_id)
140
+ result = api_request(:get, "/subscriptions/#{subscription_id}/components/#{component_id}/usages.json")
141
+ response = Hashie::Mash.new(result)
142
+ response
143
+ end
144
+
145
+ def component_usage(subscription_id, component_id)
146
+ component_usage!(subscription_id, component_id)
147
+ rescue Chargify::Error::Base => e
148
+ return false
149
+ end
150
+
151
+ end
152
+
153
+ end
154
+ end
@@ -0,0 +1,14 @@
1
+ module Chargify
2
+ class Transaction < Base
3
+
4
+ class << self
5
+
6
+ def all(options={})
7
+ result = api_request(:get, "/transactions.json", :query => options)
8
+ result.map{|t| Hashie::Mash.new t['transaction']}
9
+ end
10
+
11
+ end
12
+
13
+ end
14
+ end
data/lib/chargify.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'hashie'
2
+ require 'httparty'
3
+ require 'json'
4
+ require 'active_support/core_ext/hash'
5
+
6
+ Hash.send :include, Hashie::HashExtensions
7
+
8
+ module Chargify
9
+ autoload :Base, 'chargify/base'
10
+ autoload :Config, 'chargify/config'
11
+ autoload :Customer, 'chargify/customer'
12
+ autoload :Error, 'chargify/error'
13
+ autoload :Parser, 'chargify/parser'
14
+ autoload :Product, 'chargify/product'
15
+ autoload :ProductFamily, 'chargify/product_family'
16
+ autoload :Subscription, 'chargify/subscription'
17
+ autoload :Transaction, 'chargify/transaction'
18
+ end
@@ -0,0 +1,5 @@
1
+ {"charge":{
2
+ "success":true,
3
+ "memo":"This is the description of the one time charge.",
4
+ "amount_in_cents":100
5
+ }}
@@ -0,0 +1,4 @@
1
+ {"errors":[
2
+ "Memo: cannot be blank.",
3
+ "Amount: is not a number."
4
+ ]}
@@ -0,0 +1,11 @@
1
+ {
2
+ "component": {
3
+ "kind": "quantity_based_component",
4
+ "name": "Extra Rubies",
5
+ "allocated_quantity": 42,
6
+ "subscription_id": 16,
7
+ "pricing_scheme": "per_unit",
8
+ "component_id": 84,
9
+ "unit_name": "band"
10
+ }
11
+ }
@@ -0,0 +1,24 @@
1
+ [
2
+ {
3
+ "component": {
4
+ "kind": "quantity_based_component",
5
+ "name": "Extra Rubies",
6
+ "allocated_quantity": 42,
7
+ "subscription_id": 16,
8
+ "pricing_scheme": "per_unit",
9
+ "component_id": 84,
10
+ "unit_name": "band"
11
+ }
12
+ },
13
+ {
14
+ "component": {
15
+ "kind": "quantity_based_component",
16
+ "name": "IP addresses",
17
+ "allocated_quantity": 2,
18
+ "subscription_id": 16,
19
+ "pricing_scheme": "per_unit",
20
+ "component_id": 24,
21
+ "unit_name": "address"
22
+ }
23
+ }
24
+ ]
@@ -0,0 +1,12 @@
1
+ {
2
+ "customer": {
3
+ "reference": "bradleyjoyce",
4
+ "updated_at": "2009-10-07T11:10:27-04:00",
5
+ "id": 16,
6
+ "organization": "Squeejee",
7
+ "first_name": "Bradley",
8
+ "last_name": "Joyce",
9
+ "email": "bradley@squeejee.com",
10
+ "created_at": "2009-10-07T11:10:27-04:00"
11
+ }
12
+ }
@@ -0,0 +1,12 @@
1
+ [{
2
+ "customer": {
3
+ "reference": "bradleyjoyce",
4
+ "updated_at": "2009-10-07T11:10:27-04:00",
5
+ "id": 16,
6
+ "organization": "Squeejee",
7
+ "first_name": "Bradley",
8
+ "last_name": "Joyce",
9
+ "email": "bradley@squeejee.com",
10
+ "created_at": "2009-10-07T11:10:27-04:00"
11
+ }
12
+ }]
@@ -0,0 +1 @@
1
+ {"created_at":"Tue Jan 26 18:40:32 -0600 2010","activated_at":"Tue Jan 26 18:40:33 -0600 2010","expires_at":null,"cancellation_message":"Optional message","trial_ended_at":null,"updated_at":"Tue Jan 26 18:40:35 -0600 2010","credit_card":{"card_type":"bogus","expiration_year":2013,"masked_card_number":"XXXX-XXXX-XXXX-1","expiration_month":3,"last_name":"Indicisive","first_name":"John"},"id":3642,"current_period_ends_at":"Fri Feb 26 18:40:32 -0600 2010","product":{"product_family":{"name":"ZipZoomAuto","handle":"zipzoomauto","accounting_code":null,"id":268,"description":""},"name":"Basic Plan","handle":"basic","price_in_cents":5000,"accounting_code":"","id":689,"interval":1,"description":"","interval_unit":"month"},"success?":true,"customer":{"reference":"11654","created_at":"Tue Jan 26 18:40:32 -0600 2010","updated_at":"Tue Jan 26 18:40:32 -0600 2010","id":3546,"last_name":"Indicisive","organization":null,"email":"john@doe.com","first_name":"John"},"trial_started_at":null,"balance_in_cents":0,"current_period_started_at":"Tue Jan 26 18:40:32 -0600 2010","state":"canceled"}
@@ -0,0 +1,48 @@
1
+ "subscription": {
2
+ "customer": {
3
+ "reference": "bradleyjoyce",
4
+ "updated_at": "2009-10-07T11:10:27-04:00",
5
+ "id": 16,
6
+ "organization": "Squeejee",
7
+ "first_name": "Bradley",
8
+ "last_name": "Joyce",
9
+ "email": "bradley@squeejee.com",
10
+ "created_at": "2009-10-07T11:10:27-04:00"
11
+ },
12
+ "cancellation_message": null,
13
+ "updated_at": "2009-10-07T11:10:56-04:00",
14
+ "expires_at": null,
15
+ "activated_at": "2009-10-23T16:16:59-04:00",
16
+ "current_period_started_at": "2009-11-14T11:10:56-05:00",
17
+ "credit_card": {
18
+ "card_type": "bogus",
19
+ "expiration_year": 2015,
20
+ "masked_card_number": "XXXX-XXXX-XXXX-1",
21
+ "first_name": "Bradley",
22
+ "last_name": "Joyce",
23
+ "expiration_month": 7
24
+ },
25
+ "trial_ended_at": "2009-10-14T11:10:56-04:00",
26
+ "id": 14,
27
+ "product": {
28
+ "price_in_cents": 500,
29
+ "name": "Monthly",
30
+ "handle": "monthly",
31
+ "id": 8,
32
+ "accounting_code": "TSMO",
33
+ "product_family": {
34
+ "name": "TweetSaver",
35
+ "handle": "tweetsaver",
36
+ "id": 7,
37
+ "accounting_code": null
38
+ },
39
+ "interval_unit": "month",
40
+ "interval": 1
41
+ },
42
+ "current_period_ends_at": "2009-12-14T11:10:56-05:00",
43
+ "trial_started_at": "2009-10-07T11:10:56-04:00",
44
+ "balance_in_cents": 0,
45
+ "state": "active",
46
+ "created_at": "2009-10-07T11:10:56-04:00"
47
+ }
48
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "usages": []
3
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "subscription": {
3
+ "id": 123,
4
+ "state": "active",
5
+ "balance_in_cents": "auto generated",
6
+ "current_period_started_at": "auto generated",
7
+ "current_period_ends_at": "auto generated",
8
+ "activated_at": "auto generated",
9
+ "trial_ended_at": "auto generated",
10
+ "trial_started_at": "auto generated",
11
+ "expires_at": "auto generated",
12
+ "created_at": "auto generated",
13
+ "updated_at": "auto generated",
14
+ "cancellation_message": null,
15
+ "customer": {
16
+ "id": "auto generated",
17
+ "first_name": "your value",
18
+ "last_name": "your value",
19
+ "email": "your value",
20
+ "organization": "your value",
21
+ "reference": "your value",
22
+ "updated_at": "auto generated",
23
+ "created_at": "auto generated"
24
+ },
25
+ "product": {
26
+ "id": 354,
27
+ "name": "[@products.last.name]",
28
+ "handle": 354,
29
+ "price_in_cents": 1000,
30
+ "accounting_code": "[@products.last.accounting_code]",
31
+ "description": "your value",
32
+ "interval": 3600,
33
+ "interval_unit": "[@products.last.interval_unit]",
34
+ "product_family": {
35
+ "id": 15,
36
+ "name": "[@products.last.product_family.name]",
37
+ "handle": "[@products.last.product_family.handle]",
38
+ "accounting_code": "[@products.last.product_family.accounting_code]",
39
+ "description": "your value"
40
+ }
41
+ },
42
+ "credit_card": {
43
+ "first_name": "your value",
44
+ "last_name": "your value",
45
+ "masked_card_number": "your value",
46
+ "card_type": "auto generated",
47
+ "expiration_month": "your value",
48
+ "expiration_year": "your value"
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "customer": {
3
+ "created_at": "2009-11-18T10:56:22-05:00",
4
+ "email": "wynn.netherland@gmail.com",
5
+ "first_name": "Wynn",
6
+ "id": 333,
7
+ "last_name": "Netherland",
8
+ "organization": null,
9
+ "reference": null,
10
+ "updated_at": "2009-11-18T10:56:22-05:00"
11
+ }
12
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "product": {
3
+ "price_in_cents": 500,
4
+ "name": "Monthly",
5
+ "handle": "monthly",
6
+ "id": 8,
7
+ "accounting_code": "TSMO",
8
+ "product_family": {
9
+ "name": "TweetSaver",
10
+ "handle": "tweetsaver",
11
+ "id": 7,
12
+ "accounting_code": null
13
+ },
14
+ "interval_unit": "month",
15
+ "interval": 1
16
+ }
17
+ }
@@ -0,0 +1,17 @@
1
+ [{
2
+ "product": {
3
+ "price_in_cents": 500,
4
+ "name": "Monthly",
5
+ "handle": "monthly",
6
+ "id": 8,
7
+ "accounting_code": "TSMO",
8
+ "product_family": {
9
+ "name": "TweetSaver",
10
+ "handle": "tweetsaver",
11
+ "id": 7,
12
+ "accounting_code": null
13
+ },
14
+ "interval_unit": "month",
15
+ "interval": 1
16
+ }
17
+ }]
@@ -0,0 +1,49 @@
1
+ {
2
+ "subscription": {
3
+ "customer": {
4
+ "reference": "bradleyjoyce",
5
+ "updated_at": "2009-10-07T11:10:27-04:00",
6
+ "id": 16,
7
+ "organization": "Squeejee",
8
+ "first_name": "Bradley",
9
+ "last_name": "Joyce",
10
+ "email": "bradley@squeejee.com",
11
+ "created_at": "2009-10-07T11:10:27-04:00"
12
+ },
13
+ "cancellation_message": null,
14
+ "updated_at": "2009-10-07T11:10:56-04:00",
15
+ "expires_at": null,
16
+ "activated_at": "2009-10-23T16:16:59-04:00",
17
+ "current_period_started_at": "2009-11-14T11:10:56-05:00",
18
+ "credit_card": {
19
+ "card_type": "bogus",
20
+ "expiration_year": 2015,
21
+ "masked_card_number": "XXXX-XXXX-XXXX-1",
22
+ "first_name": "Bradley",
23
+ "last_name": "Joyce",
24
+ "expiration_month": 7
25
+ },
26
+ "trial_ended_at": "2009-10-14T11:10:56-04:00",
27
+ "id": 14,
28
+ "product": {
29
+ "price_in_cents": 500,
30
+ "name": "Monthly",
31
+ "handle": "monthly",
32
+ "id": 8,
33
+ "accounting_code": "TSMO",
34
+ "product_family": {
35
+ "name": "TweetSaver",
36
+ "handle": "tweetsaver",
37
+ "id": 7,
38
+ "accounting_code": null
39
+ },
40
+ "interval_unit": "month",
41
+ "interval": 1
42
+ },
43
+ "current_period_ends_at": "2009-12-14T11:10:56-05:00",
44
+ "trial_started_at": "2009-10-07T11:10:56-04:00",
45
+ "balance_in_cents": 0,
46
+ "state": "active",
47
+ "created_at": "2009-10-07T11:10:56-04:00"
48
+ }
49
+ }
@@ -0,0 +1 @@
1
+ \r\n
@@ -0,0 +1,49 @@
1
+ [{
2
+ "subscription": {
3
+ "customer": {
4
+ "reference": "bradleyjoyce",
5
+ "updated_at": "2009-10-07T11:10:27-04:00",
6
+ "id": 16,
7
+ "organization": "Squeejee",
8
+ "first_name": "Bradley",
9
+ "last_name": "Joyce",
10
+ "email": "bradley@squeejee.com",
11
+ "created_at": "2009-10-07T11:10:27-04:00"
12
+ },
13
+ "cancellation_message": null,
14
+ "updated_at": "2009-10-07T11:10:56-04:00",
15
+ "expires_at": null,
16
+ "activated_at": "2009-10-23T16:16:59-04:00",
17
+ "current_period_started_at": "2009-11-14T11:10:56-05:00",
18
+ "credit_card": {
19
+ "card_type": "bogus",
20
+ "expiration_year": 2015,
21
+ "masked_card_number": "XXXX-XXXX-XXXX-1",
22
+ "first_name": "Bradley",
23
+ "last_name": "Joyce",
24
+ "expiration_month": 7
25
+ },
26
+ "trial_ended_at": "2009-10-14T11:10:56-04:00",
27
+ "id": 14,
28
+ "product": {
29
+ "price_in_cents": 500,
30
+ "name": "Monthly",
31
+ "handle": "monthly",
32
+ "id": 8,
33
+ "accounting_code": "TSMO",
34
+ "product_family": {
35
+ "name": "TweetSaver",
36
+ "handle": "tweetsaver",
37
+ "id": 7,
38
+ "accounting_code": null
39
+ },
40
+ "interval_unit": "month",
41
+ "interval": 1
42
+ },
43
+ "current_period_ends_at": "2009-12-14T11:10:56-05:00",
44
+ "trial_started_at": "2009-10-07T11:10:56-04:00",
45
+ "balance_in_cents": 0,
46
+ "state": "active",
47
+ "created_at": "2009-10-07T11:10:56-04:00"
48
+ }
49
+ }]
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require 'logger'
4
+
5
+ Bundler.require(:default, :runtime, :test)
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+
9
+ require 'chargify'
10
+ require 'rspec/core'
11
+ require 'autotest/rspec2'
12
+
13
+ # Requires supporting files with custom matchers and macros, etc,
14
+ # in ./support/ and its subdirectories.
15
+ Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
16
+
17
+ FakeWeb.allow_net_connect = false
18
+
19
+ RSpec.configure do |config|
20
+ # config.include(Rack::Test::Methods)
21
+
22
+ config.before :suite do
23
+
24
+ end
25
+
26
+ end
27
+
@@ -0,0 +1,33 @@
1
+ def fixture_file(filename)
2
+ return '' if filename == ''
3
+ file_path = File.join(File.dirname(__FILE__), '..', 'fixtures', filename)
4
+ File.read(file_path)
5
+ end
6
+
7
+ def stub_get(url, filename, status=nil)
8
+ options = {:body => fixture_file(filename)}
9
+ options.merge!({:status => status}) unless status.nil?
10
+
11
+ FakeWeb.register_uri(:get, url, options)
12
+ end
13
+
14
+ def stub_post(url, filename, status=nil)
15
+ options = {:body => fixture_file(filename)}
16
+ options.merge!({:status => status}) unless status.nil?
17
+
18
+ FakeWeb.register_uri(:post, url, options)
19
+ end
20
+
21
+ def stub_put(url, filename, status=nil)
22
+ options = {:body => fixture_file(filename)}
23
+ options.merge!({:status => status}) unless status.nil?
24
+
25
+ FakeWeb.register_uri(:put, url, options)
26
+ end
27
+
28
+ def stub_delete(url, filename, status=nil)
29
+ options = {:body => fixture_file(filename)}
30
+ options.merge!({:status => status}) unless status.nil?
31
+
32
+ FakeWeb.register_uri(:delete, url, options)
33
+ end