recurly 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of recurly might be problematic. Click here for more details.

Files changed (99) hide show
  1. data/README.md +15 -11
  2. data/lib/patches/active_resource/connection.rb +10 -0
  3. data/lib/recurly.rb +35 -9
  4. data/lib/recurly/account.rb +22 -1
  5. data/lib/recurly/account_base.rb +35 -0
  6. data/lib/recurly/base.rb +26 -39
  7. data/lib/recurly/billing_info.rb +40 -1
  8. data/lib/recurly/charge.rb +12 -1
  9. data/lib/recurly/coupon.rb +8 -0
  10. data/lib/recurly/credit.rb +12 -1
  11. data/lib/recurly/exceptions.rb +19 -0
  12. data/lib/recurly/invoice.rb +1 -1
  13. data/lib/recurly/plan.rb +13 -1
  14. data/lib/recurly/rails3/recurly.rake +5 -3
  15. data/lib/recurly/subscription.rb +21 -3
  16. data/lib/recurly/transaction.rb +29 -1
  17. data/lib/recurly/transparent.rb +140 -0
  18. data/lib/recurly/version.rb +1 -1
  19. data/spec/config/recurly.yml +12 -0
  20. data/spec/config/test1.yml +3 -1
  21. data/spec/config/test2.yml +4 -2
  22. data/spec/integration/credit_spec.rb +6 -6
  23. data/spec/integration/plan_spec.rb +2 -2
  24. data/spec/support/factory.rb +5 -3
  25. data/spec/unit/account_spec.rb +19 -0
  26. data/spec/unit/billing_info_spec.rb +38 -0
  27. data/spec/unit/charge_spec.rb +18 -0
  28. data/spec/unit/config_spec.rb +10 -6
  29. data/spec/unit/coupon_spec.rb +13 -0
  30. data/spec/unit/credit_spec.rb +18 -0
  31. data/spec/unit/plan_spec.rb +18 -0
  32. data/spec/unit/subscription_spec.rb +25 -0
  33. data/spec/unit/transaction_spec.rb +32 -0
  34. data/spec/unit/transparent_spec.rb +114 -0
  35. data/spec/vcr/account/accept-language-account/{1296674173.yml → 1297746103.yml} +16 -13
  36. data/spec/vcr/account/close/{1296674173.yml → 1297746103.yml} +31 -28
  37. data/spec/vcr/account/create-blank/{1296674173.yml → 1297746103.yml} +9 -5
  38. data/spec/vcr/account/create-duplicate/{1296674173.yml → 1297746103.yml} +22 -15
  39. data/spec/vcr/account/create-min/{1296674173.yml → 1297746103.yml} +16 -13
  40. data/spec/vcr/account/create/{1296674173.yml → 1297746103.yml} +16 -13
  41. data/spec/vcr/account/find/{1296674173.yml → 1297746103.yml} +29 -26
  42. data/spec/vcr/account/list/1297746103.yml +1579 -0
  43. data/spec/vcr/account/update/{1296674173.yml → 1297746103.yml} +54 -47
  44. data/spec/vcr/billing/create/{1296690812.yml → 1298594128.yml} +37 -34
  45. data/spec/vcr/billing/destroy/{1296690812.yml → 1298594128.yml} +46 -43
  46. data/spec/vcr/billing/find/{1296690812.yml → 1298594128.yml} +47 -44
  47. data/spec/vcr/billing/update/{1296690812.yml → 1298594128.yml} +50 -47
  48. data/spec/vcr/charge/create/{1296674173.yml → 1297746103.yml} +48 -45
  49. data/spec/vcr/charge/delete-uninvoiced/{1296674173.yml → 1297746103.yml} +49 -46
  50. data/spec/vcr/charge/list-all/{1296674173.yml → 1297746103.yml} +61 -58
  51. data/spec/vcr/charge/list-invoiced/{1296674173.yml → 1297746103.yml} +92 -89
  52. data/spec/vcr/charge/list-pending/{1296674173.yml → 1297746103.yml} +61 -58
  53. data/spec/vcr/charge/lookup/{1296674173.yml → 1297746103.yml} +34 -31
  54. data/spec/vcr/coupon/create/{1296774903.yml → 1299714521.yml} +35 -32
  55. data/spec/vcr/coupon/destroy/{1296688818.yml → 1299714521.yml} +34 -31
  56. data/spec/vcr/{coupon/create/1296688818.yml → credit/create/1299714599.yml} +53 -53
  57. data/spec/vcr/credit/delete/1299714599.yml +262 -0
  58. data/spec/vcr/credit/list/1299714599.yml +319 -0
  59. data/spec/vcr/credit/lookup/1299714599.yml +183 -0
  60. data/spec/vcr/invoice/create-no-charges/{1296674173.yml → 1297746103.yml} +34 -31
  61. data/spec/vcr/invoice/create/{1296674173.yml → 1297746103.yml} +63 -60
  62. data/spec/vcr/invoice/list/{1296674173.yml → 1297746103.yml} +87 -84
  63. data/spec/vcr/invoice/lookup/{1296674173.yml → 1297746103.yml} +64 -61
  64. data/spec/vcr/plan/all.yml +30 -30
  65. data/spec/vcr/plan/find.yml +25 -25
  66. data/spec/vcr/plan/update.yml +16 -15
  67. data/spec/vcr/subscription/addons/add/{1296674173.yml → 1297746103.yml} +44 -40
  68. data/spec/vcr/subscription/addons/create/{1296674173.yml → 1297746103.yml} +44 -40
  69. data/spec/vcr/subscription/addons/remove/{1296674173.yml → 1297746103.yml} +44 -40
  70. data/spec/vcr/subscription/cancel-with-code/{1296674173.yml → 1297746103.yml} +99 -95
  71. data/spec/vcr/subscription/cancel/{1296674173.yml → 1297746103.yml} +86 -82
  72. data/spec/vcr/subscription/change1/{1296674173.yml → 1297746103.yml} +82 -78
  73. data/spec/vcr/subscription/change2/{1296674173.yml → 1297746103.yml} +82 -78
  74. data/spec/vcr/subscription/create/{1296674173.yml → 1297746103.yml} +49 -45
  75. data/spec/vcr/subscription/find/{1296674173.yml → 1297746103.yml} +60 -56
  76. data/spec/vcr/subscription/reactivate/{1296674173.yml → 1297746103.yml} +93 -89
  77. data/spec/vcr/subscription/refund-full/{1296674173.yml → 1297746103.yml} +77 -73
  78. data/spec/vcr/subscription/refund-none/{1296674173.yml → 1297746103.yml} +77 -73
  79. data/spec/vcr/subscription/refund-partial/{1296674173.yml → 1297746103.yml} +77 -73
  80. data/spec/vcr/transaction/all/{1296674173.yml → 1297746103.yml} +107 -107
  81. data/spec/vcr/transaction/create-no-account/{1296674173.yml → 1297746103.yml} +14 -13
  82. data/spec/vcr/transaction/create-with-account/{1296674173.yml → 1297746103.yml} +46 -58
  83. data/spec/vcr/transaction/list-filled/1297746103.yml +213 -0
  84. data/spec/vcr/transaction/list-initial/{1296674173.yml → 1297746103.yml} +38 -35
  85. data/spec/vcr/transaction/lookup/1297746103.yml +213 -0
  86. data/spec/vcr/transaction/refund/1297746103.yml +213 -0
  87. data/spec/vcr/transaction/void/1297746103.yml +213 -0
  88. metadata +146 -139
  89. data/spec/vcr/account/list/1296674173.yml +0 -55
  90. data/spec/vcr/coupon/destroy/1296774903.yml +0 -207
  91. data/spec/vcr/credit/create/1296674173.yml +0 -121
  92. data/spec/vcr/credit/delete/1296674173.yml +0 -121
  93. data/spec/vcr/credit/list/1296674173.yml +0 -121
  94. data/spec/vcr/credit/lookup/1296674173.yml +0 -121
  95. data/spec/vcr/plan/delete/1296674173.yml +0 -225
  96. data/spec/vcr/transaction/list-filled/1296674173.yml +0 -487
  97. data/spec/vcr/transaction/lookup/1296674173.yml +0 -563
  98. data/spec/vcr/transaction/refund/1296674173.yml +0 -287
  99. data/spec/vcr/transaction/void/1296674173.yml +0 -352
