jsmestad-chargify 0.3.0.pre5

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