vitalish-chargify_api_ares 0.3.9

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use ree@chargify_ree
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2009 Grasshopper Group, LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,80 @@
1
+ Chargify API wrapper for Ruby (using ActiveResource)
2
+ ====================================================
3
+
4
+ chargify_api_ares
5
+ -----------------
6
+
7
+ This is a Ruby wrapper for the [Chargify](http://chargify.com) API that leverages ActiveResource.
8
+ It allows you to interface with the Chargify API using simple ActiveRecord-like syntax, i.e.:
9
+
10
+ Chargify::Subscription.create(
11
+ :customer_reference => 'moklett',
12
+ :product_handle => 'chargify-api-ares-test',
13
+ :credit_card_attributes => {
14
+ :first_name => "Michael",
15
+ :last_name => "Klett",
16
+ :expiration_month => 1,
17
+ :expiration_year => 2010,
18
+ :full_number => "1234-1234-1234-1234"
19
+ }
20
+ )
21
+
22
+ subscription.credit_card_attributes = {:expiration_year => 2013}
23
+ subscription.save
24
+
25
+ subscription.cancel
26
+
27
+ See the `samples` directory for more usage examples.
28
+
29
+
30
+ ### Installation
31
+
32
+ This library can be installed as a gem. It is hosted on [Gemcutter](http://gemcutter.org).
33
+
34
+ If you don't have your system set up to use gemcutter, follow the instructions on their site
35
+ <http://gemcutter.org>, i.e.:
36
+
37
+ $ gem install gemcutter
38
+ $ gem tumble
39
+
40
+ This will install Gemcutter and set your gem sources to search the gemcutter repos.
41
+
42
+ Then you can install this library as a gem:
43
+
44
+ $ gem install chargify_api_ares
45
+
46
+
47
+ ### Requirements
48
+
49
+ This library requires ActiveResource version 2.3.4 or greater.
50
+
51
+ $ gem install activeresource
52
+
53
+
54
+ ### Usage
55
+
56
+ Simply require this library before you use it:
57
+
58
+ require 'chargify_api_ares'
59
+
60
+
61
+ If you're using Rails, you could include this gem in your configuration, i.e. in `environment.rb`
62
+
63
+ config.gem 'chargify_api_ares'
64
+
65
+
66
+ Now you'll have access to classes the interact with the Chargify API, such as:
67
+
68
+ `Chargify::Product`
69
+ `Chargify::Customer`
70
+ `Chargifiy::Subscription`
71
+
72
+ Check out the examples in the `samples` directory. If you're not familiar with how ActiveResource works,
73
+ you may be interested in some [ActiveResource Documentation](http://apidock.com/rails/ActiveResource/Base)
74
+
75
+
76
+
77
+ ### Contributors
78
+
79
+ * Michael Klett (Grasshopper Labs and Chargify)
80
+ * The Lab Rats @ Phase Two Labs
@@ -0,0 +1,14 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "chargify_api_ares"
5
+ gemspec.summary = "A Chargify API wrapper for Ruby using ActiveResource"
6
+ gemspec.description = ""
7
+ gemspec.email = "mklett@grasshopper.com"
8
+ gemspec.homepage = "http://github.com/grasshopperlabs/chargify_api_ares"
9
+ gemspec.authors = ["Michael Klett", "The Lab Rats @ Phase Two Labs", "Brian Rose","Nathan Verni"]
10
+ Jeweler::GemcutterTasks.new
11
+ end
12
+ rescue LoadError
13
+ puts "Jeweler not available. Install it with: sudo gem install jeweler"
14
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.9
@@ -0,0 +1,75 @@
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_api_ares}
8
+ s.version = "0.3.9"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael Klett", "Nathan Verni", "The Lab Rats @ Phase Two Labs", "Brian Rose"]
12
+ s.date = %q{2011-3-2}
13
+ s.description = %q{}
14
+ s.email = %q{mklett@grasshopper.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".gitignore",
21
+ "LICENSE.txt",
22
+ "README.md",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "chargify_api_ares.gemspec",
26
+ "config/remote.example.yml",
27
+ "lib/chargify_api_ares.rb",
28
+ "samples/customers.rb",
29
+ "samples/metered_components.rb",
30
+ "samples/products.rb",
31
+ "samples/subscriptions.rb",
32
+ "samples/transactions.rb",
33
+ "spec/base_spec.rb",
34
+ "spec/components_spec.rb",
35
+ "spec/customer_spec.rb",
36
+ "spec/factories.rb",
37
+ "spec/mocks/fake_resource.rb",
38
+ "spec/product_spec.rb",
39
+ "spec/remote/remote_spec.rb",
40
+ "spec/remote/spec_helper.rb",
41
+ "spec/spec.opts",
42
+ "spec/spec_helper.rb",
43
+ "spec/subscription_spec.rb",
44
+ "spec/subscriptions_component_spec.rb"
45
+ ]
46
+ s.homepage = %q{http://github.com/grasshopperlabs/chargify_api_ares}
47
+ s.rdoc_options = ["--charset=UTF-8"]
48
+ s.require_paths = ["lib"]
49
+ s.rubygems_version = %q{1.3.7}
50
+ s.summary = %q{A Chargify API wrapper for Ruby using ActiveResource}
51
+ s.test_files = [
52
+ "spec/base_spec.rb",
53
+ "spec/components_spec.rb",
54
+ "spec/customer_spec.rb",
55
+ "spec/factories.rb",
56
+ "spec/mocks/fake_resource.rb",
57
+ "spec/product_spec.rb",
58
+ "spec/remote/remote_spec.rb",
59
+ "spec/remote/spec_helper.rb",
60
+ "spec/spec_helper.rb",
61
+ "spec/subscription_spec.rb",
62
+ "spec/subscriptions_component_spec.rb"
63
+ ]
64
+
65
+ if s.respond_to? :specification_version then
66
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
67
+ s.specification_version = 3
68
+
69
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
70
+ else
71
+ end
72
+ else
73
+ end
74
+ end
75
+
@@ -0,0 +1,7 @@
1
+ # Copy this file to config/remote.yml and make adjustments as necessary.
2
+ #
3
+ # Note: Remote tests will only work when configured to run on a test site that uses the Bogus gateway.
4
+ # Warning: all data in the site specified by 'subdomain' will be cleared and replaced with test data.
5
+ run_tests: true
6
+ subdomain: yoursubdomain
7
+ api_key: xxx
@@ -0,0 +1,277 @@
1
+ # Chargify API Wrapper using ActiveResource.
2
+ #
3
+ begin
4
+ require 'active_resource'
5
+ rescue LoadError
6
+ begin
7
+ require 'rubygems'
8
+ require 'active_resource'
9
+ rescue LoadError
10
+ abort <<-ERROR
11
+ The 'activeresource' library could not be loaded. If you have RubyGems
12
+ installed you can install ActiveResource by doing "gem install activeresource".
13
+ ERROR
14
+ end
15
+ end
16
+
17
+
18
+ # Version check
19
+ module Chargify
20
+ MIN_VERSION = '2.3.4'
21
+ end
22
+ require 'active_resource/version'
23
+ unless Gem::Version.new(ActiveResource::VERSION::STRING) >= Gem::Version.new(Chargify::MIN_VERSION)
24
+ abort <<-ERROR
25
+ ActiveResource version #{Chargify::MIN_VERSION} or greater is required.
26
+ ERROR
27
+ end
28
+
29
+ # Patch ActiveResource version 2.3.4
30
+ if ActiveResource::VERSION::STRING == '2.3.4'
31
+ module ActiveResource
32
+ class Base
33
+ def save
34
+ save_without_validation
35
+ true
36
+ rescue ResourceInvalid => error
37
+ case error.response['Content-Type']
38
+ when /application\/xml/
39
+ errors.from_xml(error.response.body)
40
+ when /application\/json/
41
+ errors.from_json(error.response.body)
42
+ end
43
+ false
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+
50
+ module Chargify
51
+
52
+ class << self
53
+ attr_accessor :subdomain, :api_key, :site, :format, :timeout
54
+
55
+ def configure
56
+ yield self
57
+
58
+ Base.user = api_key
59
+ Base.password = 'X'
60
+ Base.timeout = timeout unless (timeout.blank?)
61
+
62
+ self.site ||= "https://#{subdomain}.chargify.com"
63
+
64
+ Base.site = site
65
+ Subscription::Component.site = site + "/subscriptions/:subscription_id"
66
+ Subscription::Statement.site = site + "/subscriptions/:subscription_id"
67
+ Subscription::Transaction.site = site + "/subscriptions/:subscription_id"
68
+ end
69
+ end
70
+
71
+ class Base < ActiveResource::Base
72
+ def self.element_name
73
+ name.split(/::/).last.underscore
74
+ end
75
+
76
+ def to_xml(options = {})
77
+ options.merge!(:dasherize => false)
78
+ super
79
+ end
80
+ end
81
+
82
+ class Site < Base
83
+ def self.clear_data!(params = {})
84
+ post(:clear_data, params)
85
+ end
86
+ end
87
+
88
+ class Customer < Base
89
+ def self.find_by_reference(reference)
90
+ Customer.new get(:lookup, :reference => reference)
91
+ end
92
+
93
+ def subscriptions(params = {})
94
+ params.merge!({:customer_id => self.id})
95
+ Subscription.find(:all, :params => params)
96
+ end
97
+
98
+ def payment_profiles(params = {})
99
+ params.merge!({:customer_id => self.id})
100
+ PaymentProfile.find(:all, :params => params)
101
+ end
102
+ end
103
+
104
+ class Subscription < Base
105
+ def self.find_by_customer_reference(reference)
106
+ customer = Customer.find_by_reference(reference)
107
+ find(:first, :params => {:customer_id => customer.id})
108
+ end
109
+
110
+ # Strip off nested attributes of associations before saving, or type-mismatch errors will occur
111
+ def save
112
+ self.attributes.delete('customer')
113
+ self.attributes.delete('product')
114
+ self.attributes.delete('credit_card')
115
+ super
116
+ end
117
+
118
+ def cancel
119
+ destroy
120
+ end
121
+
122
+ def component(id)
123
+ Component.find(id, :params => {:subscription_id => self.id})
124
+ end
125
+
126
+ def components(params = {})
127
+ params.merge!({:subscription_id => self.id})
128
+ Component.find(:all, :params => params)
129
+ end
130
+
131
+ def payment_profile
132
+ credit_card
133
+ end
134
+
135
+ # Perform a one-time charge on an existing subscription.
136
+ # For more information, please see the one-time charge API docs available
137
+ # at: http://support.chargify.com/faqs/api/api-charges
138
+ def charge(attrs = {})
139
+ post :charges, {}, attrs.to_xml(:root => :charge)
140
+ end
141
+
142
+ def credit(attrs = {})
143
+ post :credits, {}, attrs.to_xml(:root => :credit)
144
+ end
145
+
146
+ def refund(attrs = {})
147
+ post :refunds, {}, attrs.to_xml(:root => :refund)
148
+ end
149
+
150
+ def reactivate(params = {})
151
+ put :reactivate, params
152
+ end
153
+
154
+ def reset_balance
155
+ put :reset_balance
156
+ end
157
+
158
+ def migrate(attrs = {})
159
+ post :migrations, :migration => attrs
160
+ end
161
+
162
+ def statement(id)
163
+ statement = Chargify::Statement.find(id)
164
+ raise ActiveResource::ResourceNotFound.new(nil) if (statement.subscription_id != self.id)
165
+ statement
166
+ end
167
+
168
+ def statements(params = {})
169
+ params.merge!(:subscription_id => self.id)
170
+ Statement.find(:all, :params => params)
171
+ end
172
+
173
+ def transactions(params = {})
174
+ params.merge!(:subscription_id => self.id)
175
+ Transaction.find(:all, :params => params)
176
+ end
177
+
178
+ class Component < Base
179
+ # All Subscription Components are considered already existing records, but the id isn't used
180
+ def id
181
+ self.component_id
182
+ end
183
+
184
+ def create_usage(attrs = {})
185
+ post :usages, {}, attrs.to_xml(:root => :usage)
186
+ end
187
+
188
+ def usages(attrs = {})
189
+ get :usages
190
+ end
191
+ end
192
+
193
+ class Statement < Base
194
+ end
195
+
196
+ class Transaction < Base
197
+ def full_refund(attrs = {})
198
+ return false if self.transaction_type != 'payment'
199
+
200
+ attrs.merge!(:amount_in_cents => self.amount_in_cents)
201
+ self.refund(attrs)
202
+ end
203
+
204
+ def refund(attrs = {})
205
+ return false if self.transaction_type != 'payment'
206
+
207
+ attrs.merge!(:payment_id => self.id)
208
+ Subscription.find(self.prefix_options[:subscription_id]).refund(attrs)
209
+ end
210
+ end
211
+ end
212
+
213
+ class Product < Base
214
+ def self.find_by_handle(handle)
215
+ Product.new get(:lookup, :handle => handle)
216
+ end
217
+
218
+ protected
219
+
220
+ # Products are created in the scope of a ProductFamily, i.e. /product_families/nnn/products
221
+ #
222
+ # This alters the collection path such that it uses the product_family_id that is set on the
223
+ # attributes.
224
+ def create
225
+ pfid = begin
226
+ self.product_family_id
227
+ rescue NoMethodError
228
+ 0
229
+ end
230
+ connection.post("/product_families/#{pfid}/products.#{self.class.format.extension}", encode, self.class.headers).tap do |response|
231
+ self.id = id_from_response(response)
232
+ load_attributes_from_response(response)
233
+ end
234
+ end
235
+ end
236
+
237
+ class ProductFamily < Base
238
+ def self.find_by_handle(handle, attributes = {})
239
+ ProductFamily.find(:one, :from => :lookup, :handle => handle)
240
+ end
241
+ end
242
+
243
+ class Usage < Base
244
+ def subscription_id=(i)
245
+ self.prefix_options[:subscription_id] = i
246
+ end
247
+ def component_id=(i)
248
+ self.prefix_options[:component_id] = i
249
+ end
250
+ end
251
+
252
+ class Component < Base
253
+ end
254
+
255
+ class Statement < Base
256
+ end
257
+
258
+ class Transaction < Base
259
+ def full_refund(attrs = {})
260
+ return false if self.transaction_type != 'payment'
261
+
262
+ attrs.merge!(:amount_in_cents => self.amount_in_cents)
263
+ self.refund(attrs)
264
+ end
265
+
266
+ def refund(attrs = {})
267
+ return false if self.transaction_type != 'payment'
268
+
269
+ attrs.merge!(:payment_id => self.id)
270
+ Subscription.find(self.subscription_id).refund(attrs)
271
+ end
272
+ end
273
+
274
+ class PaymentProfile < Base
275
+ end
276
+
277
+ end