servicemerchant 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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