stefl-chargify 0.3.3

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 (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