fake_braintree 0.2.1 → 0.3

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml CHANGED
@@ -3,3 +3,6 @@ rvm:
3
3
  - 1.8.7
4
4
  - 1.9.2
5
5
  - 1.9.3
6
+ branches:
7
+ only:
8
+ - master
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source 'http://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in fake_braintree.gemspec
4
4
  gemspec
data/LICENSE CHANGED
@@ -1,9 +1,8 @@
1
-
2
1
  LICENSE
3
2
 
4
3
  The MIT License
5
4
 
6
- Copyright (c) 2011-2012 thoughtbot, inc.
5
+ Copyright (c) 2011-2013 thoughtbot, inc.
7
6
 
8
7
  Permission is hereby granted, free of charge, to any person obtaining a copy
9
8
  of this software and associated documentation files (the "Software"), to deal
@@ -22,5 +21,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
21
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
22
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
23
  THE SOFTWARE.
25
-
26
-
data/NEWS.md ADDED
@@ -0,0 +1,62 @@
1
+ # 0.3
2
+
3
+ * Braintree::Transaction.void updates the existing sale transaction instead of
4
+ creating a new transaction of type Braintree::Transaction::Status::Voided
5
+
6
+ * Preserve `redirect_url` query parameters for transparent redirect (#36)
7
+
8
+ * Transactions can be submitted for settlement by passing an options hash to
9
+ Braintree::Transaction.create as shown in the [Braintree documentation](https://www.braintreepayments.com/docs/ruby/transactions/create#full_example) (#31)
10
+
11
+ * When a customer is created with a credit card
12
+ (`Braintree::Customer.create(:credit_card => ...`), that credit card is set as
13
+ the customer's default card.
14
+
15
+ # 0.2.1
16
+ * Fake refunds via `Braintree::Transaction.refund` and
17
+ `Braintree::CreditCard.refund`.
18
+ * Create credit cards via `Braintree::CreditCard.create(:token => token,
19
+ :number => TEST_CC_NUMBER)`
20
+ * Depend on Thin instead of Mongrel (fixes NotImplementedError).
21
+
22
+ # 0.2.0
23
+ * Generated transactions (from `FakeBraintree.generate_transaction`) now include
24
+ the amount.
25
+ * `Braintree::Customer.update` will reject updates that contain credit cards that
26
+ have been marked as a failure in the registry.
27
+
28
+ # 0.1.1
29
+ * `Braintree::CreditCard.update` now works
30
+
31
+ # 0.1.0
32
+ * `FakeBraintree.{customers, transactions, failures, subscriptions, redirects}`
33
+ are now accessed via `FakeBraintree.registry`. For example,
34
+ `FakeBraintree.customers` is now `FakeBraintree.registry.customers`
35
+ * `FakeBraintree.credit_card_from_token` is now `FakeBraintree.registry.credit_card_from_token`
36
+ * The server code (it intercepts calls to Braintree) now lives in FakeBraintree::Server
37
+ * `Braintree::Customer.create` will use the provided customer ID instead of
38
+ overwriting it (#15).
39
+ * `Braintree::Subscription.cancel` now works
40
+
41
+ # 0.0.6
42
+ * Flesh out the README
43
+ * Add support for transparent redirect
44
+ * Add basic support for adding add-ons
45
+ * Add basic support for adding discounts
46
+ * Add support for `Braintree::Customer.update`
47
+ * Add support for `Braintree::Customer.delete`
48
+ * Add support for `Braintree::Subscription.delete`
49
+ * Lots of internal refactorings
50
+
51
+ # 0.0.5
52
+ * Add support for `Braintree::Customer.find`
53
+
54
+ # 0.0.4
55
+ * Allow for very basic card verification
56
+
57
+ # 0.0.3
58
+ * Ensure `FakeBraintree.log_file_path` directory exists
59
+ * The `FakeBraintree.log_file_path` attribute can now be read (it could only be set before)
60
+ * Clear log when `FakeBraintree.clear!` is called
61
+ * Correctly handle nonexistent subscriptions when using
62
+ `Braintree::Subscription.find`
data/README.md CHANGED
@@ -33,6 +33,8 @@ of them (yet).
33
33
 
34
34
  ### Transaction
35
35
  * `Braintree::Transaction.sale`
36
+ * `Braintree::Transaction.refund`
37
+ * `Braintree::Transaction.void`
36
38
 
37
39
  ### TransparentRedirect
38
40
  * `Braintree::TransparentRedirect.url`
@@ -172,4 +174,4 @@ The names and logos for thoughtbot are trademarks of thoughtbot, inc.
172
174
  License
173
175
  -------
174
176
 
175
- Fake Braintree is Copyright © 2011-2012 thoughtbot. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
177
+ Fake Braintree is Copyright © 2011-2013 thoughtbot. It is free software, and may be redistributed under the terms specified in the MIT-LICENSE file.
data/Rakefile CHANGED
@@ -1,8 +1,8 @@
1
- require "bundler/setup"
2
- require "bundler/gem_tasks"
3
- require "rspec/core/rake_task"
1
+ require 'bundler/setup'
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
4
 
5
5
  RSpec::Core::RakeTask.new(:spec)
6
6
 
7
- desc "Run specs"
7
+ desc 'Run specs'
8
8
  task :default => [:spec]
@@ -1,20 +1,20 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "fake_braintree/version"
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'fake_braintree/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
- s.name = "fake_braintree"
6
+ s.name = 'fake_braintree'
7
7
  s.version = FakeBraintree::VERSION
8
- s.authors = ["thoughtbot, inc."]
9
- s.email = ["gabe@thoughtbot.com", "ben@thoughtbot.com"]
10
- s.homepage = ""
8
+ s.authors = ['thoughtbot, inc.']
9
+ s.email = ['gabe@thoughtbot.com', 'ben@thoughtbot.com']
10
+ s.homepage = ''
11
11
  s.summary = %q{A fake Braintree that you can run integration tests against}
12
12
  s.description = %q{A fake Braintree that you can run integration tests against}
13
13
 
14
14
  s.files = `git ls-files`.split("\n")
15
15
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
16
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
- s.require_paths = ["lib"]
17
+ s.require_paths = ['lib']
18
18
 
19
19
  s.add_dependency 'capybara'
20
20
  s.add_dependency 'activesupport'
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency 'braintree', '~> 2.5'
24
24
  s.add_dependency 'thin'
25
25
 
26
- s.add_development_dependency 'rspec', '~> 2.6.0'
26
+ s.add_development_dependency 'rspec', '~> 2.12.0'
27
27
  s.add_development_dependency 'bourne', '~> 1.0'
28
28
  s.add_development_dependency 'timecop', '~> 0.3.5'
29
29
  s.add_development_dependency 'spork', '~> 0.9.0.rc9'
@@ -46,26 +46,32 @@ module FakeBraintree
46
46
 
47
47
  def self.failure_response(card_number = nil)
48
48
  failure = registry.failures[card_number] || {}
49
- failure["errors"] ||= { "errors" => [] }
50
-
51
- { "message" => failure["message"],
52
- "verification" => { "status" => failure["status"],
53
- "processor_response_text" => failure["message"],
54
- "processor_response_code" => failure["code"],
55
- "gateway_rejection_reason" => "cvv",
56
- "cvv_response_code" => failure["code"] },
57
- "errors" => failure["errors"],
58
- "params" => {}}
49
+ failure['errors'] ||= { 'errors' => [] }
50
+
51
+ {
52
+ 'message' => failure['message'],
53
+ 'verification' => {
54
+ 'status' => failure['status'],
55
+ 'processor_response_text' => failure['message'],
56
+ 'processor_response_code' => failure['code'],
57
+ 'gateway_rejection_reason' => 'cvv',
58
+ 'cvv_response_code' => failure['code']
59
+ },
60
+ 'errors' => failure['errors'],
61
+ 'params' => {}
62
+ }
59
63
  end
60
64
 
61
65
  def self.create_failure
62
66
  {
63
- "message" => "Do Not Honor",
64
- "verification" => { "status" => "processor_declined",
65
- "processor_response_text" => "Do Not Honor",
66
- "processor_response_code" => '2000' },
67
- "errors" => { 'errors' => [] },
68
- "params" => {}
67
+ 'message' => 'Do Not Honor',
68
+ 'verification' => {
69
+ 'status' => 'processor_declined',
70
+ 'processor_response_text' => 'Do Not Honor',
71
+ 'processor_response_code' => '2000'
72
+ },
73
+ 'errors' => { 'errors' => [] },
74
+ 'params' => {}
69
75
  }
70
76
  end
71
77
 
@@ -82,23 +88,27 @@ module FakeBraintree
82
88
  end
83
89
 
84
90
  def self.generate_transaction(options = {})
85
- history_item = { 'timestamp' => Time.now,
86
- 'amount' => options[:amount],
87
- 'status' => options[:status] }
91
+ history_item = {
92
+ 'timestamp' => Time.now,
93
+ 'amount' => options[:amount],
94
+ 'status' => options[:status]
95
+ }
88
96
  created_at = options[:created_at] || Time.now
89
- {'status_history' => [history_item],
90
- 'subscription_id' => options[:subscription_id],
91
- 'created_at' => created_at,
92
- 'amount' => options[:amount] }
97
+ {
98
+ 'status_history' => [history_item],
99
+ 'subscription_id' => options[:subscription_id],
100
+ 'created_at' => created_at,
101
+ 'amount' => options[:amount]
102
+ }
93
103
  end
94
104
 
95
105
  private
96
106
 
97
107
  def self.set_configuration
98
108
  Braintree::Configuration.environment = :development
99
- Braintree::Configuration.merchant_id = "xxx"
100
- Braintree::Configuration.public_key = "xxx"
101
- Braintree::Configuration.private_key = "xxx"
109
+ Braintree::Configuration.merchant_id = 'xxx'
110
+ Braintree::Configuration.public_key = 'xxx'
111
+ Braintree::Configuration.private_key = 'xxx'
102
112
  end
103
113
 
104
114
  def self.boot_server
@@ -7,6 +7,22 @@ module FakeBraintree
7
7
  set_expiration_month_and_year
8
8
  end
9
9
 
10
+ def create
11
+ if valid_number?
12
+ if token.nil?
13
+ @hash['token'] = generate_token
14
+ end
15
+ FakeBraintree.registry.credit_cards[token] = @hash
16
+ if customer = FakeBraintree.registry.customers[@hash['customer_id']]
17
+ customer['credit_cards'] << @hash
18
+ update_default_card
19
+ end
20
+ response_for_updated_card
21
+ else
22
+ response_for_invalid_card
23
+ end
24
+ end
25
+
10
26
  def update
11
27
  if credit_card_exists_in_registry?
12
28
  update_existing_credit_card
@@ -20,10 +36,32 @@ module FakeBraintree
20
36
  @hash.to_xml(:root => 'credit_card')
21
37
  end
22
38
 
39
+ def valid_number?
40
+ if FakeBraintree.decline_all_cards?
41
+ false
42
+ elsif FakeBraintree.verify_all_cards
43
+ FakeBraintree::VALID_CREDIT_CARDS.include?(@hash['number'])
44
+ else
45
+ true
46
+ end
47
+ end
48
+
23
49
  private
24
50
 
25
51
  def update_existing_credit_card
26
52
  @hash = credit_card_from_registry.merge!(@hash)
53
+ update_default_card
54
+ end
55
+
56
+ # When updating a card that has 'default' set to true, make sure
57
+ # only one card has the flag.
58
+ def update_default_card
59
+ if @hash['default']
60
+ FakeBraintree.registry.customers[@hash['customer_id']]['credit_cards'].each do |card|
61
+ card['default'] = false
62
+ end
63
+ @hash['default'] = true
64
+ end
27
65
  end
28
66
 
29
67
  def response_for_updated_card
@@ -42,6 +80,13 @@ module FakeBraintree
42
80
  gzipped_response(404, FakeBraintree.failure_response.to_xml(:root => 'api_error_response'))
43
81
  end
44
82
 
83
+ def response_for_invalid_card
84
+ gzipped_response(422, FakeBraintree.failure_response.merge(
85
+ 'params' => {:credit_card => @hash}
86
+ ).
87
+ to_xml(:root => 'api_error_response'))
88
+ end
89
+
45
90
  def expiration_month
46
91
  expiration_date_parts[0]
47
92
  end
@@ -52,28 +97,34 @@ module FakeBraintree
52
97
 
53
98
  def set_up_credit_card(credit_card_hash_from_params, options)
54
99
  @hash = {
55
- "token" => options[:token],
56
- "merchant_id" => options[:merchant_id]
100
+ 'token' => options[:token],
101
+ 'merchant_id' => options[:merchant_id],
102
+ 'customer_id' => options[:customer_id],
103
+ 'default' => options[:make_default]
57
104
  }.merge(credit_card_hash_from_params)
58
105
  end
59
106
 
60
107
  def set_expiration_month_and_year
61
108
  if expiration_month
62
- @hash["expiration_month"] = expiration_month
109
+ @hash['expiration_month'] = expiration_month
63
110
  end
64
111
 
65
112
  if expiration_year
66
- @hash["expiration_year"] = expiration_year
113
+ @hash['expiration_year'] = expiration_year
67
114
  end
68
115
  end
69
116
 
117
+ def generate_token
118
+ md5("#{@hash['number']}#{@hash['merchant_id']}")
119
+ end
120
+
70
121
  def token
71
122
  @hash['token']
72
123
  end
73
124
 
74
125
  def expiration_date_parts
75
- if @hash.key?("expiration_date")
76
- @hash["expiration_date"].split('/')
126
+ if @hash.key?('expiration_date')
127
+ @hash['expiration_date'].split('/')
77
128
  else
78
129
  []
79
130
  end
@@ -4,10 +4,10 @@ module FakeBraintree
4
4
 
5
5
  def initialize(customer_hash_from_params, options)
6
6
  @customer_hash = {
7
- "id" => options[:id],
8
- "merchant_id" => options[:merchant_id]
9
- }.merge(customer_hash_from_params)
10
-
7
+ 'id' => options[:id],
8
+ 'merchant_id' => options[:merchant_id]
9
+ }
10
+ @customer_hash.merge!(customer_hash_from_params)
11
11
  set_customer_id
12
12
  end
13
13
 
@@ -15,9 +15,10 @@ module FakeBraintree
15
15
  if invalid?
16
16
  response_for_invalid_card
17
17
  else
18
- credit_cards = customer_hash["credit_cards"]
18
+ credit_cards = customer_hash['credit_cards']
19
19
  create_customer_with(customer_hash)
20
20
  credit_cards.each { |card| add_credit_card_to_registry(card) }
21
+ set_default_credit_card credit_cards.first
21
22
  response_for_created_customer(customer_hash)
22
23
  end
23
24
  end
@@ -48,11 +49,11 @@ module FakeBraintree
48
49
  end
49
50
 
50
51
  def create_customer_with(hash)
51
- FakeBraintree.registry.customers[hash["id"]] = hash
52
+ FakeBraintree.registry.customers[hash['id']] = hash
52
53
  end
53
54
 
54
55
  def add_credit_card_to_registry(new_credit_card_hash)
55
- token = new_credit_card_hash["token"]
56
+ token = new_credit_card_hash['token']
56
57
  FakeBraintree.registry.credit_cards[token] = new_credit_card_hash
57
58
  end
58
59
 
@@ -61,7 +62,7 @@ module FakeBraintree
61
62
  end
62
63
 
63
64
  def customer_hash
64
- @customer_hash.merge("credit_cards" => generate_credit_cards_from(@customer_hash["credit_card"]))
65
+ @customer_hash.merge('credit_cards' => generate_credit_cards_from(@customer_hash['credit_card']))
65
66
  end
66
67
 
67
68
  def customer_from_registry
@@ -83,11 +84,11 @@ module FakeBraintree
83
84
  def verify_credit_card?(customer_hash_for_verification)
84
85
  return true if FakeBraintree.verify_all_cards
85
86
 
86
- credit_card_hash_for_verification = customer_hash_for_verification["credit_card"]
87
+ credit_card_hash_for_verification = customer_hash_for_verification['credit_card']
87
88
  if credit_card_hash_for_verification.is_a?(Hash) &&
88
- credit_card_hash_for_verification.key?("options")
89
- options = credit_card_hash_for_verification["options"]
90
- options["verify_card"] == true
89
+ credit_card_hash_for_verification.key?('options')
90
+ options = credit_card_hash_for_verification['options']
91
+ options['verify_card'] == true
91
92
  end
92
93
  end
93
94
 
@@ -97,20 +98,27 @@ module FakeBraintree
97
98
  end
98
99
 
99
100
  def credit_card_number
100
- credit_card_hash["number"]
101
+ credit_card_hash['number']
102
+ end
103
+
104
+ def set_default_credit_card(credit_card_hash)
105
+ if credit_card_hash
106
+ CreditCard.new(credit_card_hash, :customer_id => @customer_hash['id'], :make_default => true).update
107
+ end
101
108
  end
102
109
 
103
110
  def generate_credit_cards_from(new_credit_card_hash)
104
111
  if new_credit_card_hash.present? && new_credit_card_hash.is_a?(Hash)
105
- new_credit_card_hash["last_4"] = new_credit_card_hash["number"][-4..-1]
106
- new_credit_card_hash["token"] = credit_card_token(new_credit_card_hash)
112
+ new_credit_card_hash['bin'] = new_credit_card_hash['number'][0..5]
113
+ new_credit_card_hash['last_4'] = new_credit_card_hash['number'][-4..-1]
114
+ new_credit_card_hash['token'] = credit_card_token(new_credit_card_hash)
107
115
 
108
116
  if credit_card_expiration_month
109
- new_credit_card_hash["expiration_month"] = credit_card_expiration_month
117
+ new_credit_card_hash['expiration_month'] = credit_card_expiration_month
110
118
  end
111
119
 
112
120
  if credit_card_expiration_year
113
- new_credit_card_hash["expiration_year"] = credit_card_expiration_year
121
+ new_credit_card_hash['expiration_year'] = credit_card_expiration_year
114
122
  end
115
123
 
116
124
  [new_credit_card_hash]
@@ -128,8 +136,8 @@ module FakeBraintree
128
136
  end
129
137
 
130
138
  def credit_card_expiration_date
131
- if credit_card_hash.key?("expiration_date")
132
- credit_card_hash["expiration_date"].split('/')
139
+ if credit_card_hash.key?('expiration_date')
140
+ credit_card_hash['expiration_date'].split('/')
133
141
  else
134
142
  []
135
143
  end
@@ -164,7 +172,7 @@ module FakeBraintree
164
172
  end
165
173
 
166
174
  def customer_id
167
- customer_hash["id"]
175
+ customer_hash['id']
168
176
  end
169
177
 
170
178
  def has_credit_card?
@@ -172,15 +180,15 @@ module FakeBraintree
172
180
  end
173
181
 
174
182
  def credit_card_hash
175
- @customer_hash["credit_card"] || {}
183
+ @customer_hash['credit_card'] || {}
176
184
  end
177
185
 
178
186
  def set_customer_id
179
- @customer_hash["id"] ||= create_id(@customer_hash["merchant_id"])
187
+ @customer_hash['id'] ||= create_id(@customer_hash['merchant_id'])
180
188
  end
181
189
 
182
190
  def credit_card_token(credit_card_hash_without_token)
183
- md5("#{credit_card_hash_without_token["number"]}#{@customer_hash["merchant_id"]}")
191
+ md5("#{credit_card_hash_without_token['number']}#{@customer_hash['merchant_id']}")
184
192
  end
185
193
  end
186
194
  end