@@ -0,0 +1,19 @@
1
+ module Recurly
2
+ class RecurlyError < StandardError; end
3
+
4
+ class ConfigurationError < RecurlyError; end
5
+
6
+ # Query string has been tampered with and cannot be trusted.
7
+ class ForgedQueryString < RecurlyError; end
8
+
9
+ # Transparent Post -- validations failed or transaction failed. See the {model} for errors.
10
+ class ValidationsFailed < RecurlyError
11
+ attr_reader :model
12
+
13
+ def initialize(model)
14
+ @model = model
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -1,5 +1,5 @@
1
1
  module Recurly
2
- class Invoice < RecurlyBase
2
+ class Invoice < Base
3
3
  self.element_name = "invoice"
4
4
  self.prefix = "/accounts/:account_code/"
5
5
 
data/lib/recurly/plan.rb CHANGED
@@ -1,7 +1,19 @@
1
1
  module Recurly
2
- class Plan < RecurlyBase
2
+ class Plan < Base
3
3
  self.element_name = "plan"
4
4
  self.prefix = "/company/"
5
5
  self.primary_key = :plan_code
6
+
7
+ def self.known_attributes
8
+ [
9
+ "plan_code",
10
+ "name",
11
+ "description",
12
+ "success_url",
13
+ "cancel_url",
14
+ "created_at"
15
+ ]
16
+ end
17
+
6
18
  end
