chargify 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,15 +1,15 @@
1
- = chargify
1
+ # chargify
2
2
 
3
3
  Ruby wrapper for the chargify.com SAAS and billing API
4
4
 
5
- == Installation
5
+ ## Installation
6
6
 
7
7
  sudo gem install gemcutter
8
8
  gem tumble
9
9
  sudo gem install chargify
10
10
 
11
11
 
12
- == Note on Patches/Pull Requests
12
+ ## Note on Patches/Pull Requests
13
13
 
14
14
  * Fork the project.
15
15
  * Make your feature addition or bug fix.
@@ -20,6 +20,6 @@ Ruby wrapper for the chargify.com SAAS and billing API
20
20
  bump version in a commit by itself I can ignore when I pull)
21
21
  * Send me a pull request. Bonus points for topic branches.
22
22
 
23
- == Copyright
23
+ ### Copyright
24
24
 
25
- Copyright (c) 2009 Wynn Netherland. See LICENSE for details.
25
+ Copyright (c) 2009 [Wynn Netherland](http://wynnnetherland.com). See LICENSE for details.
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ begin
9
9
  gem.description = %Q{Ruby wrapper for the chargify.com SAAS and billing API}
10
10
  gem.email = "wynn.netherland@gmail.com"
11
11
  gem.homepage = "http://github.com/pengwynn/chargify"
12
- gem.authors = ["Wynn Netherland"]
12
+ gem.authors = ["Wynn Netherland","Nash Kabbara"]
13
13
 
14
14
  gem.add_dependency('hashie', '~> 0.1.3')
15
15
  gem.add_dependency('httparty', '~> 0.4.5')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0 January 26, 2010
4
+
5
+ * Substantial fixes and convenience enhancements from [@nkabbara](http://github.com/nkabbara)
6
+
7
+ ## 0.1.0 November 18, 2009
8
+
9
+ * Initial version
@@ -0,0 +1,80 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{chargify}
8
+ s.version = "0.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Wynn Netherland", "Nash Kabbara"]
12
+ s.date = %q{2010-01-26}
13
+ s.description = %q{Ruby wrapper for the chargify.com SAAS and billing API}
14
+ s.email = %q{wynn.netherland@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.markdown"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.markdown",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "changelog.md",
27
+ "chargify.gemspec",
28
+ "lib/chargify.rb",
29
+ "lib/chargify/client.rb",
30
+ "test/fixtures/customer.json",
31
+ "test/fixtures/customers.json",
32
+ "test/fixtures/deleted_subscription.json",
33
+ "test/fixtures/invalid_subscription.json",
34
+ "test/fixtures/new_customer.json",
35
+ "test/fixtures/product.json",
36
+ "test/fixtures/products.json",
37
+ "test/fixtures/subscription.json",
38
+ "test/fixtures/subscriptions.json",
39
+ "test/helper.rb",
40
+ "test/test_chargify.rb"
41
+ ]
42
+ s.homepage = %q{http://github.com/pengwynn/chargify}
43
+ s.rdoc_options = ["--charset=UTF-8"]
44
+ s.require_paths = ["lib"]
45
+ s.rubygems_version = %q{1.3.5}
46
+ s.summary = %q{Ruby wrapper for the chargify.com SAAS and billing API}
47
+ s.test_files = [
48
+ "test/helper.rb",
49
+ "test/test_chargify.rb"
50
+ ]
51
+
52
+ if s.respond_to? :specification_version then
53
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
54
+ s.specification_version = 3
55
+
56
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
57
+ s.add_runtime_dependency(%q<hashie>, ["~> 0.1.3"])
58
+ s.add_runtime_dependency(%q<httparty>, ["~> 0.4.5"])
59
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 2.10.1"])
60
+ s.add_development_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
61
+ s.add_development_dependency(%q<mocha>, ["= 0.9.4"])
62
+ s.add_development_dependency(%q<fakeweb>, [">= 1.2.5"])
63
+ else
64
+ s.add_dependency(%q<hashie>, ["~> 0.1.3"])
65
+ s.add_dependency(%q<httparty>, ["~> 0.4.5"])
66
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 2.10.1"])
67
+ s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
68
+ s.add_dependency(%q<mocha>, ["= 0.9.4"])
69
+ s.add_dependency(%q<fakeweb>, [">= 1.2.5"])
70
+ end
71
+ else
72
+ s.add_dependency(%q<hashie>, ["~> 0.1.3"])
73
+ s.add_dependency(%q<httparty>, ["~> 0.4.5"])
74
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 2.10.1"])
75
+ s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
76
+ s.add_dependency(%q<mocha>, ["= 0.9.4"])
77
+ s.add_dependency(%q<fakeweb>, [">= 1.2.5"])
78
+ end
79
+ end
80
+
@@ -1,16 +1,16 @@
1
1
  require 'rubygems'
2
2
 
3
- gem 'oauth', '~> 0.3.5'
4
- require 'oauth'
5
-
6
3
  gem 'hashie', '~> 0.1.3'
7
4
  require 'hashie'
8
5
 
9
6
  gem 'httparty', '~> 0.4.5'
10
7
  require 'httparty'
11
8
 
9
+ gem 'json', '~> 1.1.9'
10
+ require "json"
11
+
12
12
  directory = File.expand_path(File.dirname(__FILE__))
13
13
 
14
14
  Hash.send :include, Hashie::HashExtensions
15
15
 
16
- require File.join(directory, 'chargify', 'client')
16
+ require File.join(directory, 'chargify', 'client')
@@ -1,7 +1,22 @@
1
1
  module Chargify
2
+ class UnexpectedResponseError < RuntimeError;end
3
+
4
+ def self.custom_parser
5
+ proc do |data|
6
+ begin
7
+ Crack::JSON.parse(data)
8
+ rescue => e
9
+ error_msg = "Crack could not parse JSON. It said: #{e.message}. Chargify's raw response: #{data}"
10
+ raise UnexpectedResponseError, error_msg
11
+ end
12
+ end
13
+ end
14
+
2
15
  class Client
3
16
  include HTTParty
4
17
  format :json
18
+ parser Chargify::custom_parser
19
+ headers 'Content-Type' => 'application/json'
5
20
 
6
21
  attr_reader :api_key, :subdomain
7
22
 
@@ -33,8 +48,8 @@ module Chargify
33
48
  # * reference (Optional, but encouraged) The unique identifier used within your own application for this customer
34
49
  #
35
50
  def create_customer(info={})
36
- response = Hashie::Mash.new(self.class.post("/customers.json", :body => {:customer => info}))
37
- return response.customer unless response.customer.blank?
51
+ response = Hashie::Mash.new(self.class.post("/customers.json", :body => {:customer => info}.to_json))
52
+ return response.customer if response.customer
38
53
  response
39
54
  end
40
55
 
@@ -49,7 +64,7 @@ module Chargify
49
64
  info.stringify_keys!
50
65
  chargify_id = info.delete('id')
51
66
  response = Hashie::Mash.new(self.class.put("/customers/#{chargify_id}.json", :body => {:customer => info}))
52
- return response.customer unless response.customer.blank?
67
+ return response.customer unless response.customer.to_a.empty?
53
68
  response
54
69
  end
55
70
 
@@ -62,30 +77,33 @@ module Chargify
62
77
  Hashie::Mash.new(self.class.get("/subscriptions/#{subscription_id}.json")).subscription
63
78
  end
64
79
 
65
- # When creating a subscription, you must specify a product, a customer, and payment (credit card) details.
66
- #
67
- # The product may be specified by product_id or by product_handle (API Handle).
68
- #
69
- # An existing customer may be specified by a customer_id (ID within Chargify) or a customer_reference (unique value within your app that you have shared with Chargify via the reference attribute on a customer). A new customer may be created by providing customer_attributes.
70
- #
71
- # * product_handle The API Handle of the product for which you are creating a subscription. Required, unless a product_id is given instead.
72
- # * product_id The Product ID of the product for which you are creating a subscription. The product ID is not currently published, so we recommend using the API Handle instead.
73
- # * customer_id The ID of an existing customer within Chargify. Required, unless a customer_reference or a set of customer_attributes is given.
74
- # * customer_reference The reference value (provided by your app) of an existing customer within Chargify. Required, unless a customer_id or a set of customer_attributes is given.
75
- # * customer_attributes
76
- # o first_name The first name of the customer. Required when creating a customer via attributes.
77
- # o last_name The last name of the customer. Required when creating a customer via attributes.
78
- # o email The email address of the customer. Required when creating a customer via attributes.
79
- # o organization The organization/company of the customer. Optional.
80
- # o reference A customer "reference", or unique identifier from your app, stored in Chargify. Can be used so that you may reference your customers within Chargify using the same unique value you use in your application. Optional.
81
- #
82
- def create_subscription(options, customer_attributes={})
83
- options.merge({:customer_attributes => customer_attributes}) unless customer_attributes.blank?
84
- response = Hashie::Mash.new(self.class.post("/subscriptions.json", :body => options))
85
- return response.subscription unless response.subscription.blank?
86
- response
80
+ # Returns all elements outputted by Chargify plus:
81
+ # response.success? -> true if response code is 201, false otherwise
82
+ def create_subscription(subscription_attributes={})
83
+ raw_response = self.class.post("/subscriptions.json", :body => {:subscription => subscription_attributes}.to_json)
84
+ created = true if raw_response.code == 201
85
+ response = Hashie::Mash.new(raw_response)
86
+ (response.subscription || response).update(:success? => created)
87
87
  end
88
-
88
+
89
+ # Returns all elements outputted by Chargify plus:
90
+ # response.success? -> true if response code is 200, false otherwise
91
+ def update_subscription(sub_id, subscription_attributes = {})
92
+ raw_response = self.class.put("/subscriptions/#{sub_id}.json", :body => {:subscription => subscription_attributes}.to_json)
93
+ updated = true if raw_response.code == 200
94
+ response = Hashie::Mash.new(raw_response)
95
+ (response.subscription || response).update(:success? => updated)
96
+ end
97
+
98
+ # Returns all elements outputted by Chargify plus:
99
+ # response.success? -> true if response code is 200, false otherwise
100
+ def cancel_subscription(sub_id, message="")
101
+ raw_response = self.class.delete("/subscriptions/#{sub_id}.json", :body => {:subscription => {:cancellation_message => message} }.to_json)
102
+ deleted = true if raw_response.code == 200
103
+ response = Hashie::Mash.new(raw_response)
104
+ (response.subscription || response).update(:success? => deleted)
105
+ end
106
+
89
107
  def list_products
90
108
  products = self.class.get("/products.json")
91
109
  products.map{|p| Hashie::Mash.new p['product']}
@@ -99,6 +117,5 @@ module Chargify
99
117
  Hashie::Mash.new(self.class.get("/products/handle/#{handle}.json")).product
100
118
  end
101
119
 
102
-
103
120
  end
104
- end
121
+ end
@@ -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
+ }
@@ -51,4 +51,11 @@ def stub_put(url, filename, status=nil)
51
51
  options.merge!({:status => status}) unless status.nil?
52
52
 
53
53
  FakeWeb.register_uri(:put, url, options)
54
- end
54
+ end
55
+
56
+ def stub_delete(url, filename, status=nil)
57
+ options = {:body => fixture_file(filename)}
58
+ options.merge!({:status => status}) unless status.nil?
59
+
60
+ FakeWeb.register_uri(:delete, url, options)
61
+ end
@@ -5,6 +5,22 @@ class TestChargify < Test::Unit::TestCase
5
5
  setup do
6
6
  @client = Chargify::Client.new('OU812', 'pengwynn')
7
7
  end
8
+
9
+ should "raise UnexpectedResponseError when reponse is invalid JSON" do
10
+ stub_post "https://OU812:x@pengwynn.chargify.com/subscriptions.json", "invalid_subscription.json"
11
+ options = {
12
+ :product_handle => 'monthly',
13
+ :customer_reference => 'bradleyjoyce',
14
+ :customer_attributes => {
15
+ :first_name => "Wynn",
16
+ :last_name => "Netherland",
17
+ :email => "wynn@example.com"
18
+ }
19
+ }
20
+ assert_raise Chargify::UnexpectedResponseError do
21
+ @client.create_subscription(options)
22
+ end
23
+ end
8
24
 
9
25
  should "return a list of customers" do
10
26
  stub_get "https://OU812:x@pengwynn.chargify.com/customers.json", "customers.json"
@@ -44,7 +60,7 @@ class TestChargify < Test::Unit::TestCase
44
60
  customer = @client.update_customer(info)
45
61
  customer.first_name.should == "Wynn"
46
62
  end
47
-
63
+
48
64
  should "return a list of customer subscriptions" do
49
65
  stub_get "https://OU812:x@pengwynn.chargify.com/customers/16/subscriptions.json", "subscriptions.json"
50
66
  subscriptions = @client.customer_subscriptions(16)
@@ -59,20 +75,116 @@ class TestChargify < Test::Unit::TestCase
59
75
  subscription.customer.reference.should == 'bradleyjoyce'
60
76
  end
61
77
 
78
+ should "update a customer subscription" do
79
+ stub_put "https://OU812:x@pengwynn.chargify.com/subscriptions/123.json", "subscription.json"
80
+ options = {
81
+ :product_handle => 'monthly',
82
+ :customer_reference => 'bradleyjoyce',
83
+ :customer_attributes => {
84
+ :first_name => "Wynn",
85
+ :last_name => "Netherland",
86
+ :email => "wynn@example.com"
87
+ }
88
+ }
89
+ subscription = @client.update_subscription(123, options)
90
+ subscription.customer.organization.should == 'Squeejee'
91
+ end
92
+
93
+ should "set success? to true when subscription is updated successfully" do
94
+ stub_put "https://OU812:x@pengwynn.chargify.com/subscriptions/123.json", "subscription.json", 200
95
+ options = {
96
+ :product_handle => 'monthly',
97
+ :customer_reference => 'bradleyjoyce',
98
+ :customer_attributes => {
99
+ :first_name => "Wynn",
100
+ :last_name => "Netherland",
101
+ :email => "wynn@example.com"
102
+ }
103
+ }
104
+ subscription = @client.update_subscription(123, options)
105
+ subscription.success?.should == true
106
+ end
107
+
108
+ should "set success? to false when subscription is not updated successfully" do
109
+ stub_put "https://OU812:x@pengwynn.chargify.com/subscriptions/123.json", "subscription.json", 500
110
+ options = {
111
+ :product_handle => 'monthly',
112
+ :customer_reference => 'bradleyjoyce',
113
+ :customer_attributes => {
114
+ :first_name => "Wynn",
115
+ :last_name => "Netherland",
116
+ :email => "wynn@example.com"
117
+ }
118
+ }
119
+ subscription = @client.update_subscription(123, options)
120
+ subscription.success?.should == nil
121
+ end
122
+
62
123
  should "create a customer subscription" do
63
124
  stub_post "https://OU812:x@pengwynn.chargify.com/subscriptions.json", "subscription.json"
64
125
  options = {
65
126
  :product_handle => 'monthly',
66
- :customer_reference => 'bradleyjoyce'
127
+ :customer_reference => 'bradleyjoyce',
128
+ :customer_attributes => {
129
+ :first_name => "Wynn",
130
+ :last_name => "Netherland",
131
+ :email => "wynn@example.com"
132
+ }
67
133
  }
68
- customer_attributes = {
69
- :first_name => "Wynn",
70
- :last_name => "Netherland",
71
- :email => "wynn@example.com"
72
- }
73
- subscription = @client.create_subscription(options, customer_attributes)
134
+ subscription = @client.create_subscription(options)
74
135
  subscription.customer.organization.should == 'Squeejee'
75
136
  end
137
+
138
+ should "set success? to true when subscription is created successfully" do
139
+ stub_post "https://OU812:x@pengwynn.chargify.com/subscriptions.json", "subscription.json", 201
140
+ options = {
141
+ :product_handle => 'monthly',
142
+ :customer_reference => 'bradleyjoyce',
143
+ :customer_attributes => {
144
+ :first_name => "Wynn",
145
+ :last_name => "Netherland",
146
+ :email => "wynn@example.com"
147
+ }
148
+ }
149
+ subscription = @client.create_subscription(options)
150
+ subscription.success?.should == true
151
+ end
152
+
153
+ should "set success? to nil when subscription is not created successfully" do
154
+ stub_post "https://OU812:x@pengwynn.chargify.com/subscriptions.json", "subscription.json", 400
155
+ options = {
156
+ :product_handle => 'monthly',
157
+ :customer_reference => 'bradleyjoyce',
158
+ :customer_attributes => {
159
+ :first_name => "Wynn",
160
+ :last_name => "Netherland",
161
+ :email => "wynn@example.com"
162
+ }
163
+ }
164
+ subscription = @client.create_subscription(options)
165
+ subscription.success?.should == nil
166
+ end
167
+
168
+ should "cancel subscription" do
169
+ stub_delete "https://OU812:x@pengwynn.chargify.com/subscriptions/123.json", "deleted_subscription.json", 200
170
+ subscription = @client.cancel_subscription(123)
171
+
172
+ subscription.state.should == "canceled"
173
+ end
174
+
175
+ should "set success? to nil when subscription is not cancelled successfully" do
176
+ stub_delete "https://OU812:x@pengwynn.chargify.com/subscriptions/123.json", "deleted_subscription.json", 500
177
+ subscription = @client.cancel_subscription(123)
178
+
179
+ subscription.success?.should == nil
180
+ end
181
+
182
+ should "set success? to true when subscription is cancelled successfully" do
183
+ stub_delete "https://OU812:x@pengwynn.chargify.com/subscriptions/123.json", "deleted_subscription.json", 200
184
+ subscription = @client.cancel_subscription(123)
185
+
186
+ subscription.success?.should == true
187
+ end
76
188
 
77
189
  should "return a list of products" do
78
190
  stub_get "https://OU812:x@pengwynn.chargify.com/products.json", "products.json"
@@ -93,4 +205,4 @@ class TestChargify < Test::Unit::TestCase
93
205
  end
94
206
 
95
207
  end
96
- end
208
+ end
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chargify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wynn Netherland
8
+ - Nash Kabbara
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
12
 
12
- date: 2009-11-18 00:00:00 -06:00
13
+ date: 2010-01-26 00:00:00 -06:00
13
14
  default_executable:
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
@@ -88,10 +89,14 @@ files:
88
89
  - README.markdown
89
90
  - Rakefile
90
91
  - VERSION
92
+ - changelog.md
93
+ - chargify.gemspec
91
94
  - lib/chargify.rb
92
95
  - lib/chargify/client.rb
93
96
  - test/fixtures/customer.json
94
97
  - test/fixtures/customers.json
98
+ - test/fixtures/deleted_subscription.json
99
+ - test/fixtures/invalid_subscription.json
95
100
  - test/fixtures/new_customer.json
96
101
  - test/fixtures/product.json
97
102
  - test/fixtures/products.json