vitalish-chargify_api_ares 0.3.9

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.
@@ -0,0 +1,51 @@
1
+ $: << File.expand_path(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'chargify_api_ares'
4
+
5
+ # You could load your credentials from a file...
6
+ chargify_config = YAML::load_file(File.join(File.dirname(__FILE__), '..', 'config', 'chargify.yml'))
7
+
8
+ Chargify.configure do |c|
9
+ c.subdomain = chargify_config['subdomain']
10
+ c.api_key = chargify_config['api_key']
11
+ end
12
+
13
+
14
+ # Retrieve a list of all your customers
15
+ Chargify::Customer.find(:all)
16
+ # => [#<Chargify::Customer:0x102d0cef8 @prefix_options={}, @attributes={"reference"=>"moklett", "updated_at"=>Mon Nov 16 23:19:25 UTC 2009, "id"=>325, "first_name"=>"Michael", "organization"=>"Chargify", "last_name"=>"Klett", "email"=>"moklett@example.com", "created_at"=>Mon Nov 16 23:19:25 UTC 2009}>]
17
+
18
+
19
+ customer = Chargify::Customer.find(325)
20
+
21
+ customer.first_name
22
+ # => Michael
23
+
24
+ customer.last_name
25
+ # => Klett
26
+
27
+ # Update a customer - success!
28
+ customer.first_name = "Miguel"
29
+ customer.save
30
+ # => true
31
+
32
+ customer.first_name
33
+ # => Miguel
34
+
35
+ # Update a customer - fail!
36
+ customer.first_name = ""
37
+ customer.save
38
+ # => false
39
+
40
+ customer.errors.full_messages.inspect
41
+ # => ["First name: cannot be blank."]
42
+
43
+
44
+ # Create a new customer - success!
45
+ Chargify::Customer.create(
46
+ :first_name => "Charlie",
47
+ :last_name => "Bull",
48
+ :email => "charlie@example.com",
49
+ :organization => "Chargify"
50
+ )
51
+ # => #<Chargify::Customer:0x102c27970 @prefix_options={}, @attributes={"reference"=>nil, "updated_at"=>Mon Nov 16 23:43:33 UTC 2009, "id"=>327, "organization"=>"Chargify", "first_name"=>"Charlie", "last_name"=>"Bull", "created_at"=>Mon Nov 16 23:43:33 UTC 2009, "email"=>"charlie@example.com"}>
@@ -0,0 +1,35 @@
1
+ $: << File.expand_path(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'chargify_api_ares'
4
+
5
+ # You could load your credentials from a file...
6
+ chargify_config = YAML::load_file(File.join(File.dirname(__FILE__), '..', 'config', 'chargify.yml'))
7
+
8
+ Chargify.configure do |c|
9
+ c.subdomain = chargify_config['subdomain']
10
+ c.api_key = chargify_config['api_key']
11
+ if chargify_config['site']
12
+ c.site = chargify_config['site']
13
+ end
14
+ end
15
+
16
+ #
17
+ # This assumes you have a product family with a metered component setup
18
+ #
19
+ product_family = Chargify::ProductFamily.find(:first)
20
+ component = Chargify::Component.find(:first, :params => {:product_family_id => product_family.id})
21
+ subscription = Chargify::Subscription.find(:first)
22
+
23
+
24
+ u = Chargify::Usage.new
25
+ u.subscription_id = subscription.id
26
+ u.component_id = component.id
27
+ u.quantity = 5
28
+ d = DateTime.now.to_s
29
+ u.memo = d
30
+ puts d
31
+ u.save
32
+
33
+
34
+ x = Chargify::Usage.find(:last, :params => {:subscription_id => subscription.id, :component_id => component.id})
35
+ puts x.memo == d
@@ -0,0 +1,24 @@
1
+ $: << File.expand_path(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'chargify_api_ares'
4
+
5
+ # You could load your credentials from a file...
6
+ chargify_config = YAML::load_file(File.join(File.dirname(__FILE__), '..', 'config', 'chargify.yml'))
7
+
8
+ Chargify.configure do |c|
9
+ c.subdomain = chargify_config['subdomain']
10
+ c.api_key = chargify_config['api_key']
11
+ end
12
+
13
+
14
+ # Retrieve a list of all your products
15
+ products = Chargify::Product.find(:all)
16
+ # => [#<Chargify::Product:0x102cdcac8 @prefix_options={}, @attributes={"name"=>"Chargify API Ares Test", "price_in_cents"=>0, "handle"=>"chargify-api-ares-test", "product_family"=>#<Chargify::Product::ProductFamily:0x102cdbad8 @prefix_options={}, @attributes={"name"=>"Chargify API ARes Test", "handle"=>"chargify-api-ares-test", "id"=>78, "accounting_code"=>nil}>, "id"=>152, "accounting_code"=>nil, "interval_unit"=>"month", "interval"=>1}>]
17
+
18
+ # Find a single product by id
19
+ product = Chargify::Product.find(products.first.id)
20
+ # => #<Chargify::Product:0x102ce7540 @prefix_options={}, @attributes={"price_in_cents"=>0, "name"=>"Chargify API Ares Test", "handle"=>"chargify-api-ares-test", "product_family"=>#<Chargify::Product::ProductFamily:0x102ce6ca8 @prefix_options={}, @attributes={"name"=>"Chargify API ARes Test", "handle"=>"chargify-api-ares-test", "id"=>78, "accounting_code"=>nil}>, "id"=>152, "accounting_code"=>nil, "interval_unit"=>"month", "interval"=>1}>
21
+
22
+ # Find a single product by its handle
23
+ product = Chargify::Product.find_by_handle(products.first.handle)
24
+ # => #<Chargify::Product:0x102c7a828 @prefix_options={}, @attributes={"price_in_cents"=>0, "name"=>"Chargify API Ares Test", "handle"=>"chargify-api-ares-test", "product_family"=>#<Chargify::Product::ProductFamily:0x102c798b0 @prefix_options={}, @attributes={"name"=>"Chargify API ARes Test", "handle"=>"chargify-api-ares-test", "id"=>78, "accounting_code"=>nil}>, "id"=>152, "accounting_code"=>nil, "interval_unit"=>"month", "interval"=>1}>
@@ -0,0 +1,53 @@
1
+ $: << File.expand_path(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'chargify_api_ares'
4
+
5
+ # You could load your credentials from a file...
6
+ chargify_config = YAML::load_file(File.join(File.dirname(__FILE__), '..', 'config', 'chargify.yml'))
7
+
8
+ Chargify.configure do |c|
9
+ c.subdomain = chargify_config['subdomain']
10
+ c.api_key = chargify_config['api_key']
11
+ end
12
+
13
+
14
+ # Retrieve a list of all your customers
15
+ subscription = Chargify::Subscription.find(:all)
16
+ # => [#<Chargify::Subscription:0x1020fff70 @prefix_options={}, @attributes={"cancellation_message"=>nil, "activated_at"=>Tue Nov 17 15:51:42 UTC 2009, "expires_at"=>nil, "updated_at"=>Tue Nov 17 15:51:41 UTC 2009, "credit_card"=>#<Chargify::Subscription::CreditCard:0x1020f24d8 @prefix_options={}, @attributes={"card_type"=>"bogus", "expiration_year"=>2015, "masked_card_number"=>"XXXX-XXXX-XXXX-2", "first_name"=>"Michael", "expiration_month"=>1, "last_name"=>"Klett"}>, "product"=>#<Chargify::Product:0x1020f5a70 @prefix_options={}, @attributes={"price_in_cents"=>0, "name"=>"Chargify API Ares Test", "handle"=>"chargify-api-ares-test", "product_family"=>#<Chargify::Product::ProductFamily:0x1020f48f0 @prefix_options={}, @attributes={"name"=>"Chargify API ARes Test", "handle"=>"chargify-api-ares-test", "id"=>79, "accounting_code"=>nil}>, "id"=>153, "accounting_code"=>nil, "interval_unit"=>"month", "interval"=>1}>, "trial_ended_at"=>nil, "id"=>328, "current_period_ends_at"=>Thu Dec 17 15:51:41 UTC 2009, "trial_started_at"=>nil, "customer"=>#<Chargify::Customer:0x1020f6d80 @prefix_options={}, @attributes={"reference"=>"moklett", "updated_at"=>Tue Nov 17 15:51:02 UTC 2009, "id"=>331, "first_name"=>"Michael", "organization"=>"Chargify", "last_name"=>"Klett", "email"=>"moklett@example.com", "created_at"=>Tue Nov 17 15:51:02 UTC 2009}>, "balance_in_cents"=>0, "current_period_started_at"=>Tue Nov 17 15:51:41 UTC 2009, "state"=>"canceled", "created_at"=>Tue Nov 17 15:51:41 UTC 2009}>]]
17
+
18
+
19
+ # Create a subscription from a customer reference
20
+ subscription = Chargify::Subscription.create(
21
+ :customer_reference => 'moklett',
22
+ :product_handle => 'chargify-api-ares-test',
23
+ :credit_card_attributes => {
24
+ :first_name => "Michael",
25
+ :last_name => "Klett",
26
+ :expiration_month => 1,
27
+ :expiration_year => 2020,
28
+ :full_number => "1"
29
+ }
30
+ )
31
+ # => #<Chargify::Subscription:0x1020ed4b0 @prefix_options={}, @attributes={"cancellation_message"=>nil, "activated_at"=>Tue Nov 17 16:00:17 UTC 2009, "expires_at"=>nil, "updated_at"=>Tue Nov 17 16:00:17 UTC 2009, "credit_card"=>#<Chargify::Subscription::CreditCard:0x102046b10 @prefix_options={}, @attributes={"card_type"=>"bogus", "expiration_year"=>2020, "masked_card_number"=>"XXXX-XXXX-XXXX-1", "first_name"=>"Michael", "expiration_month"=>1, "last_name"=>"Klett"}>, "product"=>#<Chargify::Product:0x10204a2d8 @prefix_options={}, @attributes={"price_in_cents"=>0, "name"=>"Chargify API Ares Test", "handle"=>"chargify-api-ares-test", "product_family"=>#<Chargify::Product::ProductFamily:0x1020490b8 @prefix_options={}, @attributes={"name"=>"Chargify API ARes Test", "handle"=>"chargify-api-ares-test", "id"=>79, "accounting_code"=>nil}>, "id"=>153, "accounting_code"=>nil, "interval_unit"=>"month", "interval"=>1}>, "credit_card_attributes"=>#<Chargify::Subscription::CreditCardAttributes:0x1020ecab0 @prefix_options={}, @attributes={"expiration_year"=>2020, "full_number"=>"1", "first_name"=>"Michael", "expiration_month"=>1, "last_name"=>"Klett"}>, "trial_ended_at"=>nil, "id"=>331, "current_period_ends_at"=>Thu Dec 17 16:00:17 UTC 2009, "product_handle"=>"chargify-api-ares-test", "trial_started_at"=>nil, "customer"=>#<Chargify::Customer:0x10204b688 @prefix_options={}, @attributes={"reference"=>"moklett", "updated_at"=>Tue Nov 17 15:51:02 UTC 2009, "id"=>331, "first_name"=>"Michael", "organization"=>"Chargify", "last_name"=>"Klett", "email"=>"moklett@example.com", "created_at"=>Tue Nov 17 15:51:02 UTC 2009}>, "balance_in_cents"=>0, "current_period_started_at"=>Tue Nov 17 16:00:17 UTC 2009, "state"=>"active", "created_at"=>Tue Nov 17 16:00:17 UTC 2009, "customer_reference"=>"moklett"}>
32
+
33
+
34
+ # Lookup up existing Subscription using the Customer's reference
35
+ Subscription.find_by_customer_reference('moklett')
36
+ # => #<Chargify::Subscription:0x1020ed4b0 @prefix_options={}, @attributes={"cancellation_message"=>nil, "activated_at"=>Tue Nov 17 16:00:17 UTC 2009, "expires_at"=>nil, "updated_at"=>Tue Nov 17 16:00:17 UTC 2009, "credit_card"=>#<Chargify::Subscription::CreditCard:0x102046b10 @prefix_options={}, @attributes={"card_type"=>"bogus", "expiration_year"=>2020, "masked_card_number"=>"XXXX-XXXX-XXXX-1", "first_name"=>"Michael", "expiration_month"=>1, "last_name"=>"Klett"}>, "product"=>#<Chargify::Product:0x10204a2d8 @prefix_options={}, @attributes={"price_in_cents"=>0, "name"=>"Chargify API Ares Test", "handle"=>"chargify-api-ares-test", "product_family"=>#<Chargify::Product::ProductFamily:0x1020490b8 @prefix_options={}, @attributes={"name"=>"Chargify API ARes Test", "handle"=>"chargify-api-ares-test", "id"=>79, "accounting_code"=>nil}>, "id"=>153, "accounting_code"=>nil, "interval_unit"=>"month", "interval"=>1}>, "trial_ended_at"=>nil, "id"=>331, "current_period_ends_at"=>Thu Dec 17 16:00:17 UTC 2009, "product_handle"=>"chargify-api-ares-test", "trial_started_at"=>nil, "customer"=>#<Chargify::Customer:0x10204b688 @prefix_options={}, @attributes={"reference"=>"moklett", "updated_at"=>Tue Nov 17 15:51:02 UTC 2009, "id"=>331, "first_name"=>"Michael", "organization"=>"Chargify", "last_name"=>"Klett", "email"=>"moklett@example.com", "created_at"=>Tue Nov 17 15:51:02 UTC 2009}>, "balance_in_cents"=>0, "current_period_started_at"=>Tue Nov 17 16:00:17 UTC 2009, "state"=>"active", "created_at"=>Tue Nov 17 16:00:17 UTC 2009, "customer_reference"=>"moklett"}>
37
+
38
+
39
+ # Update credit card information
40
+ subscription.credit_card_attributes = {:full_number => "2", :expiration_year => "2015"}
41
+ subscription.save
42
+ # => #<Chargify::Subscription:0x1020ed4b0 @prefix_options={}, @attributes={"cancellation_message"=>nil, "activated_at"=>Tue Nov 17 16:00:17 UTC 2009, "expires_at"=>nil, "updated_at"=>Tue Nov 17 16:00:17 UTC 2009, "credit_card"=>#<Chargify::Subscription::CreditCard:0x1023ba878 @prefix_options={}, @attributes={"card_type"=>"bogus", "expiration_year"=>2015, "masked_card_number"=>"XXXX-XXXX-XXXX-2", "first_name"=>"Michael", "expiration_month"=>1, "last_name"=>"Klett"}>, "product"=>#<Chargify::Product:0x1023baa80 @prefix_options={}, @attributes={"price_in_cents"=>0, "name"=>"Chargify API Ares Test", "handle"=>"chargify-api-ares-test", "product_family"=>#<Chargify::Product::ProductFamily:0x1023c04d0 @prefix_options={}, @attributes={"name"=>"Chargify API ARes Test", "handle"=>"chargify-api-ares-test", "id"=>79, "accounting_code"=>nil}>, "id"=>153, "accounting_code"=>nil, "interval_unit"=>"month", "interval"=>1}>, "credit_card_attributes"=>{:full_number=>"2", :expiration_year=>"2015"}, "trial_ended_at"=>nil, "id"=>331, "current_period_ends_at"=>Thu Dec 17 16:00:17 UTC 2009, "product_handle"=>"chargify-api-ares-test", "customer"=>#<Chargify::Customer:0x1023bae40 @prefix_options={}, @attributes={"reference"=>"moklett", "updated_at"=>Tue Nov 17 15:51:02 UTC 2009, "id"=>331, "first_name"=>"Michael", "organization"=>"Chargify", "last_name"=>"Klett", "email"=>"moklett@example.com", "created_at"=>Tue Nov 17 15:51:02 UTC 2009}>, "trial_started_at"=>nil, "balance_in_cents"=>0, "current_period_started_at"=>Tue Nov 17 16:00:17 UTC 2009, "state"=>"active", "created_at"=>Tue Nov 17 16:00:17 UTC 2009, "customer_reference"=>"moklett"}>
43
+
44
+
45
+ # Perform a one-time charge against an existing subscription
46
+ subscription.charge(:amount => 10.00, :memo => 'Extra service')
47
+ # => #<Net::HTTPCreated>
48
+
49
+
50
+ # Cancel a subscription
51
+ subscription.cancel
52
+ subscription.reload
53
+ # => #<Chargify::Subscription:0x1020ed4b0 @prefix_options={}, @attributes={"cancellation_message"=>nil, "activated_at"=>Tue Nov 17 16:00:17 UTC 2009, "expires_at"=>nil, "updated_at"=>Tue Nov 17 16:00:17 UTC 2009, "credit_card"=>#<Chargify::Subscription::CreditCard:0x10234f168 @prefix_options={}, @attributes={"card_type"=>"bogus", "expiration_year"=>2015, "masked_card_number"=>"XXXX-XXXX-XXXX-2", "first_name"=>"Michael", "expiration_month"=>1, "last_name"=>"Klett"}>, "product"=>#<Chargify::Product:0x10234f370 @prefix_options={}, @attributes={"price_in_cents"=>0, "name"=>"Chargify API Ares Test", "handle"=>"chargify-api-ares-test", "product_family"=>#<Chargify::Product::ProductFamily:0x102354708 @prefix_options={}, @attributes={"name"=>"Chargify API ARes Test", "handle"=>"chargify-api-ares-test", "id"=>79, "accounting_code"=>nil}>, "id"=>153, "accounting_code"=>nil, "interval_unit"=>"month", "interval"=>1}>, "credit_card_attributes"=>{:full_number=>"2", :expiration_year=>"2015"}, "trial_ended_at"=>nil, "id"=>331, "current_period_ends_at"=>Thu Dec 17 16:00:17 UTC 2009, "product_handle"=>"chargify-api-ares-test", "customer"=>#<Chargify::Customer:0x10234f730 @prefix_options={}, @attributes={"reference"=>"moklett", "updated_at"=>Tue Nov 17 15:51:02 UTC 2009, "id"=>331, "first_name"=>"Michael", "organization"=>"Chargify", "last_name"=>"Klett", "email"=>"moklett@example.com", "created_at"=>Tue Nov 17 15:51:02 UTC 2009}>, "trial_started_at"=>nil, "balance_in_cents"=>0, "current_period_started_at"=>Tue Nov 17 16:00:17 UTC 2009, "state"=>"canceled", "created_at"=>Tue Nov 17 16:00:17 UTC 2009, "customer_reference"=>"moklett"}>
@@ -0,0 +1,17 @@
1
+ $: << File.expand_path(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'chargify_api_ares'
4
+
5
+ # You could load your credentials from a file...
6
+ chargify_config = YAML::load_file(File.join(File.dirname(__FILE__), '..', 'config', 'chargify.yml'))
7
+
8
+ Chargify.configure do |c|
9
+ c.subdomain = chargify_config['subdomain']
10
+ c.api_key = chargify_config['api_key']
11
+ end
12
+
13
+
14
+ # Retrieve a list of all your customers
15
+ subscription = Chargify::Subscription.find(:all).first
16
+
17
+ transactions = subscription.transactions
@@ -0,0 +1,10 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Chargify::Base do
4
+
5
+ it 'parses element names' do
6
+ Chargify::Base.stub!(:name).and_return("Test::Namespace::ElementName")
7
+ Chargify::Base.element_name.should eql('element_name')
8
+ end
9
+
10
+ end
@@ -0,0 +1,48 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Chargify::Component do
4
+ describe "Recording usage" do
5
+ before do
6
+ @subscription = Factory(:subscription)
7
+ @component = Factory(:component)
8
+ @now = DateTime.now.to_s
9
+ end
10
+
11
+ it "should create a usage record" do
12
+ u = Chargify::Usage.new
13
+ u.subscription_id = @subscription.id
14
+ u.component_id = @component.id
15
+ u.quantity = 5
16
+ u.memo = @now
17
+ u.save
18
+
19
+ component = Chargify::Usage.find(:last, :params => {:subscription_id => @subscription.id, :component_id => @component.id})
20
+ component.memo.should == @now
21
+ component.quantity.should == 5
22
+ end
23
+ end
24
+
25
+ describe "Listing usages" do
26
+ before do
27
+ @subscription = Factory(:subscription)
28
+ @component = Factory(:component)
29
+ @now = DateTime.now.to_s
30
+ create_usage
31
+ end
32
+
33
+ it "should return all usages for a component and subscription" do
34
+ component = Chargify::Usage.find(:last, :params => {:subscription_id => @subscription.id, :component_id => @component.id})
35
+ component.quantity.should == 5
36
+ end
37
+ end
38
+
39
+ def create_usage
40
+ u = Chargify::Usage.new
41
+ u.subscription_id = @subscription.id
42
+ u.component_id = @component.id
43
+ u.quantity = 5
44
+ u.memo = @now
45
+ u.save
46
+ end
47
+ end
48
+
@@ -0,0 +1,23 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Chargify::Customer do
4
+
5
+ context 'find by reference' do
6
+ before do
7
+ @reference = 'ref0123'
8
+ @existing_customer = Factory(:customer, :reference => @reference, :id => Factory.next(:customer_id))
9
+ FakeWeb.register_uri(:get, "#{test_domain}/customers/lookup.xml?reference=#{@existing_customer.reference}", :body => @existing_customer.attributes.to_xml)
10
+ end
11
+
12
+ it 'finds the correct customer by reference' do
13
+ customer = Chargify::Customer.find_by_reference(@reference)
14
+ customer.should eql(@existing_customer)
15
+ end
16
+
17
+ it 'is an instance of Chargify::Customer' do
18
+ customer = Chargify::Customer.find_by_reference(@reference)
19
+ customer.should be_instance_of(Chargify::Customer)
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,62 @@
1
+ Factory.sequence :email do |n|
2
+ "customer#{n}@example.com"
3
+ end
4
+
5
+ Factory.sequence :customer_id do |n|
6
+ n
7
+ end
8
+
9
+ Factory.define :customer, :class => Chargify::Customer do |c|
10
+ c.first_name { Faker::Name.first_name }
11
+ c.last_name { Faker::Name.last_name }
12
+ c.email { Factory.next(:email) }
13
+ c.organization { Faker::Company.name }
14
+ c.created_at { 2.days.ago }
15
+ c.updated_at { 1.hour.ago }
16
+ end
17
+
18
+
19
+ Factory.sequence :product_id do |n|
20
+ n
21
+ end
22
+
23
+ Factory.sequence :product_name do |n|
24
+ "Product #{n}"
25
+ end
26
+
27
+ Factory.define :product, :class => Chargify::Product do |p|
28
+ p.name { Factory.next(:product_name) }
29
+ end
30
+
31
+ Factory.sequence :subscription_id do |n|
32
+ n
33
+ end
34
+
35
+ Factory.define :subscription, :class => Chargify::Subscription do |s|
36
+ s.balance_in_cents 500
37
+ s.current_period_ends_at 3.days.from_now
38
+ end
39
+
40
+ Factory.define :subscription_with_extra_attrs, :parent => :subscription do |swea|
41
+ swea.customer Chargify::Customer.new
42
+ swea.product Chargify::Product.new
43
+ swea.credit_card "CREDIT CARD"
44
+ end
45
+
46
+ Factory.define :component, :class => Chargify::Component do |f|
47
+ f.name { Faker::Company.bs }
48
+ f.unit_name 'unit'
49
+ end
50
+
51
+ Factory.define :quantity_based_component, :class => Chargify::Component do |f|
52
+ f.name { Faker::Company.bs }
53
+ f.unit_name 'unit'
54
+ f.pricing_scheme 'tiered'
55
+ f.component_type 'quantity_based_component'
56
+ end
57
+
58
+ Factory.define :subscriptions_component, :class => Chargify::Subscription::Component do |f|
59
+ f.name { Faker::Company.bs }
60
+ f.unit_name 'unit'
61
+ f.component_type 'quantity_based_component'
62
+ end
@@ -0,0 +1,82 @@
1
+ # Taken from https://gist.github.com/238158/487a411c392e1fb2a0c00347e32444320f5cdd49
2
+ require 'FakeWeb'
3
+
4
+ module ActiveResource
5
+
6
+ #
7
+ # The FakeResource fakes ActiveResources so that no real resources are transferred. It catches the creation methods
8
+ # and stores the resources internally instead of sending to a remote service and responds these resources back on
9
+ # request.
10
+ #
11
+ # Additionally it adds a save! method and can be used in conjunction with Cucumber/Pickle/FactoryGirl to fully
12
+ # fake a back end service in the BDD cycle
13
+ #
14
+ module FakeResource
15
+
16
+ @@fake_resources = []
17
+
18
+ def self.clean
19
+ FakeWeb.clean_registry
20
+ @@fake_resources = []
21
+ end
22
+
23
+ def self.included(base)
24
+ base.class_eval do
25
+
26
+ def save
27
+ @@fake_resources << self
28
+ update_fake_responses
29
+ end
30
+
31
+ def destroy
32
+ @@fake_resources.delete(self)
33
+ update_fake_responses
34
+ end
35
+
36
+ def self.delete(id, options = {})
37
+ puts "delete"
38
+ @@fake_resources.delete_if {|r| r.id == id }
39
+ #update_fake_responses
40
+ end
41
+
42
+ def self.exists?(id, options = {})
43
+ not @@fake_resources.select {|r| r.id == id}.blank?
44
+ end
45
+
46
+ end
47
+ end
48
+
49
+ def save!
50
+ save
51
+ end
52
+
53
+ def save
54
+ super
55
+ end
56
+
57
+ private
58
+
59
+ def update_fake_responses
60
+ FakeWeb.clean_registry
61
+
62
+ @@fake_resources.each do |r|
63
+ FakeWeb.register_uri(:get, element_uri, :body => r.to_xml)
64
+ end
65
+
66
+ FakeWeb.register_uri(:get, collection_uri, :body => @@fake_resources.to_xml)
67
+ end
68
+
69
+ def element_uri
70
+ "#{base_uri}#{element_path}"
71
+ end
72
+
73
+ def collection_uri
74
+ "#{base_uri}#{collection_path}"
75
+ end
76
+
77
+ def base_uri
78
+ "#{connection.site.scheme}://#{connection.user}:#{connection.password}@#{connection.site.host}:#{connection.site.port}"
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Chargify::Product do
4
+
5
+ context 'find by handle' do
6
+ before do
7
+ @handle = 'handle1'
8
+ @existing_product = Factory(:product, :handle => @handle, :id => Factory.next(:product_id))
9
+ FakeWeb.register_uri(:get, "#{test_domain}/products/lookup.xml?handle=#{@existing_product.handle}", :body => @existing_product.attributes.to_xml)
10
+ end
11
+
12
+ it 'finds the correct product by handle' do
13
+ product = Chargify::Product.find_by_handle(@handle)
14
+ product.should eql(@existing_product)
15
+ end
16
+
17
+ it 'is an instance of Chargify::Product' do
18
+ product = Chargify::Product.find_by_handle(@handle)
19
+ product.should be_instance_of(Chargify::Product)
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,514 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ if run_remote_tests?
4
+ describe "Remote" do
5
+ before(:all) do
6
+ clear_site_data
7
+ setup_plans
8
+ setup_customer
9
+ end
10
+
11
+ describe "creating a new subscription to a product with a trial" do
12
+ context "when providing valid attributes for the customer and the payment profile" do
13
+ before(:each) do
14
+ @subscription = create_once(:subscription) do
15
+ Chargify::Subscription.create(
16
+ :product_handle => @@basic_plan.handle,
17
+ :customer_attributes => valid_customer_attributes,
18
+ :payment_profile_attributes => good_payment_profile_attributes
19
+ )
20
+ end
21
+ end
22
+
23
+ it "successfully creates the subscription" do
24
+ @subscription.should be_a(Chargify::Subscription)
25
+ end
26
+
27
+ it "sets the current_period_started_at attribute to now" do
28
+ @subscription.current_period_started_at.utc.should be_close(now.utc, approximately)
29
+ end
30
+
31
+ it "sets the current_period_ends_at attribute to 1 month from now" do
32
+ @subscription.current_period_ends_at.utc.should be_close(one_month_from_now.utc, approximately)
33
+ end
34
+
35
+ it "is in the trialing state" do
36
+ @subscription.state.should == 'trialing'
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "creating a new subscription to a product without a trial" do
42
+ context "when providing an existing customer reference and valid payment profile attributes" do
43
+ before(:each) do
44
+ @subscription = create_once(:subscription) do
45
+ Chargify::Subscription.create(
46
+ :product_handle => @@pro_plan.handle,
47
+ :customer_reference => @@johnadoe.reference,
48
+ :payment_profile_attributes => good_payment_profile_attributes
49
+ )
50
+ end
51
+ end
52
+
53
+ it "successfully creates the subscription" do
54
+ @subscription.should be_a(Chargify::Subscription)
55
+ end
56
+
57
+ it "sets the current_period_started_at attribute to now" do
58
+ @subscription.current_period_started_at.utc.should be_close(now.utc, approximately)
59
+ end
60
+
61
+ it "sets the current_period_ends_at attribute to 1 month from now" do
62
+ @subscription.current_period_ends_at.utc.should be_close(one_month_from_now.utc, approximately)
63
+ end
64
+
65
+ it "is in the active state" do
66
+ @subscription.state.should == 'active'
67
+ end
68
+
69
+ it "belongs to the existing customer" do
70
+ @subscription.customer.should == @@johnadoe
71
+ end
72
+ end
73
+
74
+ context "when providing an existing customer reference and an existing payment profile" do
75
+ before(:each) do
76
+ @subscription = create_once(:subscription) do
77
+ Chargify::Subscription.create(
78
+ :product_handle => @@pro_plan.handle,
79
+ :customer_reference => @@johnadoe.reference,
80
+ :payment_profile_id => @@johnadoes_credit_card.id.to_s
81
+ )
82
+ end
83
+ end
84
+
85
+ it "successfully creates the subscription" do
86
+ @subscription.should be_a(Chargify::Subscription)
87
+ end
88
+
89
+ it "is in the active state" do
90
+ @subscription.state.should == 'active'
91
+ end
92
+
93
+ it "belongs to the existing customer" do
94
+ @subscription.customer.should == @@johnadoe
95
+ end
96
+
97
+ it "uses the provided credit card" do
98
+ expected_card = Chargify::PaymentProfile.find(@@johnadoes_credit_card.id)
99
+ @subscription.payment_profile.id.should == @@johnadoes_credit_card.id
100
+ @subscription.payment_profile.attributes.should == expected_card.attributes
101
+ end
102
+ end
103
+
104
+ context "when providing valid attributes for the customer and attributes for a credit card that cannot be stored" do
105
+ before(:each) do
106
+ @customer_attributes = valid_customer_attributes.dup
107
+ @subscription = create_once(:subscription) do
108
+ Chargify::Subscription.create(
109
+ :product_handle => @@basic_plan.handle,
110
+ :customer_attributes => @customer_attributes,
111
+ :payment_profile_attributes => unstorable_payment_profile_attributes
112
+ )
113
+ end
114
+ end
115
+
116
+ it "does not create the subscription" do
117
+ @subscription.should_not be_valid
118
+ end
119
+
120
+ it "does not create the customer" do
121
+ lambda {
122
+ Chargify::Customer.find_by_reference(@customer_attributes[:reference])
123
+ }.should raise_error(ActiveResource::ResourceNotFound)
124
+ end
125
+ end
126
+
127
+ end
128
+
129
+ describe "importing a subscription to a product with a trial and a next billing date 10 days from now" do
130
+ context "when giving valid attributes for the customer and the payment profile" do
131
+ before(:each) do
132
+ @subscription = create_once(:subscription) do
133
+ Chargify::Subscription.create(
134
+ :product_handle => @@basic_plan.handle,
135
+ :customer_attributes => valid_customer_attributes,
136
+ :payment_profile_attributes => pretokenized_card_attributes,
137
+ :next_billing_at => ten_days_from_now.utc
138
+ )
139
+ end
140
+ end
141
+
142
+ it "successfully creates the subscription" do
143
+ @subscription.should be_a(Chargify::Subscription)
144
+ end
145
+
146
+ it "sets the current_period_started_at attribute to now" do
147
+ @subscription.current_period_started_at.utc.should be_close(now.utc, approximately)
148
+ end
149
+
150
+ it "sets the current_period_ends_at attribute to 1 month from now" do
151
+ @subscription.current_period_ends_at.utc.should be_close(ten_days_from_now.utc, approximately)
152
+ end
153
+
154
+ it "is in the active state" do
155
+ @subscription.state.should == 'active'
156
+ end
157
+ end
158
+ end
159
+
160
+ describe "creating failed subscriptions" do
161
+ context "due to providing payment profile attribtues for a card that will be declined" do
162
+ before(:each) do
163
+ @customer_attributes = valid_customer_attributes.dup
164
+ @subscription = create_once(:subscription) do
165
+ Chargify::Subscription.create(
166
+ :product_handle => @@pro_plan.handle,
167
+ :customer_attributes => @customer_attributes,
168
+ :payment_profile_attributes => declined_payment_profile_attributes
169
+ )
170
+ end
171
+ end
172
+
173
+ it "does not create the subscription" do
174
+ @subscription.should_not be_valid
175
+ end
176
+
177
+ it "does not create the customer" do
178
+ lambda {
179
+ Chargify::Customer.find_by_reference(@customer_attributes[:reference])
180
+ }.should raise_error(ActiveResource::ResourceNotFound)
181
+ end
182
+ end
183
+ end
184
+
185
+ describe "cancelling a subscription" do
186
+ before(:each) do
187
+ @subscription = create_once(:subscription) do
188
+ Chargify::Subscription.create(
189
+ :product_handle => @@pro_plan.handle,
190
+ :customer_reference => @@johnadoe.reference,
191
+ :payment_profile_attributes => good_payment_profile_attributes
192
+ )
193
+ end
194
+ @subscription.cancel
195
+ end
196
+
197
+ it "is in the canceled state" do
198
+ Chargify::Subscription.find(@subscription.id).state.should == 'canceled'
199
+ end
200
+ end
201
+
202
+ describe "reactivating a subscriptions" do
203
+ before(:each) do
204
+ @subscription = create_once(:subscription) do
205
+ Chargify::Subscription.create(
206
+ :product_handle => @@pro_plan.handle,
207
+ :customer_reference => @@johnadoe.reference,
208
+ :payment_profile_attributes => good_payment_profile_attributes
209
+ )
210
+ end
211
+ @subscription.cancel
212
+ @subscription.reload.state.should == 'canceled'
213
+ @subscription.reactivate
214
+ end
215
+
216
+ it "puts it in the active state" do
217
+ @subscription.reload.state.should == 'active'
218
+ end
219
+ end
220
+
221
+ describe "adding a one time charge" do
222
+ before(:each) do
223
+ @subscription = create_once(:subscription) do
224
+ Chargify::Subscription.create(
225
+ :product_handle => @@pro_plan.handle,
226
+ :customer_reference => @@johnadoe.reference,
227
+ :payment_profile_attributes => good_payment_profile_attributes
228
+ )
229
+ end
230
+ end
231
+ it "creates a charge and payment" do
232
+ lambda{
233
+ @subscription.charge(:amount => 7, :memo => 'One Time Charge')
234
+ }.should change{@subscription.reload.transactions.size}.by(2)
235
+ @subscription.transactions.first.amount_in_cents.should == 700
236
+ end
237
+ end
238
+
239
+ describe "adding a credit" do
240
+ before(:each) do
241
+ @subscription = create_once(:subscription) do
242
+ Chargify::Subscription.create(
243
+ :product_handle => @@pro_plan.handle,
244
+ :customer_reference => @@johnadoe.reference,
245
+ :payment_profile_attributes => good_payment_profile_attributes
246
+ )
247
+ end
248
+ end
249
+
250
+ it "creates a credit" do
251
+ lambda{
252
+ @subscription.credit(:amount => 7, :memo => 'credit')
253
+ }.should change{@subscription.reload.transactions.size}.by(1)
254
+ @subscription.transactions.first.amount_in_cents.should == -700
255
+ end
256
+ end
257
+
258
+ describe "adding a refund" do
259
+ before(:each) do
260
+ @subscription = create_once(:subscription) do
261
+ Chargify::Subscription.create(
262
+ :product_handle => @@pro_plan.handle,
263
+ :customer_reference => @@johnadoe.reference,
264
+ :payment_profile_attributes => good_payment_profile_attributes
265
+ )
266
+ end
267
+
268
+ @subscription.charge(:amount => 7, :memo => 'One Time Charge')
269
+ @subscription.reload
270
+ end
271
+
272
+ it "creates a refund" do
273
+ lambda{
274
+ @subscription.refund :payment_id => @subscription.transactions[0].id, :amount => 7,
275
+ :memo => 'Refunding One Time Charge'
276
+ }.should change{@subscription.reload.transactions.size}.by(1)
277
+ @subscription.transactions.first.amount_in_cents.should == 700
278
+ @subscription.transactions.first.transaction_type.should == 'refund'
279
+ end
280
+
281
+ context "via subscription payment (Chargify::Subscription::Transaction)" do
282
+ before :each do
283
+ @payment = @subscription.transactions.first
284
+ end
285
+
286
+ it "creates a refund" do
287
+ lambda{
288
+ @payment.refund :amount => 7, :memo => 'Refunding One Time Charge'
289
+ }.should change{@subscription.reload.transactions.size}.by(1)
290
+ @subscription.transactions.first.amount_in_cents.should == 700
291
+ @subscription.transactions.first.transaction_type.should == 'refund'
292
+ end
293
+
294
+ it "creates a full refund" do
295
+ lambda{
296
+ @payment.full_refund :memo => 'Refunding One Time Charge'
297
+ }.should change{@subscription.reload.transactions.size}.by(1)
298
+ @subscription.transactions.first.amount_in_cents.should == 700
299
+ @subscription.transactions.first.transaction_type.should == 'refund'
300
+ end
301
+ end
302
+
303
+ context "via site payment (Chargify::Transaction)" do
304
+ before :each do
305
+ @site_payment = Chargify::Transaction.find(:first)
306
+ end
307
+
308
+ it "creates a refund" do
309
+ lambda{
310
+ @site_payment.refund :amount => 7, :memo => 'Refunding One Time Charge'
311
+ }.should change{@subscription.reload.transactions.size}.by(1)
312
+ @subscription.transactions.first.amount_in_cents.should == 700
313
+ @subscription.transactions.first.transaction_type.should == 'refund'
314
+ end
315
+
316
+ it "creates a full refund" do
317
+ lambda{
318
+ @site_payment.full_refund :memo => 'Refunding One Time Charge'
319
+ }.should change{@subscription.reload.transactions.size}.by(1)
320
+ @subscription.transactions.first.amount_in_cents.should == 700
321
+ @subscription.transactions.first.transaction_type.should == 'refund'
322
+ end
323
+ end
324
+ end
325
+
326
+ def already_cleared_site_data?
327
+ @@already_cleared_site_data ||= nil
328
+ @@already_cleared_site_data == true
329
+ end
330
+
331
+ def cleared_site_data!
332
+ @@already_cleared_site_data = true
333
+ end
334
+
335
+ def clear_site_data
336
+ return if already_cleared_site_data?
337
+ begin
338
+ Chargify::Site.clear_data!
339
+ cleared_site_data!
340
+ rescue ActiveResource::ForbiddenAccess
341
+ raise StandardError.new("Remote specs may only be run against a site in test mode")
342
+ end
343
+ end
344
+
345
+ # Create Basic and Pro products in the Acme Projects family
346
+ def setup_plans
347
+ begin
348
+ @@acme_projects ||= Chargify::ProductFamily.find_by_handle('acme-projects')
349
+ rescue ActiveResource::ResourceNotFound
350
+ @@acme_projects = Chargify::ProductFamily.new(
351
+ :name => "Acme Projects"
352
+ )
353
+ result = @@acme_projects.save
354
+ result.should be_true
355
+ end
356
+
357
+ begin
358
+ @@basic_plan ||= Chargify::Product.find_by_handle('basic')
359
+ rescue ActiveResource::ResourceNotFound
360
+ @@basic_plan = Chargify::Product.new(
361
+ :product_family_id => @@acme_projects.id,
362
+ :name => "Basic Plan",
363
+ :handle => "basic",
364
+ :price_in_cents => 1000,
365
+ :interval => 1,
366
+ :interval_unit => 'month',
367
+ :trial_interval => 1,
368
+ :trial_interval_unit => 'month',
369
+ :trial_price_in_cents => 0
370
+ )
371
+ result = @@basic_plan.save
372
+ result.should be_true
373
+ end
374
+
375
+ begin
376
+ @@pro_plan ||= Chargify::Product.find_by_handle('pro')
377
+ rescue ActiveResource::ResourceNotFound
378
+ @@pro_plan = Chargify::Product.new(
379
+ :product_family_id => @@acme_projects.id,
380
+ :name => "Pro Plan",
381
+ :handle => "pro",
382
+ :price_in_cents => 5000,
383
+ :interval => 1,
384
+ :interval_unit => 'month'
385
+ )
386
+ result = @@pro_plan.save
387
+ result.should be_true
388
+ end
389
+ end
390
+
391
+ def setup_customer
392
+ # Create a customer
393
+ begin
394
+ @@johnadoe ||= Chargify::Customer.find_by_reference('a')
395
+ rescue ActiveResource::ResourceNotFound
396
+ @@johnadoe = Chargify::Customer.new(valid_customer_attributes)
397
+ result = @@johnadoe.save
398
+ result.should be_true
399
+
400
+ @@johnadoes_credit_card = Chargify::PaymentProfile.new(
401
+ good_payment_profile_attributes.merge(:customer_id => @@johnadoe.id)
402
+ )
403
+ result = @@johnadoes_credit_card.save
404
+ result.should be_true
405
+ end
406
+ end
407
+
408
+ def now
409
+ Time.now
410
+ end
411
+
412
+ def one_month_from_now
413
+ Time.now + 1.month
414
+ end
415
+
416
+ def ten_days_from_now
417
+ 10.days.from_now
418
+ end
419
+
420
+ # Gives a reasonable range for time comparisons
421
+ def approximately
422
+ @approximately ||= 5.minutes
423
+ end
424
+
425
+ def valid_customer_attributes
426
+ initial = next_customer_initial
427
+ {
428
+ :first_name => "John #{initial.upcase}",
429
+ :last_name => "Doe",
430
+ :email => "john.#{initial}.doe@example.com",
431
+ :reference => initial
432
+ }
433
+ end
434
+
435
+ def good_payment_profile_attributes
436
+ {
437
+ :full_number => '1',
438
+ :expiration_month => '12',
439
+ :expiration_year => Time.now.year + 1
440
+ }
441
+ end
442
+
443
+ def declined_payment_profile_attributes
444
+ {
445
+ :full_number => '2',
446
+ :expiration_month => '12',
447
+ :expiration_year => Time.now.year + 1
448
+ }
449
+ end
450
+
451
+ def unstorable_payment_profile_attributes
452
+ {
453
+ :full_number => '3',
454
+ :expiration_month => '12',
455
+ :expiration_year => Time.now.year + 1
456
+ }
457
+ end
458
+
459
+ def expired_payment_profile_attributes
460
+ {
461
+ :full_number => '1',
462
+ :expiration_month => '12',
463
+ :expiration_year => Time.now.year - 1
464
+ }
465
+ end
466
+
467
+ def pretokenized_card_attributes
468
+ {
469
+ :vault_token => '1',
470
+ :current_vault => 'bogus',
471
+ :expiration_month => '12',
472
+ :expiration_year => Time.now.year + 1,
473
+ :last_four => '1234',
474
+ :card_type => 'visa'
475
+ }
476
+ end
477
+
478
+ # Don't create more than 26 customers until we add more initials :)
479
+ def next_customer_initial
480
+ @@customer_initial_index ||= 0
481
+ initial = customer_initials[@@customer_initial_index]
482
+ @@customer_initial_index += 1
483
+ initial
484
+ end
485
+
486
+ # An array of intials
487
+ def customer_initials
488
+ @customer_initials ||= ('a'..'z').to_a
489
+ end
490
+
491
+ # Allows us to create remote resources once per spec hierarchy
492
+ def create_once(type, &block)
493
+ hierarchy = example_group_hierarchy.collect(&:object_id).to_s
494
+
495
+ unless resource(type, hierarchy)
496
+ register_resource(type, hierarchy, block.call)
497
+ end
498
+ resource(type, hierarchy)
499
+ end
500
+
501
+ def resource(type, hierarchy)
502
+ @@resources ||= {}
503
+ @@resources[type] ||= {}
504
+ @@resources[type][hierarchy]
505
+ end
506
+
507
+ def register_resource(type, hierarchy, resource)
508
+ @@resources ||= {}
509
+ @@resources[type] ||= {}
510
+ @@resources[type][hierarchy] = resource
511
+ end
512
+
513
+ end
514
+ end