7
19
  end
@@ -38,7 +38,7 @@ namespace :recurly do
38
38
 
39
39
  # now lets clear site data
40
40
  begin
41
- RestClient.post( @recurly_config["site"]+"/site/test_data",
41
+ RestClient.post( Recurly::Base.site+"/site/test_data",
42
42
  {"_method"=>"delete"},
43
43
  :cookies => login_response.cookies)
44
44
  raise "Clearing Didn't work for some reason. Is your site setting correct?"
@@ -49,8 +49,10 @@ namespace :recurly do
49
49
 
50
50
  def setup_static
51
51
  @recurly_config["username"] ||= "myemail@mydomain.com"
52
- @recurly_config["password"] ||= "mypassword"
53
- @recurly_config["site"] ||= "https://my-site.recurly.com"
52
+ @recurly_config["password"] ||= "my_api_key"
53
+ @recurly_config["private_key"] ||= "my_private_key"
54
+ @recurly_config["subdomain"] ||= "mysite"
55
+ @recurly_config["site"] ||= "https://api-production.recurly.com"
54
56
  end
55
57
 
56
58
  desc "Creates a recurly.yml config file"
@@ -1,7 +1,25 @@
1
1
  module Recurly
2
- class Subscription < RecurlyAccountBase
2
+ class Subscription < AccountBase
3
3
  self.element_name = "subscription"
4
4
 
5
+ def self.known_attributes
6
+ [
7
+ "plan_code",
8
+ "coupon_code",
9
+ "unit_amount",
10
+ "quantity",
11
+ "trial_ends_at"
12
+ ]
13
+ end
14
+
15
+ # initialize associations
16
+ def initialize(attributes = {})
17
+ attributes = attributes.with_indifferent_access
18
+ attributes[:account] ||= {}
19
+ attributes[:addons] ||= []
20
+ super(attributes)
21
+ end
22
+
5
23
  def self.refund(account_code, refund_type = :partial)
6
24
  raise "Refund type must be :full, :partial, or :none." unless [:full, :partial, :none].include?(refund_type)
7
25
  Subscription.delete(nil, {:account_code => account_code, :refund => refund_type})
@@ -39,7 +57,7 @@ module Recurly
39
57
  # Valid timeframe: :now or :renewal
40
58
  # Valid options: plan_code, quantity, unit_amount
41
59
  def change(timeframe, options = {})
42
- raise "Timeframe must be :full or :renewal." unless timeframe == 'now' or timeframe == 'renewal'
60
+ raise "Timeframe must be :full or :renewal." unless ['now','renewal'].include?(timeframe)
43
61
  options[:timeframe] = timeframe
44
62
  path = "/accounts/#{CGI::escape(self.subscription_account_code.to_s)}/subscription.xml"
45
63
  connection.put(path,
@@ -52,7 +70,7 @@ module Recurly
52
70
  acct_code ||= account.account_code if defined?(account) and !account.nil?
53
71
  acct_code ||= self.primary_key if defined?(self.primary_key)
54
72
  acct_code ||= self.id if defined?(self.id)
55
- raise 'Missing Account Code' if acct_code.nil? or acct_code.blank?
73
+ raise 'Missing Account Code' if acct_code.blank?
56
74
  acct_code
57
75
  end
58
76
  end
@@ -1,7 +1,35 @@
1
1
  module Recurly
2
- class Transaction < RecurlyBase
2
+ class Transaction < Base
3
3
  self.element_name = "transaction"
4
4
 
5
+ def self.known_attributes
6
+ [
7
+ "description",
8
+ "amount_in_cents",
9
+ "account_code",
10
+ "type",
11
+ "action",
12
+ "date",
13
+ "status",
14
+ "message",
15
+ "reference",
16
+ "ccv_result",
17
+ "avs_result",
18
+ "avs_result_street",
19
+ "avs_result_postal",
20
+ "test",
21
+ "voidable",
22
+ "refundable"
23
+ ]
24
+ end
25
+
26
+ # initialize fields with blank data
27
+ def initialize(attributes = {})
28
+ # initialize embedded attributes
29
+ attributes = attributes.with_indifferent_access
30
+ attributes[:account] ||= {}
31
+ super(attributes)
32
+ end
5
33
 
6
34
  def self.list(status = :all)
7
35
 
@@ -0,0 +1,140 @@
1
+ module Recurly
2
+
3
+ module Action
4
+ CreateSubscription = "subscription"
5
+ UpdateBilling = "billing_info"
6
+ CreateTransaction = "transaction"
7
+ end
8
+
9
+ class Transparent
10
+ attr_accessor :data
11
+
12
+ def initialize(data = {})
13
+ @data = data || {}
14
+ end
15
+
16
+ # output the transparent data as a hidden field
17
+ def hidden_field
18
+ html = %{<input type="hidden" name="data" value="#{ERB::Util.html_escape(encoded_data)}" />}
19
+
20
+ if html.respond_to?(:html_safe)
21
+ html.html_safe
22
+ else
23
+ html
24
+ end
25
+ end
26
+
27
+ # output transparent data along with a verification string to prevent tampering of data
28
+ def encoded_data
29
+ verify_required_fields
30
+
31
+ # convert data to a query string
32
+ query_data = self.class.query_string(data)
33
+
34
+ # generate a validation string by encrypting the string using the private key
35
+ validation_string = self.class.encrypt_string(query_data)
36
+
37
+ # return the validation and query data
38
+ "#{validation_string}|#{query_data}"
39
+ end
40
+
41
+ # verify that certain fields are present (or else the transparent post wont work)
42
+ def verify_required_fields
43
+ # make sure there's a redirect_url defined
44
+ unless @data.has_key?(:redirect_url)
45
+ raise "A :redirect_url key must be defined for Transparent posts"
46
+ end
47
+ unless @data.has_key?(:account)
48
+ raise "An :account key must be defined for Transparent posts"
49
+ end
50
+ unless @data[:account].has_key?(:account_code)
51
+ raise "An :account[:account_code] key must be defined for Transparent posts"
52
+ end
53
+
54
+ return true
55
+ end
56
+
57
+ # convert data into query string
58
+ def self.query_string(data = {})
59
+ # process data
60
+ data = process_data(data.dup)
61
+ data[:time] = Time.now.utc.strftime("%d/%b/%Y %H:%M:%S %Z")
62
+
63
+ address = Addressable::URI.new
64
+ address.query_values = data
65
+ address.query
66
+ end
67
+
68
+ # returns the url to post to
69
+ def self.url(action = nil)
70
+ raise Recurly::ConfigurationError.new("Recurly gem not configured. run `rake recurly:setup`") unless Recurly.configured?
71
+ raise Recurly::ConfigurationError.new("Recurly gem not configured. 'private_key' missing.") if Recurly.private_key.blank?
72
+ raise Recurly::ConfigurationError.new("Recurly gem not configured. 'subdomain' missing.") if Recurly.subdomain.blank?
73
+
74
+ # default action to create new subscription
75
+ action ||= Action::CreateSubscription
76
+
77
+ "#{Recurly::Base.site}/transparent/#{Recurly.subdomain}/#{action}"
78
+ end
79
+
80
+ def self.create_subscription_url
81
+ url(Action::CreateSubscription)
82
+ end
83
+
84
+ def self.create_transaction_url
85
+ url(Action::CreateTransaction)
86
+ end
87
+
88
+ def self.update_billing_url
89
+ url(Action::UpdateBilling)
90
+ end
91
+
92
+ # returns the results via a code
93
+ def self.results(params)
94
+ # pull out the result key and status
95
+ type = params["type"]
96
+ result_key = params["result"]
97
+ status = params["status"]
98
+
99
+ # verify confirmation matches the passed in querystring
100
+ address = Addressable::URI.new
101
+ address.query_values = {:type => type.to_s, :status => status.to_s, :result => result_key.to_s}
102
+ raise Recurly::ForgedQueryString.new if params["confirm"] != encrypt_string(address.query)
103
+
104
+ # pull the class name
105
+ model = Recurly.const_get(type.to_s.classify)
106
+
107
+ response = nil
108
+ begin
109
+ # rebuild the ActiveResource object from the xml results
110
+ response = Recurly::Base.connection.get_raw("/transparent/results/#{result_key}", model.headers)
111
+ return model.new.from_transparent_results(response)
112
+
113
+ rescue ActiveResource::ResourceInvalid => ex
114
+ model_result = model.new.from_transparent_results(ex.response)
115
+ raise Recurly::ValidationsFailed.new(model_result)
116
+ end
117
+ end
118
+
119
+ # encode a string using the configured private key
120
+ def self.encrypt_string(input_string)
121
+ raise Recurly::ConfigurationError.new("Recurly gem not configured. To use transparent redirects, set your private_key within config/recurly.yml to the private_key provided by recurly.com") unless Recurly.private_key.present?
122
+ digest_key = ::Digest::SHA1.digest(Recurly.private_key)
123
+ sha1_hash = ::OpenSSL::Digest::Digest.new("sha1")
124
+ ::OpenSSL::HMAC.hexdigest(sha1_hash, digest_key, input_string.to_s)
125
+ end
126
+
127
+ # recursively process the query data (running to_s on values)
128
+ def self.process_data(data = {})
129
+ data.each do |key, val|
130
+ if val.is_a?(Hash)
131
+ data[key] = process_data(val)
132
+ elsif val.is_a?(Enumerable)
133
+ data[key] = val.map{|i| i.to_s}
134
+ else
135
+ data[key] = val.to_s
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -1,3 +1,3 @@
1
1
  module Recurly #:nodoc
2
- VERSION = "0.3.3"
2
+ VERSION = "0.3.4"
3
3
  end
@@ -0,0 +1,12 @@
1
+ ---
2
+ username: api-test-123@litle.com
3
+ password: 82a98ee0c1c2495789775177babfadb7
4
+ private_key: 986bfa2bec61479ca560dbaaec345820
5
+ subdomain: litle-test
6
+ environment: :development
7
+
8
+ #username: api-test@isaactest.com
9
+ #password: e94fb95953454b1dad4abf26af382a5d
10
+ #private_key: 2b656f0351e345faa1d29b2d7a455202
11
+ #subdomain: isaachall-test
12
+ #environment: :sandbox
@@ -1,4 +1,6 @@
1
1
  ---
2
2
  username: username1@recurly.com
3
- site: https://site1.recurly.com
4
3
  password: asdf4jk31
4
+ subdomain: site1
5
+ private_key: asdfasdfasdf
6
+ environment: :production
@@ -1,9 +1,11 @@
1
1
  development:
2
2
  username: username1@recurly.com
3
- site: https://site1.recurly.com
4
3
  password: asdf4jk31
4
+ subdomain: site1
5
+ environment: :sandbox
5
6
 
6
7
  test:
7
8
  username: username2@recurly.com
8
- site: https://site2.recurly.com
9
9
  password: asdf4jk32
10
+ subdomain: site2
11
+ environment: :production
@@ -12,7 +12,7 @@ module Recurly
12
12
 
13
13
  before(:each) do
14
14
  credit = Factory.create_credit account.account_code,
15
- :amount => 10.05,
15
+ :amount_in_cents => 1005,
16
16
  :description => "free moniez"
17
17
 
18
18
  @credit = Credit.lookup(account.account_code, credit.id)
@@ -36,9 +36,9 @@ module Recurly
36
36
  let(:account){ Factory.create_account("credit-list-#{timestamp}") }
37
37
 
38
38
  before(:each) do
39
- Factory.create_credit(account.account_code, :amount => 1, :description => "one")
40
- Factory.create_credit(account.account_code, :amount => 2, :description => "two")
41
- Factory.create_credit(account.account_code, :amount => 3, :description => "three")
39
+ Factory.create_credit(account.account_code, :amount_in_cents => 100, :description => "one")
40
+ Factory.create_credit(account.account_code, :amount_in_cents => 200, :description => "two")
41
+ Factory.create_credit(account.account_code, :amount_in_cents => 300, :description => "three")
42
42
  @credits = Credit.list(account.account_code)
43
43
  end
44
44
 
@@ -65,7 +65,7 @@ module Recurly
65
65
 
66
66
  before(:each) do
67
67
  credit = Factory.create_credit account.account_code,
68
- :amount => 13.15,
68
+ :amount_in_cents => 1315,
69
69
  :description => "free moniez 4 u"
70
70
  @credit = Credit.lookup(account.account_code, credit.id)
71
71
  end
@@ -89,7 +89,7 @@ module Recurly
89
89
 
90
90
  before(:each) do
91
91
  credit = Factory.create_credit account.account_code,
92
- :amount => 13.15,
92
+ :amount_in_cents => 1315,
93
93
  :description => "free moniez 4 u"
94
94
  @credit = Credit.lookup(account.account_code, credit.id)
95
95
 
@@ -64,7 +64,7 @@ module Recurly
64
64
  Plan.new({
65
65
  :plan_code => "test",
66
66
  :name => "Test Plan",
67
- :unit_amount_in_cents => 100,
67
+ :amount_in_cents => 100,
68
68
  :plan_interval_length => 1,
69
69
  :plan_interval_unit => "months",
70
70
  :trial_interval_length => 0,
@@ -75,7 +75,7 @@ module Recurly
75
75
  end
76
76
 
77
77
  it "should update the plan" do
78
- @test_plan.unit_amount_in_cents = 200
78
+ @test_plan.amount_in_cents = 200
79
79
  @test_plan.save!
80
80
 
81
81
  @test_plan = test_plan
@@ -45,6 +45,8 @@ module Recurly
45
45
  # returns a hash of billing information
46
46
  def self.billing_attributes(address_overrides = {}, credit_card_overrides = {})
47
47
  attributes = {
48
+ :first_name => 'Verena',
49
+ :last_name => 'Test',
48
50
  :address1 => '123 Test St',
49
51
  :city => 'San Francisco',
50
52
  :state => 'CA',
@@ -153,7 +155,7 @@ module Recurly
153
155
  def self.create_credit(account_code, attributes = {})
154
156
  credit = Credit.new({
155
157
  :account_code => account_code,
156
- :amount => 10.00,
158
+ :amount_in_cents => 1000,
157
159
  :description => "free moniez"
158
160
  }.merge(attributes))
159
161
  credit.save!
@@ -166,7 +168,7 @@ module Recurly
166
168
  :name => "Trial",
167
169
 
168
170
  # 10 dollars a month
169
- :unit_amount_in_cents => 1000,
171
+ :amount_in_cents => 1000,
170
172
 
171
173
  # 1 month intervals
172
174
  :plan_interval_length => 1,
@@ -184,7 +186,7 @@ module Recurly
184
186
  :name => "Paid",
185
187
 
186
188
  # 10 dollars a month
187
- :unit_amount_in_cents => 1000,
189
+ :amount_in_cents => 1000,
188
190
 
189
191
  # 1 month intervals
190
192
  :plan_interval_length => 1,
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ module Recurly
4
+ describe Account do
5
+ context "new record" do
6
+ subject{Account.new}
7
+
8
+ it { should respond_to(:account_code)}
9
+ it { should respond_to(:username)}
10
+ it { should respond_to(:first_name)}
11
+ it { should respond_to(:last_name)}
12
+ it { should respond_to(:email)}
13
+ it { should respond_to(:company_name)}
14
+ it { should respond_to(:hosted_login_token)}
15
+ it { should respond_to(:accept_language)}
16
+ end
17
+
18
+ end
19
+ end