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,42 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class AuthorizeNetGatewayTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ credentials = fixtures(:authorize_net)
7
+ assert @gw = RecurringBilling::AuthorizeNetGateway.new(credentials.update({:is_test => true}))
8
+ assert_equal @gw.name, 'Authorize.net'
9
+ @card = credit_card()
10
+ end
11
+
12
+ def test_correct_update?
13
+ #def correct_update?(billing_id, amount, card, payment_options, recurring_options)
14
+ subscr_id = 'SOMERANDOMID'
15
+ assert_raise StandardError do; @gw.correct_update?(subscr_id, nil, @card, nil, {:start_date => Date.today + 1}); end
16
+ assert_nothing_thrown do;@gw.correct_update?(subscr_id, 1, @card, nil, nil);end
17
+ assert_nothing_thrown do;@gw.correct_update?(subscr_id, 100, @card, nil, {});end
18
+
19
+ end
20
+
21
+ def test_transform_dates
22
+ def d(string);return Date.parse(string);end
23
+ def h(a,b,c,d);return {:interval=>{:length=>a, :unit=>b}, :duration=>{:start_date=>c, :occurrences=>d}};end
24
+
25
+ #syntax is: transform_dates(start_date, interval, occurrences, end_date)
26
+ assert_raise ArgumentError do; @gw.transform_dates(d('2008/01/01'), '5m', nil, nil); end
27
+ assert_raise ArgumentError do; @gw.transform_dates(d('2008/01/01'), '5m', 5, d('2009/01/01')); end
28
+ assert_raise ArgumentError do; @gw.transform_dates(d('2008/01/01'), 'm', 1, nil); end
29
+ assert_raise ArgumentError do; @gw.transform_dates(d('2008/01/01'), '0.5m', 1, nil); end
30
+ assert_raise ArgumentError do; @gw.transform_dates(d('2008/01/01'), '1 year', 1, nil); end
31
+ assert_raise ArgumentError do; @gw.transform_dates(d('2008/01/01'), '8', 1, nil); end
32
+ assert_raise ArgumentError do; @gw.transform_dates(d('2008/01/01'), '5m', -1, nil); end
33
+ assert_raise ArgumentError do; @gw.transform_dates(d('2008/01/01'), '5m', nil, d('2007/12/31')); end
34
+
35
+ assert_equal @gw.transform_dates(d('2008/01/01'), '5m', 7, nil), h(5,:months,d('2008/01/01'),7)
36
+ assert_equal @gw.transform_dates(d('2008/01/01'), '3 d', nil, d('2008/01/19')), h(3,:days,d('2008/01/01'),7)
37
+ assert_equal @gw.transform_dates(d('2008/01/01'), '3d', nil, d('2008/01/21')), h(3,:days,d('2008/01/01'),7)
38
+ assert_equal @gw.transform_dates(d('2008/01/01'), '8w', 13, nil), h(56,:days,d('2008/01/01'),13)
39
+ assert_equal @gw.transform_dates(d('2008/01/01'), '1y', nil, d('2010/12/01')), h(12,:months,d('2008/01/01'),3)
40
+ end
41
+
42
+ end
@@ -0,0 +1,23 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class PaypalGatewayTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ cred = fixtures(:paypal)
7
+ assert @gw = RecurringBilling::PaypalGateway.new(cred.update({:is_test=>true}))
8
+ assert_equal @gw.name, 'PayPal Website Payments Pro (US)'
9
+ @card = credit_card()
10
+ end
11
+
12
+ def test_true
13
+ end
14
+
15
+ # def test_correct_update?
16
+ # #def correct_update?(billing_id, amount, card, payment_options, recurring_options)
17
+ # subscr_id = 'SOMERANDOMID'
18
+ # assert_raise StandardError do; @gw.correct_update?(subscr_id, nil, @card, nil, {:start_date => Date.today + 1}); end
19
+ # assert_nothing_thrown do;@gw.correct_update?(subscr_id, 1, @card, nil, nil);end
20
+ # assert_nothing_thrown do;@gw.correct_update?(subscr_id, 100, @card, nil, {});end
21
+ # end
22
+
23
+ end
@@ -0,0 +1,35 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class RecurringBillingGatewayTest < Test::Unit::TestCase
4
+
5
+ def perform_generic_test(gateway)
6
+ credentials = fixtures(gateway)
7
+ assert gw = RecurringBilling::RecurringBillingGateway.get_instance(credentials)
8
+ end
9
+
10
+ # Checking separate_create_update_params_from_options method
11
+ def test_separate_create_update_params_from_options
12
+ cc = credit_card()
13
+ payment_options = {
14
+ :subscription_name => 'Test Subscription 1337',
15
+ :order => {:invoice_number => '000000'}
16
+ }
17
+ recurring_options = {
18
+ :start_date => Date.today + 1,
19
+ :end_date => Date.today + 290,
20
+ :interval => '1m'
21
+ }
22
+ all_options = {}.update({:card => cc}).update(payment_options).update(recurring_options)
23
+ separate_options = RecurringBilling::RecurringBillingGateway.separate_create_update_params_from_options(all_options)
24
+ assert_equal separate_options, {:amount => nil, :card => cc, :payment_options => payment_options, :recurring_options => recurring_options}
25
+ end
26
+
27
+ def test_paypal
28
+ perform_generic_test(:paypal)
29
+ end
30
+
31
+ def test_authorize_net
32
+ perform_generic_test(:authorize_net)
33
+ end
34
+
35
+ end
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+
3
+ class UtilsTest < Test::Unit::TestCase
4
+ def test_months_between
5
+ def d(string);return Date.parse(string);end
6
+
7
+ assert months_between(d("2008/10/01"), d("2008/10/01")), 0
8
+ assert months_between(d("2008/10/02"), d("2008/10/01")), 0
9
+ assert months_between(d("2008/11/01"), d("2008/10/02")), 0
10
+ assert months_between(d("2008/01/01"), d("2007/12/31")), 0
11
+ assert months_between(d("2008/11/01"), d("2008/10/01")), 1
12
+ assert months_between(d("2008/02/01"), d("2007/05/01")), 9
13
+ assert months_between(d("2008/02/14"), d("2007/05/01")), 9
14
+ assert months_between(d("2008/02/02"), d("2007/05/13")), 8
15
+ end
16
+
17
+ end
@@ -0,0 +1,29 @@
1
+ require 'rake'
2
+ require File.dirname(__FILE__) + '/tasks/schema.rb'
3
+
4
+
5
+ require 'rake/testtask'
6
+ namespace :test do
7
+
8
+ Rake::TestTask.new(:remote_sm) do |t|
9
+ t.pattern = 'test/remote/**/*_test.rb'
10
+ t.ruby_opts << '-rubygems'
11
+ t.verbose = true
12
+ end
13
+
14
+ desc "Run all remote tests"
15
+ task :remote => [:remote_sm]
16
+
17
+ Rake::TestTask.new(:unit_sm) do |t|
18
+ t.pattern = 'test/unit/**/*_test.rb'
19
+ t.ruby_opts << '-rubygems'
20
+ t.verbose = true
21
+ end
22
+
23
+ desc "Run all unit tests"
24
+ task :unit => [:unit_sm]
25
+
26
+ desc "Run all tests"
27
+ task :all => [:unit_sm, :remote_sm]
28
+
29
+ end
@@ -0,0 +1,9 @@
1
+ class Subscription < ActiveRecord::Base
2
+ has_many :subscription_profiles
3
+ has_many :recurring_payment_profiles, :through => :subscription_profiles
4
+
5
+ # Returns billing amount (sum of net amount + taxes)
6
+ def billing_amount
7
+ self.net_amount + self.taxes_amount
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ class SubscriptionProfile < ActiveRecord::Base
2
+ belongs_to :subscription
3
+ belongs_to :recurring_payment_profile
4
+ end
@@ -0,0 +1,326 @@
1
+ require 'yaml'
2
+ require File.dirname(__FILE__) + '/../../recurring_billing/lib/recurring_billing'
3
+ require File.dirname(__FILE__) + '/../../tracker/tracker'
4
+ require 'rubygems'
5
+ require 'active_support/inflector'
6
+
7
+ #module SubscriptionManagement
8
+
9
+ # This class allows handling of user subscriptions for given merchant service. See {PROJECT_ROOT}/demo.rb for usage example.
10
+ class SubscriptionManagement
11
+ attr_accessor :all_tariff_plans, :all_taxes, :tariff_plans_namespace, :all_gateways, :gateway
12
+
13
+ # Constructs new SubscriptionManagement object
14
+ #
15
+ # Optional +options+ hash may include:
16
+ #
17
+ # definition of tariff plan config by config file name
18
+ # - :tariff_plans_config - string defining name of YML file to read tariff plan configuration from
19
+ # definition of tariff plan config by specifying tariff plans and its namespace directly (only if :tariff_plans_config is not present)
20
+ # - :all_tariff_plans - hash containing tariff plans
21
+ # - :tariff_plans_namespace - string defining namespace for given tariff plans
22
+ # definition of tax config by config file name
23
+ # - :taxes_config - string defining name of YML file to read taxes configuration from
24
+ # definition of tax config by specifying tariff plans and its namespace directly (only if :taxes_config is not present)
25
+ # - :all_taxes - hash containing taxes
26
+ # definition of gateways config by config file name
27
+ # - :gateways_config - string defining name of YML file to read gateways configuration from
28
+ # definition of tax config by specifying tariff plans and its namespace directly (only if :gateways_config is not present)
29
+ # - :all_gateways - hash containing gateways
30
+ # definition of default gateway
31
+ # - :gateway - Symbol or string containing gateway name
32
+ def initialize(options={})
33
+ if options[:tariff_plans_config]
34
+ @all_tariff_plans = SubscriptionManagement.get_all_tariff_plans(options[:tariff_plans_config])
35
+ @tariff_plans_namespace = File.basename(options[:tariff_plans_config], '.yml').downcase.camelize
36
+ else
37
+ if options[:all_tariff_plans]
38
+ @all_tariff_plans = options[:all_tariff_plans]
39
+ end
40
+ if options[:tariff_plans_namespace]
41
+ @tariff_plan_namespace = options[:tariff_plans_namespace]
42
+ end
43
+ end
44
+
45
+ if options[:taxes_config]
46
+ @all_taxes = SubscriptionManagement.get_all_taxes(options[:taxes_config])
47
+ elsif options[:taxes]
48
+ @all_taxes = options[:all_taxes]
49
+ end
50
+
51
+ if options[:gateways_config]
52
+ @all_gateways = SubscriptionManagement.get_gateway_settings(options[:gateways_config])
53
+ elsif options[:all_gateways]
54
+ @all_gateways = options[:all_gateways]
55
+ end
56
+
57
+ if [String, Symbol].include? options[:gateway].class
58
+ @gateway = @all_gateways[options[:gateway].to_sym]
59
+ elsif options[:gateway].class == Hash
60
+ @gateway = options[:gateway]
61
+ end
62
+
63
+ return self
64
+ end
65
+
66
+ # Returns the most applicable identifier of tax area settings available for given country and state (instance)
67
+ def get_applicable_taxes_id(country, state)
68
+ return SubscriptionManagement.get_taxes_id(@all_taxes, country, state)
69
+ end
70
+
71
+ # Subscribe account for tariff plan, specified in "all_tariff_plans" property of an instance
72
+ #
73
+ # options hash should/may include following keys:
74
+ # :account_id
75
+ # :account_country
76
+ # :account_state
77
+ # :tariff_plan
78
+ # :start_date
79
+ # :quantity
80
+ # :end_date
81
+ def subscribe(options)
82
+ subscription = Subscription.new
83
+ subscription.account_id=options[:account_id]
84
+ subscription.tariff_plan_id = options[:tariff_plan]
85
+ subscription.quantity = options[:quantity]
86
+
87
+
88
+ # Set tariff-related fields
89
+ tariff = @all_tariff_plans[subscription.tariff_plan_id]
90
+ raise ArgumentError, 'Invalid tariff given: %s' % subscription.tariff_plan_id if tariff.nil?
91
+ subscription.currency = tariff["currency"]
92
+ subscription.periodicity = tariff["payment_term"]["periodicity"]
93
+
94
+ subscription.starts_on = options[:start_date] + tariff["payment_term"]["trial_days"]
95
+ subscription.ends_on = options[:end_date]
96
+
97
+ # Set tax- and payment-related fields
98
+ subscription.taxes_id = get_applicable_taxes_id(options[:account_country], options[:account_state])
99
+ total_tax = @all_taxes[subscription.taxes_id]["taxes"].inject(0){|sum,item| sum + item["rate"]} # sum all taxes
100
+ subscription.net_amount = subscription.quantity * tariff["price"]
101
+ subscription.taxes_amount = subscription.net_amount * total_tax
102
+
103
+ subscription.status = 'pending'
104
+ subscription.save
105
+
106
+ return subscription.id
107
+ end
108
+
109
+ # Proceed subscription payment through specified payment gateway
110
+ def pay_for_subscription(subscription_id, card, payment_options)
111
+ subscription = Subscription.find_by_id(subscription_id)
112
+
113
+ gw = RecurringBilling::RecurringBillingGateway.get_instance(@gateway)
114
+ tariff = @all_tariff_plans[subscription.tariff_plan_id]
115
+ recurring_options = {
116
+ :start_date => subscription.starts_on,
117
+ :trial_days => tariff['payment_term']['trial_days'],
118
+ :end_date => subscription.ends_on,
119
+ :interval => tariff['payment_term']['periodicity']
120
+ }
121
+
122
+ if payment_options[:subscription_name].nil?
123
+ payment_options[:subscription_name] = @tariff_plans_namespace+': '+tariff['service']['name']
124
+ end
125
+
126
+ payment_options[:taxes_amount_included] = Money.new(subscription.taxes_amount,subscription.currency)
127
+
128
+ gateway_id = gw.create(Money.new(subscription.billing_amount, subscription.currency), card, payment_options, recurring_options)
129
+ if !gateway_id.nil?
130
+ sp = SubscriptionProfile.new
131
+ sp.subscription_id = subscription.id
132
+ sp.recurring_payment_profile_id = RecurringPaymentProfile.find_by_gateway_reference(gateway_id).id
133
+ sp.save
134
+ subscription.status = 'ok'
135
+ subscription.save
136
+ else
137
+ raise StandardError, 'Recurring payment creation error: ' + gw.last_response.message
138
+ end
139
+ end
140
+
141
+ # Update subscription through specified payment gateway
142
+ def update_subscription(subscription_id, options)
143
+ profile = get_active_profile(subscription_id)
144
+ gw = RecurringBilling::RecurringBillingGateway.get_instance(@gateway)
145
+ unless new_gateway_reference = gw.update_or_recreate(profile.gateway_reference, options)
146
+ raise StandardError, 'Cannot update subscription through gateway: ' + gw.last_response.message
147
+ end
148
+
149
+ unless new_gateway_reference == profile.gateway_reference
150
+ sp = SubscriptionProfile.new
151
+ sp.subscription_id = subscription_id
152
+ sp.recurring_payment_profile_id = RecurringPaymentProfile.find_by_gateway_reference(new_gateway_reference).id
153
+ sp.save
154
+ end
155
+ end
156
+
157
+ # Gets active profile for given subscription_id
158
+ def get_active_profile(subscription_id)
159
+ raise StandardError, "Subscription with ID #{subscription_id} not found" if (subscription = Subscription.find_by_id(subscription_id)).nil?
160
+ raise StandardError, "Subscription with ID #{subscription_id} is inactive and cannot thus have active profiles" unless subscription.status == 'ok'
161
+
162
+ if (profile = subscription.recurring_payment_profiles.find(:first, :conditions => [ "status != 'deleted'"])).nil?
163
+ raise StandardError, "Cannot find any active profiles for subscription: #{subscription_id}"
164
+ end
165
+
166
+ return profile
167
+ end
168
+
169
+ # Checks if given subscription could be updated (re-create would be needed otherwize)
170
+ def update_possible?(subscription_id, options)
171
+ begin
172
+ gw = RecurringBilling::RecurringBillingGateway.get_instance(@gateway)
173
+ return gw.can_update?(get_active_profile(subscription_id).gateway_reference, options) ? true : false
174
+ rescue
175
+ return false
176
+ end
177
+ end
178
+
179
+ #Cancel subscription (specified by SUBSCRIPTION_ID)
180
+ def unsubscribe(subscription_id)
181
+ raise StandardError, "Subscription with ID #{subscription_id} not found" if (subscription = Subscription.find_by_id(subscription_id)).nil?
182
+ if subscription.status == 'ok' && !(profile = subscription.recurring_payment_profiles.find(:first, :conditions => [ "status != 'deleted'"])).nil?
183
+ gw = RecurringBilling::RecurringBillingGateway.get_instance(@gateway)
184
+ raise StandardError, 'Cannot cancel subscription through gateway: ' + gw.last_response.message unless gw.delete(profile.gateway_reference)
185
+ end
186
+ subscription.status = 'canceled'
187
+ subscription.save
188
+ end
189
+
190
+ #Get available features provided by given subscription (specified by SUBSCRIPTION_ID)
191
+ def get_features(subscription_id)
192
+ return {} if (subscription = Subscription.find_by_id(subscription_id)).nil? && (subscription.status != 'ok')
193
+ @all_tariff_plans[subscription.tariff_plan_id]['service']['features']
194
+ end
195
+
196
+ def get_invoice_data(invoice_id) #:nodoc:
197
+ transaction = Transaction.find invoice_id
198
+ profile = transaction.recurring_payment_profile
199
+
200
+ if transaction.money != profile.money
201
+ raise NotImplementedError, 'Transaction payment cannot differ from recurring payment'
202
+ end
203
+
204
+ subscription = SubscriptionProfile.find(:first, :conditions => ['recurring_payment_profile_id = ?', profile]).subscription
205
+ tariff = @all_tariff_plans[subscription.tariff_plan_id]
206
+ service_name = '%s %s(%s)' % [
207
+ tariff['service']['name'],
208
+ (subscription.quantity == 1 ? '' : 'x%s '% subscription.quantity),
209
+ SubscriptionManagement.format_periodicity(tariff['payment_term']['periodicity']).gsub('each','per')
210
+ ]
211
+ {
212
+ :billing_account => subscription.account_id,
213
+ :service_name => service_name,
214
+ :net_amount => profile.net_money_formatted,
215
+ :taxes_amount => profile.taxes_money_formatted,
216
+ :total_amount => profile.money_formatted,
217
+ :taxes_comment => @all_taxes[subscription.taxes_id]["name"],
218
+
219
+ :date => transaction.created_at,
220
+ :number => transaction.id,
221
+ :transaction_gateway => profile.gateway,
222
+ :transaction_id => transaction.gateway_reference,
223
+ :transaction_amount => transaction.money_formatted
224
+ }
225
+ end
226
+
227
+ class << self
228
+
229
+ # Returns whole contents of given tariff config file (by CONFIG_NAME filename)
230
+ def read_tariff_config(config_name)
231
+ return YAML.load([File.read('%s/presets.yml' % File.dirname(config_name)), File.read(config_name)].join("\n"))
232
+ end
233
+
234
+ # Retrieves tariff settings from given file (by CONFIG_NAME filename)
235
+ def get_all_tariff_plans(config_name)
236
+ return read_tariff_config(config_name)[File.basename(config_name, '.yml')]['tariff_plans']
237
+ end
238
+
239
+ # Reads tax config from given file (by CONFIG_NAME filename)
240
+ def get_all_taxes(config_name)
241
+ return YAML.load(File.read(config_name))['taxes']
242
+ end
243
+
244
+ # Reads gateway settings from given file (by CONFIG_NAME filename)
245
+ def get_gateway_settings(config_name)
246
+ def symbolize_keys(hash)
247
+ return unless hash.is_a?(Hash)
248
+
249
+ hash.symbolize_keys!
250
+ hash.each{|k,v| symbolize_keys(v)}
251
+ end
252
+
253
+ symbolize_keys(YAML.load(File.read(config_name)))
254
+ end
255
+
256
+ # Returns the most applicable identifier of tax area settings available for given COUNTRY and STATE (class)
257
+ #
258
+ # Example:
259
+ # taxes = {}
260
+ # taxes["ca"] = {"country"=>"CA", "taxes"=>[{"tax"=>{"name"=>"Tax1"}, "rate"=>0.05}], "state"=>"*"}
261
+ # taxes[""us_ca""] = {"country"=>"US", "taxes"=>[{"tax"=>{"name"=>"Sample tax"}, "rate"=>0.2}], "state"=>"CA"}
262
+ # get_taxes_id(taxes, 'RU', 'MSK') # => StandardError
263
+ # get_taxes_id(taxes, 'CA', 'ON') # => "ca"
264
+ # get_taxes_id(taxes, 'US', 'CA') # => "us_ca"
265
+ # get_taxes_id(taxes, 'US', 'FL') # => StandardError
266
+ def get_taxes_id(taxes, country, state)
267
+ return ("%s_%s" % [country, state]).downcase unless (state.empty? || taxes[("%s_%s" % [country, state]).downcase].nil?)
268
+ return country.downcase unless (country.empty? || taxes[country.downcase].nil?)
269
+ raise StandardError, 'Tax is unknown for given country and state - %s, %s' % [country, state]
270
+ end
271
+
272
+ # Returns formatted string for FEATURE hash
273
+ #
274
+ # Example 1:
275
+ # feature['feature']['name'] = 'Message Boards'
276
+ # feature['quantity'] == nil => 'Message Boards' (when we just want to show that feature is available)
277
+ # feature['quantity'] == 1, feature['feature']['unit'] == nil => 'Message Boards: 1' (when unit is obvious from feature name)
278
+ #
279
+ # Example 2:
280
+ # feature['feature']['name'] = 'Disk Quota'
281
+ # feature['quantity'] == 1, feature['feature']['unit'] == 'Gigabyte' => 'Disk Quota: 1 Gigabyte' (when unit is not obvious it has to be specified)
282
+ # feature['quantity'] == 2, feature['feature']['unit'] == 'Gigabyte' => 'Disk Quota: 2 Gigabytes'
283
+ # feature['quantity'] == 0, feature['feature']['unit'] == 'Gigabyte' => 'Disk Quota: Unlimited'
284
+ def format_feature(feature)
285
+ return "#{feature['feature']['name']}" unless feature['quantity']
286
+ quantity = feature['quantity']
287
+ if quantity == 0
288
+ return "#{feature['feature']['name']}: Unlimited"
289
+ else
290
+ return "#{feature['feature']['name']}: #{quantity}" unless feature['feature']['unit']
291
+ unit_correct_form = (quantity > 1) ? ActiveSupport::Inflector.pluralize(feature['feature']['unit']) : feature['feature']['unit']
292
+ return "#{feature['feature']['name']}: #{quantity} #{unit_correct_form}"
293
+ end
294
+ end
295
+
296
+ # Returns human-readable string for standard interval string (PERIODICITY)
297
+ #
298
+ # Sample use:
299
+ # "1w" => 'each week'
300
+ # "0.5 m" => 'twice a month'
301
+ # "10 d" => 'each 10 days'
302
+ # "3y" => 'each 3 years'
303
+ # "0.25 w" => ArgumentError
304
+ # "2 x" => ArgumentError
305
+ def format_periodicity(periodicity)
306
+ if (periodicity =~ /^(\d+|0\.5)\s*(d|w|m|y)$/i)
307
+ i_length, i_unit = $1 == '0.5' ? 0.5 : $1.to_i, $2.downcase.to_sym
308
+ else
309
+ raise ArgumentError, "Invalid periodicity given: #{periodicity}"
310
+ end
311
+
312
+ text_unit = case i_unit
313
+ when :d then 'day'
314
+ when :w then 'week'
315
+ when :m then 'month'
316
+ when :y then 'year'
317
+ end
318
+
319
+ return "twice a #{text_unit}" if i_length == 0.5
320
+ return "each #{text_unit}" if i_length == 1
321
+ return "each #{i_length} #{ActiveSupport::Inflector.pluralize(text_unit)}"
322
+ end
323
+
324
+ end
325
+ end
326
+ #end