servicemerchant 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/MIT-LICENSE.txt +20 -0
  2. data/README.txt +231 -0
  3. data/Rakefile +122 -0
  4. data/demo.rb +69 -0
  5. data/recurring_billing/lib/am_extensions.rb +1 -0
  6. data/recurring_billing/lib/am_extensions/paypal_extension.rb +170 -0
  7. data/recurring_billing/lib/dependencies.rb +14 -0
  8. data/recurring_billing/lib/gateways.rb +5 -0
  9. data/recurring_billing/lib/gateways/authorize_net.rb +103 -0
  10. data/recurring_billing/lib/gateways/paypal.rb +124 -0
  11. data/recurring_billing/lib/recurring_billing.rb +130 -0
  12. data/recurring_billing/lib/recurring_billing.rdoc +87 -0
  13. data/recurring_billing/lib/utils.rb +81 -0
  14. data/recurring_billing/test/fixtures.yml +33 -0
  15. data/recurring_billing/test/remote/authorize_net_test.rb +36 -0
  16. data/recurring_billing/test/remote/paypal_test.rb +46 -0
  17. data/recurring_billing/test/remote/recurring_billing_test.rb +41 -0
  18. data/recurring_billing/test/test_helper.rb +153 -0
  19. data/recurring_billing/test/unit/authorize_net_gateway_class_test.rb +42 -0
  20. data/recurring_billing/test/unit/paypal_gateway_class_test.rb +23 -0
  21. data/recurring_billing/test/unit/recurring_billing_gateway_class_test.rb +35 -0
  22. data/recurring_billing/test/unit/utils_test.rb +17 -0
  23. data/subscription_management/Rakefile +29 -0
  24. data/subscription_management/lib/models/subscription.rb +9 -0
  25. data/subscription_management/lib/models/subscription_profile.rb +4 -0
  26. data/subscription_management/lib/subscription_management.rb +326 -0
  27. data/subscription_management/samples/backpack.yml +101 -0
  28. data/subscription_management/samples/basecamp.yml +71 -0
  29. data/subscription_management/samples/brainkeeper.yml +90 -0
  30. data/subscription_management/samples/campfire.yml +74 -0
  31. data/subscription_management/samples/clickandpledge.yml +24 -0
  32. data/subscription_management/samples/demo.rb +19 -0
  33. data/subscription_management/samples/elm.yml +174 -0
  34. data/subscription_management/samples/freshbooks.yml +78 -0
  35. data/subscription_management/samples/highrise.yml +100 -0
  36. data/subscription_management/samples/presets.yml +10 -0
  37. data/subscription_management/samples/tariff.outline.yml +0 -0
  38. data/subscription_management/samples/taxes.yml +21 -0
  39. data/subscription_management/subscription_management.rb +7 -0
  40. data/subscription_management/tasks/schema.rb +50 -0
  41. data/subscription_management/test/connection.rb +10 -0
  42. data/subscription_management/test/remote/subscription_management_test.rb +112 -0
  43. data/subscription_management/test/test_helper.rb +84 -0
  44. data/subscription_management/test/unit/subscription_management_test.rb +40 -0
  45. data/tracker/README +12 -0
  46. data/tracker/Rakefile +40 -0
  47. data/tracker/db/migrations/empty-directory +0 -0
  48. data/tracker/demo.rb +12 -0
  49. data/tracker/lib/models/recurring_payment_profile.rb +134 -0
  50. data/tracker/lib/models/transaction.rb +19 -0
  51. data/tracker/lib/recurring_billing_extension.rb +103 -0
  52. data/tracker/lib/recurring_billing_extension.rdoc +34 -0
  53. data/tracker/tasks/schema.rb +66 -0
  54. data/tracker/test/connection.rb +10 -0
  55. data/tracker/test/recurring_payment_profile.rb +35 -0
  56. data/tracker/test/remote/authorize_net_test.rb +68 -0
  57. data/tracker/test/remote/paypal_test.rb +115 -0
  58. data/tracker/test/test_helper.rb +87 -0
  59. data/tracker/test/unit/recurring_payment_profile_test.rb +62 -0
  60. data/tracker/tracker.rb +10 -0
  61. data/vendor/money-1.7.1/MIT-LICENSE +20 -0
  62. data/vendor/money-1.7.1/README +75 -0
  63. data/vendor/money-1.7.1/lib/bank/no_exchange_bank.rb +9 -0
  64. data/vendor/money-1.7.1/lib/bank/variable_exchange_bank.rb +30 -0
  65. data/vendor/money-1.7.1/lib/money.rb +29 -0
  66. data/vendor/money-1.7.1/lib/money/core_extensions.rb +26 -0
  67. data/vendor/money-1.7.1/lib/money/money.rb +209 -0
  68. data/vendor/money-1.7.1/lib/support/cattr_accessor.rb +57 -0
  69. metadata +153 -0
