jsmestad-chargify 0.3.0.pre5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/.gitignore +23 -0
  2. data/Gemfile +20 -0
  3. data/LICENSE +20 -0
  4. data/README.markdown +38 -0
  5. data/Rakefile +38 -0
  6. data/VERSION +1 -0
  7. data/changelog.md +24 -0
  8. data/jsmestad-chargify.gemspec +97 -0
  9. data/lib/chargify.rb +22 -0
  10. data/lib/chargify/base.rb +88 -0
  11. data/lib/chargify/config.rb +86 -0
  12. data/lib/chargify/customer.rb +72 -0
  13. data/lib/chargify/error.rb +23 -0
  14. data/lib/chargify/parser.rb +13 -0
  15. data/lib/chargify/product.rb +26 -0
  16. data/lib/chargify/subscription.rb +93 -0
  17. data/lib/chargify/transaction.rb +14 -0
  18. data/spec/fixtures/charge_subscription.json +5 -0
  19. data/spec/fixtures/charge_subscription_missing_parameters.json +4 -0
  20. data/spec/fixtures/component.json +11 -0
  21. data/spec/fixtures/components.json +24 -0
  22. data/spec/fixtures/customer.json +12 -0
  23. data/spec/fixtures/customers.json +12 -0
  24. data/spec/fixtures/deleted_subscription.json +1 -0
  25. data/spec/fixtures/invalid_subscription.json +48 -0
  26. data/spec/fixtures/list_metered_subscriptions.json +3 -0
  27. data/spec/fixtures/migrate_subscription.json +51 -0
  28. data/spec/fixtures/new_customer.json +12 -0
  29. data/spec/fixtures/product.json +17 -0
  30. data/spec/fixtures/products.json +17 -0
  31. data/spec/fixtures/subscription.json +49 -0
  32. data/spec/fixtures/subscription_not_found.json +1 -0
  33. data/spec/fixtures/subscriptions.json +49 -0
  34. data/spec/spec.opts +1 -0
  35. data/spec/spec_helper.rb +26 -0
  36. data/spec/support/fakeweb_stubs.rb +33 -0
  37. data/spec/unit/chargify/config_spec.rb +147 -0
  38. data/spec/unit/chargify/customer_spec.rb +111 -0
  39. data/spec/unit/chargify/parser_spec.rb +7 -0
  40. data/spec/unit/chargify/product_spec.rb +35 -0
  41. data/spec/unit/chargify/subscription_spec.rb +304 -0
  42. data/spec/unit/chargify/transaction_spec.rb +11 -0
  43. metadata +154 -0