@@ -0,0 +1,78 @@
1
+ # Tariff configuration for freshbooks
2
+ # http://www.freshbooks.com/pricing.php
3
+ #
4
+
5
+ freshbooks:
6
+ features:
7
+ clients: &clients
8
+ name: Active Clients
9
+ description: "Number of clients available for management"
10
+ staff: &staff
11
+ name: Staff Members
12
+ description: "Number of staff members who can access an account"
13
+ payment_terms:
14
+ monthly: &monthly
15
+ name: Monthly payments
16
+ periodicity: 1m
17
+ services:
18
+ shuttle_bus: &shuttle_bus
19
+ name: Shuttle Bus
20
+ features:
21
+ - feature: *clients
22
+ quantity: 25
23
+ - feature: *staff
24
+ quantity: 1
25
+ limousine: &limousine
26
+ name: Limousine
27
+ features:
28
+ - feature: *clients
29
+ quantity: 100
30
+ - feature: *staff
31
+ quantity: 2
32
+ private_jet: &private_jet
33
+ name: Private Jet
34
+ features:
35
+ - feature: *clients
36
+ quantity: 500
37
+ - feature: *staff
38
+ quantity: 3
39
+ starship: &starship
40
+ name: Starship
41
+ features:
42
+ - feature: *clients
43
+ quantity: 2000
44
+ - feature: *staff
45
+ quantity: 10
46
+ time_machine: &time_machine
47
+ name: Time Machine
48
+ features:
49
+ - feature: *clients
50
+ quantity: 5000
51
+ - feature: *staff
52
+ quantity: 20
53
+ tariff_plans:
54
+ shuttle_bus_monthly:
55
+ service: *shuttle_bus
56
+ payment_term: *monthly
57
+ currency: USD
58
+ price: 1400
59
+ limousine_monthly:
60
+ service: *limousine
61
+ payment_term: *monthly
62
+ currency: USD
63
+ price: 2700
64
+ private_jet_monthly:
65
+ service: *private_jet
66
+ payment_term: *monthly
67
+ currency: USD
68
+ price: 3900
69
+ starship_monthly:
70
+ service: *starship
71
+ payment_term: *monthly
72
+ currency: USD
73
+ price: 8900
74
+ time_machine_monthly:
75
+ service: *time_machine
76
+ payment_term: *monthly
77
+ currency: USD
78
+ price: 14900
@@ -0,0 +1,100 @@
1
+ # Tariff configuration for highrise
2
+ # http://www.highrisehq.com/signup
3
+ #
4
+
5
+ highrise:
6
+ features:
7
+ user: &user
8
+ name: User Accounts
9
+ description: "User accounts available within application"
10
+ storage: &storage
11
+ name: "File Storage"
12
+ unit: Gigabyte
13
+ description: "File storage maximum disk quota"
14
+ case: &case
15
+ name: Cases
16
+ description: "Cases let you keep related people, companies, notes, files, and images together on a convenient single page."
17
+ contact: &contact
18
+ name: Contacts
19
+ descrption: "Contacts for an account"
20
+ ssl: &ssl
21
+ name: SSL Security
22
+ description: "Whether SSL encryption for online sessions is available or not"
23
+ free_campfire_premium: &free_campfire_premium
24
+ name: Free Campfore Premium
25
+ description: "Free Premium Campfire membership. Campfire is real-time group chat tool for businesses."
26
+ payment_terms:
27
+ monthly: &monthly
28
+ name: Monthly payments
29
+ periodicity: 1m
30
+ trial_days: 30
31
+ services:
32
+ solo: &solo
33
+ name: Solo
34
+ features:
35
+ - feature: *user
36
+ quantity: 1
37
+ - feature: *storage
38
+ quantity: 3
39
+ - feature: *contact
40
+ quantity: 20000
41
+ - feature: *case
42
+ quantity: 0
43
+ - feature: *ssl
44
+ basic: &basic
45
+ name: Basic
46
+ features:
47
+ - feature: *user
48
+ quantity: 6
49
+ - feature: *storage
50
+ quantity: 3
51
+ - feature: *contact
52
+ quantity: 5000
53
+ - feature: *case
54
+ quantity: 5
55
+ plus: &plus
56
+ name: Plus
57
+ features:
58
+ - feature: *user
59
+ quantity: 15
60
+ - feature: *storage
61
+ quantity: 10
62
+ - feature: *contact
63
+ quantity: 20000
64
+ - feature: *case
65
+ quantity: 0
66
+ - feature: *ssl
67
+ pro: &pro
68
+ name: Pro
69
+ features:
70
+ - feature: *user
71
+ quantity: 40
72
+ - feature: *storage
73
+ quantity: 20
74
+ - feature: *contact
75
+ quantity: 30000
76
+ - feature: *case
77
+ quantity: 0
78
+ - feature: *ssl
79
+ - feature: *free_campfire_premium
80
+ tariff_plans:
81
+ solo_monthly:
82
+ service: *solo
83
+ payment_term: *monthly
84
+ currency: USD
85
+ price: 2900
86
+ basic_monthly:
87
+ service: *basic
88
+ payment_term: *monthly
89
+ currency: USD
90
+ price: 2400
91
+ plus_monthly:
92
+ service: *plus
93
+ payment_term: *monthly
94
+ currency: USD
95
+ price: 4900
96
+ pro_monthly:
97
+ service: *pro
98
+ payment_term: *monthly
99
+ currency: USD
100
+ price: 9900
@@ -0,0 +1,10 @@
1
+ defaults:
2
+ payment_policies:
3
+ monthly: &default_monthly
4
+ name: Monthly payments
5
+ periodicity: 1m
6
+ description: Paid every month
7
+ yearly: &default_yearly
8
+ name: Annual payments
9
+ periodicity: 1y
10
+ description: Paid every year on the same day
@@ -0,0 +1,21 @@
1
+ defaults:
2
+ gst: &gst
3
+ name: Goods and Services Tax
4
+ tax1: &tax1
5
+ name: Sample tax
6
+
7
+ taxes:
8
+ ca:
9
+ name: non-resident, Canada
10
+ country: CA
11
+ state: *
12
+ taxes:
13
+ - tax: *gst
14
+ rate: 0.05
15
+ us_ca:
16
+ name: resident, CA
17
+ country: US
18
+ state: CA
19
+ taxes:
20
+ - tax: *tax1
21
+ rate: 0.2
@@ -0,0 +1,7 @@
1
+ #TODO: Use auto-loading from activesupport
2
+ require 'rubygems'
3
+ require 'activerecord'
4
+
5
+ require File.dirname(__FILE__) + '/lib/models/subscription'
6
+ require File.dirname(__FILE__) + '/lib/models/subscription_profile'
7
+ require File.dirname(__FILE__) + '/lib/subscription_management'
@@ -0,0 +1,50 @@
1
+ namespace :subscription do
2
+ desc 'Create Subscription management database tables'
3
+ task :create_tables => :connection do
4
+ ActiveRecord::Base.connection.create_table :subscriptions, :force => true do |t|
5
+ t.column :account_id, :string, :null => false
6
+ t.column :tariff_plan_id, :string, :null => false
7
+ t.column :taxes_id, :string, :null => false
8
+ t.column :quantity, :integer, :null => false
9
+ t.column :currency, :string, :null => false
10
+ t.column :net_amount, :integer, :null => false
11
+ t.column :taxes_amount, :integer, :null => false
12
+ t.column :periodicity, :string, :null => false
13
+ t.column :starts_on, :date, :null => false
14
+ t.column :ends_on, :date
15
+ t.column :status, :string, :null => false
16
+ t.column :created_at, :datetime, :null => false
17
+ t.column :updated_at, :datetime
18
+ t.column :deleted_at, :datetime
19
+ end
20
+ ActiveRecord::Base.connection.add_index :subscriptions, [ :account_id ], :name => 'ix_subscription_account'
21
+
22
+ ActiveRecord::Base.connection.create_table :subscription_profiles, :force => true do |t|
23
+ t.column :subscription_id, :integer, :null => false
24
+ t.column :recurring_payment_profile_id, :integer, :null => false
25
+ t.column :created_at, :datetime, :null => false
26
+ end
27
+ ActiveRecord::Base.connection.add_index :subscription_profiles, [ :subscription_id ], :name => 'ix_subscription_profiles_subscription'
28
+ end
29
+
30
+ desc 'Drop Subscription management database tables'
31
+ task :drop_tables => :connection do
32
+ ActiveRecord::Base.connection.drop_table :subscription_profiles
33
+ ActiveRecord::Base.connection.drop_table :subscriptions
34
+ end
35
+
36
+ # Use Rails connection when appropriate or fallback to local test db
37
+ task :connection do
38
+ connected = false
39
+ begin
40
+ begin
41
+ connected = true if ActiveRecord::Base.connection
42
+ rescue ActiveRecord::ConenctionNotEstablished
43
+ end
44
+ rescue NameError # ActiveRecord not loaded
45
+ end
46
+ require File.dirname(__FILE__) + "/../test/connection" unless connected
47
+ end
48
+ end
49
+
50
+
@@ -0,0 +1,10 @@
1
+ # As we're not using Rails in tests, we have to establish DB conneciton ourselves
2
+ require 'rubygems'
3
+ gem 'activerecord'
4
+ require 'activerecord'
5
+ gem 'sqlite3-ruby'
6
+
7
+ ActiveRecord::Base.establish_connection(
8
+ :adapter => "sqlite3",
9
+ :database => (File.dirname(__FILE__) + "/../../tracker/db/test.db")
10
+ )
@@ -0,0 +1,112 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ require 'money'
4
+
5
+ class SubscriptionManagementRemoteTest < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @sm = ::SubscriptionManagement.new(
9
+ :tariff_plans_config => File.dirname(__FILE__) + '/../../samples/backpack.yml',
10
+ :taxes_config => File.dirname(__FILE__) + '/../../samples/taxes.yml',
11
+ :gateways_config => File.dirname(__FILE__) + '/../../../recurring_billing/test/fixtures.yml',
12
+ :gateway => :paypal
13
+ )
14
+ end
15
+
16
+ # Checks if there are no exceptions while manipulating class with legit data; based on demo.rb
17
+ def test_crud_is_working
18
+ options = {
19
+ :account_id => 'test_acc_id',
20
+ :account_country => 'US',
21
+ :account_state => 'CA',
22
+ :tariff_plan => 'solo_monthly',
23
+ :start_date => (Date.today + 1),
24
+ :quantity => 1,
25
+ :end_date => DateTime.new(2010, 12, 11)
26
+ }
27
+ credit_card = credit_card()
28
+ credit_card_2 = credit_card(4929838635250031, {:year => Time.now.year + 5})
29
+ credit_card_3 = credit_card(4929273971564532, {:year => Time.now.year + 3})
30
+
31
+ assert_raise StandardError do; @sm.get_active_profile(-1); end
32
+
33
+ subscription_id = @sm.subscribe(options)
34
+ assert_equal 'pending', Subscription.find_by_id(subscription_id).status
35
+ assert_raise StandardError do; @sm.get_active_profile(subscription_id); end
36
+ @sm.pay_for_subscription(subscription_id, credit_card, {})
37
+ subscription = Subscription.find_by_id(subscription_id)
38
+ assert_equal 'ok', subscription.status
39
+ assert_equal 700, subscription.net_amount
40
+ assert_equal 140, subscription.taxes_amount
41
+ assert_equal 840, subscription.billing_amount
42
+
43
+ assert_equal 1, subscription.recurring_payment_profiles.length
44
+ profile = subscription.recurring_payment_profiles[0]
45
+ assert_equal 700, profile.net_amount
46
+ assert_equal 140, profile.taxes_amount
47
+ assert_equal 840, profile.amount
48
+
49
+ # create payment and check invoice
50
+ time = DateTime.now
51
+ transaction = Transaction.new({
52
+ :recurring_payment_profile_id => profile.id,
53
+ :gateway_reference => 'ABC0123456789XYZ',
54
+ :currency => 'USD',
55
+ :amount => 840,
56
+ :created_at => time
57
+ })
58
+ transaction.save!
59
+
60
+ invoice_data = @sm.get_invoice_data(transaction.id)
61
+ invoice_data[:date] = invoice_data[:date].strftime('%Y-%m-%d')
62
+
63
+ assert_equal({:taxes_comment =>"resident, CA",
64
+ :net_amount =>"7.00 USD",
65
+ :billing_account =>"test_acc_id",
66
+ :transaction_gateway=>"PAYPAL",
67
+ :taxes_amount =>"1.40 USD",
68
+ :transaction_id =>"ABC0123456789XYZ",
69
+ :number => transaction.id,
70
+ :date => time.strftime('%Y-%m-%d'),
71
+ :transaction_amount=>"8.40 USD",
72
+ :total_amount =>"8.40 USD",
73
+ :service_name =>"Solo (per month)"
74
+ },
75
+ invoice_data
76
+ )
77
+
78
+ transaction = Transaction.new({
79
+ :recurring_payment_profile_id => profile.id,
80
+ :gateway_reference => 'CAB0123456789ZYX',
81
+ :currency => 'CAD',
82
+ :amount => 840,
83
+ :created_at => Date.today
84
+ })
85
+ transaction.save!
86
+ assert_raises NotImplementedError do; @sm.get_invoice_data(transaction.id); end
87
+
88
+ transaction = Transaction.new({
89
+ :recurring_payment_profile_id => profile.id,
90
+ :gateway_reference => 'CAB0123456789ZYX',
91
+ :currency => 'USD',
92
+ :amount => 839,
93
+ :created_at => Date.today
94
+ })
95
+ transaction.save!
96
+ assert_raises NotImplementedError do; @sm.get_invoice_data(transaction.id); end
97
+
98
+ features = @sm.get_features(subscription_id)
99
+
100
+ options = {:card=>credit_card_2}
101
+ assert @sm.update_possible?(subscription_id, options)
102
+ @sm.update_subscription(subscription_id, options)
103
+
104
+ options = {:card=>credit_card_3, :start_date => Date.today + 42}
105
+ assert !@sm.update_possible?(subscription_id, options)
106
+ @sm.update_subscription(subscription_id, options)
107
+
108
+ @sm.unsubscribe(subscription_id)
109
+ assert_equal 'canceled', Subscription.find_by_id(subscription_id).status
110
+ end
111
+
112
+ end
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'test/unit'
5
+ require 'activesupport'
6
+
7
+ silence_warnings do
8
+ require 'active_merchant'
9
+ end
10
+
11
+ require File.dirname(__FILE__) + "/connection"
12
+ require File.dirname(__FILE__) + '/../subscription_management'
13
+
14
+ # Turn off invalid certificate crashes
15
+ require 'openssl'
16
+ silence_warnings do
17
+ OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
18
+ end
19
+
20
+ ActiveMerchant::Billing::Base.mode = :test
21
+
22
+ module Test
23
+ module Unit
24
+ class TestCase
25
+
26
+
27
+ DEFAULT_CREDENTIALS = File.dirname(__FILE__) + '/fixtures.yml'
28
+
29
+ private
30
+ def credit_card(number = '4242424242424242', options = {})
31
+ defaults = {
32
+ :number => number,
33
+ :month => 9,
34
+ :year => Time.now.year + 1,
35
+ :first_name => 'John',
36
+ :last_name => 'Doe',
37
+ :verification_value => '123',
38
+ :type => 'visa'
39
+ }.update(options)
40
+
41
+ ActiveMerchant::Billing::CreditCard.new(defaults)
42
+ end
43
+
44
+ def address(options = {})
45
+ {
46
+ :name => 'John Doe',
47
+ :address1 => '1234 My Street',
48
+ :address2 => 'Apt 1',
49
+ :company => 'Widgets Inc',
50
+ :city => 'Ottawa',
51
+ :state => 'ON',
52
+ :zip => 'K1C2N6',
53
+ :country => 'CA',
54
+ :phone => '(555)555-5555'
55
+ }.update(options)
56
+ end
57
+
58
+ def all_fixtures
59
+ @@fixtures ||= load_fixtures
60
+ end
61
+
62
+ def fixtures(key)
63
+ data = all_fixtures[key] || raise(StandardError, "No fixture data was found for '#{key}'")
64
+
65
+ data.dup
66
+ end
67
+
68
+ def load_fixtures
69
+ file = DEFAULT_CREDENTIALS
70
+ yaml_data = YAML.load(File.read(file))
71
+ symbolize_keys(yaml_data)
72
+
73
+ yaml_data
74
+ end
75
+
76
+ def symbolize_keys(hash)
77
+ return unless hash.is_a?(Hash)
78
+
79
+ hash.symbolize_keys!
80
+ hash.each{|k,v| symbolize_keys(v)}
81
+ end
82
+ end
83
+ end
84
+ end