@@ -0,0 +1,72 @@
1
+ module Chargify
2
+ class Customer < Base
3
+
4
+ class << self
5
+
6
+ # options: page
7
+ def all(options={})
8
+ customers = api_request(:get, '/customers.json', :query => options)
9
+ customers.map{|c| Hashie::Mash.new c['customer']}
10
+ end
11
+
12
+ def find(id)
13
+ return all if id == :all
14
+
15
+ request = api_request(:get, "/customers/#{id}.json")
16
+ success = request.code == 200
17
+ response = Hashie::Mash.new(request).customer if success
18
+ Hashie::Mash.new(response || {}).update(:success? => success)
19
+ end
20
+
21
+ # def find!(id)
22
+ # request = api_request(:get, "/customers/#{id}.json", :raise_errors => true)
23
+ # response = Hashie::Mash.new(request).customer
24
+ # end
25
+
26
+ def lookup(reference_id)
27
+ request = api_request(:get, "/customers/lookup.json?reference=#{reference_id}")
28
+ success = request.code == 200
29
+ response = Hashie::Mash.new(request).customer if success
30
+ Hashie::Mash.new(response || {}).update(:success? => success)
31
+ end
32
+
33
+ #
34
+ # * first_name (Required)
35
+ # * last_name (Required)
36
+ # * email (Required)
37
+ # * organization (Optional) Company/Organization name
38
+ # * reference (Optional, but encouraged) The unique identifier used within your own application for this customer
39
+ #
40
+ def create(info={})
41
+ result = api_request(:post, "/customers.json", :body => {:customer => info})
42
+ created = true if result.code == 201
43
+ response = Hashie::Mash.new(result)
44
+ (response.customer || response).update(:success? => created)
45
+ end
46
+
47
+ #
48
+ # * first_name (Required)
49
+ # * last_name (Required)
50
+ # * email (Required)
51
+ # * organization (Optional) Company/Organization name
52
+ # * reference (Optional, but encouraged) The unique identifier used within your own application for this customer
53
+ #
54
+ def update(info={})
55
+ info.stringify_keys!
56
+ chargify_id = info.delete('id')
57
+ result = api_request(:put, "/customers/#{chargify_id}.json", :body => {:customer => info})
58
+
59
+ response = Hashie::Mash.new(result)
60
+ return response.customer unless response.customer.to_a.empty?
61
+ response
62
+ end
63
+
64
+ def subscriptions(id)
65
+ subscriptions = api_request(:get, "/customers/#{id}/subscriptions.json")
66
+ subscriptions.map{|s| Hashie::Mash.new s['subscription']}
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,23 @@
1
+ module Chargify
2
+ module Error
3
+
4
+ class Base < StandardError
5
+ attr_reader :response
6
+
7
+ def initialize(response=nil)
8
+ @response = response
9
+ end
10
+ end
11
+
12
+ class AccessDenied < Base; end # 401 errors
13
+ class Forbidden < Base; end # 403 errors
14
+ class BadRequest < Base; end # 422 errors
15
+ class NotFound < Base; end # 404 errors
16
+ class GatewayTimeout < Base; end # 504 errors
17
+ class ConnectionFailed < Base; end
18
+
19
+ class UnexpectedResponse < Base; end
20
+
21
+ end
22
+ end
23
+
@@ -0,0 +1,13 @@
1
+ module Chargify
2
+ class Parser < HTTParty::Parser
3
+
4
+ def parse
5
+ begin
6
+ Crack::JSON.parse(body)
7
+ rescue => e
8
+ raise(Chargify::Error::UnexpectedResponse.new(e.message), body)
9
+ end
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,26 @@
1
+ module Chargify
2
+ class Product < Base
3
+
4
+ class << self
5
+
6
+ def all
7
+ result = api_request(:get, "/products.json")
8
+ result.map{|p| Hashie::Mash.new p['product']}
9
+ end
10
+
11
+ def find(id)
12
+ return all if id == :all
13
+
14
+ result = api_request(:get, "/products/#{id}.json")
15
+ Hashie::Mash.new(result).product
16
+ end
17
+
18
+ def find_by_handle(handle)
19
+ result = api_request(:get, "/products/handle/#{handle}.json")
20
+ Hashie::Mash.new(result).product
21
+ end
22
+
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,93 @@
1
+ module Chargify
2
+ class Subscription < Base
3
+
4
+ class << self
5
+
6
+ def find(id)
7
+ result = api_request(:get, "/subscriptions/#{id}.json")
8
+ return nil if result.code != 200
9
+ Hashie::Mash.new(result).subscription
10
+ end
11
+
12
+ # Returns all elements outputted by Chargify plus:
13
+ # response.success? -> true if response code is 201, false otherwise
14
+ def create(subscription_attributes={})
15
+ result = api_request(:post, "/subscriptions.json", :body => {:subscription => subscription_attributes})
16
+ created = true if result.code == 201
17
+ response = Hashie::Mash.new(result)
18
+ (response.subscription || response).update(:success? => created)
19
+ end
20
+
21
+ # Returns all elements outputted by Chargify plus:
22
+ # response.success? -> true if response code is 200, false otherwise
23
+ def update(sub_id, subscription_attributes = {})
24
+ result = api_request(:put, "/subscriptions/#{sub_id}.json", :body => {:subscription => subscription_attributes})
25
+ updated = true if result.code == 200
26
+ response = Hashie::Mash.new(result)
27
+ (response.subscription || response).update(:success? => updated)
28
+ end
29
+
30
+ # Returns all elements outputted by Chargify plus:
31
+ # response.success? -> true if response code is 200, false otherwise
32
+ def cancel(sub_id, message="")
33
+ result = api_request(:delete, "/subscriptions/#{sub_id}.json", :body => {:subscription => {:cancellation_message => message} })
34
+ deleted = true if result.code == 200
35
+ response = Hashie::Mash.new(result)
36
+ (response.subscription || response).update(:success? => deleted)
37
+ end
38
+
39
+ def reactivate(sub_id)
40
+ result = api_request(:put, "/subscriptions/#{sub_id}/reactivate.json", :body => "")
41
+ reactivated = true if result.code == 200
42
+ response = Hashie::Mash.new(result) rescue Hashie::Mash.new
43
+ (response.subscription || response).update(:success? => reactivated)
44
+ end
45
+
46
+ def charge(sub_id, subscription_attributes={})
47
+ result = api_request(:post, "/subscriptions/#{sub_id}/charges.json", :body => { :charge => subscription_attributes })
48
+ success = result.code == 201
49
+ result = {} if result.code == 404
50
+
51
+ response = Hashie::Mash.new(result)
52
+ (response.charge || response).update(:success? => success)
53
+ end
54
+
55
+ def migrate(sub_id, product_id)
56
+ result = api_request(:post, "/subscriptions/#{sub_id}/migrations.json", :body => {:product_id => product_id })
57
+ success = true if result.code == 200
58
+ response = Hashie::Mash.new(result)
59
+ (response.subscription || {}).update(:success? => success)
60
+ end
61
+
62
+ def transactions(sub_id, options={})
63
+ result = api_request(:get, "/subscriptions/#{sub_id}/transactions.json", :query => options)
64
+ result.map{|t| Hashie::Mash.new t['transaction']}
65
+ end
66
+
67
+ def components(subscription_id)
68
+ result = api_request(:get, "/subscriptions/#{subscription_id}/components.json")
69
+ result.map{|c| Hashie::Mash.new c['component']}
70
+ end
71
+
72
+ def find_component(subscription_id, component_id)
73
+ result = get("/subscriptions/#{subscription_id}/components/#{component_id}.json")
74
+ Hashie::Mash.new(result).component
75
+ end
76
+
77
+ def update_component(subscription_id, component_id, quantity)
78
+ result = api_request(:put, "/subscriptions/#{subscription_id}/components/#{component_id}.json", :body => {:component => {:allocated_quantity => quantity}})
79
+ result[:success?] = result.code == 200
80
+ Hashie::Mash.new(result)
81
+ end
82
+
83
+ def component_usage(subscription_id, component_id)
84
+ result = api_request(:get, "/subscriptions/#{subscription_id}/components/#{component_id}/usages.json")
85
+ success = result.code == 200
86
+ response = Hashie::Mash.new(result)
87
+ response.update(:success? => success)
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+ 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
@@ -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
+ }