workarea-braintree 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +20 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  4. data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  6. data/.gitignore +17 -0
  7. data/CHANGELOG.md +37 -0
  8. data/CODE_OF_CONDUCT.md +3 -0
  9. data/CONTRIBUTING.md +3 -0
  10. data/Gemfile +11 -0
  11. data/LICENSE +52 -0
  12. data/README.md +43 -0
  13. data/Rakefile +50 -0
  14. data/app/models/workarea/payment/authorize/credit_card.decorator +72 -0
  15. data/app/models/workarea/payment/capture/credit_card.decorator +14 -0
  16. data/app/models/workarea/payment/purchase/credit_card.decorator +52 -0
  17. data/app/models/workarea/payment/refund/credit_card.decorator +14 -0
  18. data/app/models/workarea/payment/store_credit_card.decorator +13 -0
  19. data/bin/rails +18 -0
  20. data/config/initializers/workarea.rb +1 -0
  21. data/lib/active_merchant/billing/bogus_braintree_gateway.rb +284 -0
  22. data/lib/tasks/braintree.rake +25 -0
  23. data/lib/workarea/braintree.rb +26 -0
  24. data/lib/workarea/braintree/engine.rb +8 -0
  25. data/lib/workarea/braintree/version.rb +5 -0
  26. data/test/dummy/Rakefile +6 -0
  27. data/test/dummy/app/assets/config/manifest.js +4 -0
  28. data/test/dummy/app/assets/javascripts/application.js +13 -0
  29. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  30. data/test/dummy/app/controllers/application_controller.rb +3 -0
  31. data/test/dummy/app/helpers/application_helper.rb +2 -0
  32. data/test/dummy/app/jobs/application_job.rb +2 -0
  33. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  34. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  35. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  36. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  37. data/test/dummy/bin/bundle +3 -0
  38. data/test/dummy/bin/rails +4 -0
  39. data/test/dummy/bin/rake +4 -0
  40. data/test/dummy/bin/setup +34 -0
  41. data/test/dummy/bin/update +29 -0
  42. data/test/dummy/config.ru +5 -0
  43. data/test/dummy/config/application.rb +23 -0
  44. data/test/dummy/config/boot.rb +5 -0
  45. data/test/dummy/config/cable.yml +9 -0
  46. data/test/dummy/config/environment.rb +5 -0
  47. data/test/dummy/config/environments/development.rb +56 -0
  48. data/test/dummy/config/environments/production.rb +86 -0
  49. data/test/dummy/config/environments/test.rb +44 -0
  50. data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
  51. data/test/dummy/config/initializers/assets.rb +11 -0
  52. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  53. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  54. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  55. data/test/dummy/config/initializers/inflections.rb +16 -0
  56. data/test/dummy/config/initializers/mime_types.rb +4 -0
  57. data/test/dummy/config/initializers/new_framework_defaults.rb +23 -0
  58. data/test/dummy/config/initializers/session_store.rb +3 -0
  59. data/test/dummy/config/initializers/workarea.rb +5 -0
  60. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  61. data/test/dummy/config/locales/en.yml +23 -0
  62. data/test/dummy/config/puma.rb +47 -0
  63. data/test/dummy/config/routes.rb +5 -0
  64. data/test/dummy/config/secrets.yml +22 -0
  65. data/test/dummy/config/spring.rb +6 -0
  66. data/test/dummy/db/seeds.rb +2 -0
  67. data/test/dummy/log/.keep +0 -0
  68. data/test/dummy/public/404.html +67 -0
  69. data/test/dummy/public/422.html +67 -0
  70. data/test/dummy/public/500.html +66 -0
  71. data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
  72. data/test/dummy/public/apple-touch-icon.png +0 -0
  73. data/test/dummy/public/favicon.ico +0 -0
  74. data/test/models/workarea/payment/authorize/credit_card_test.decorator +92 -0
  75. data/test/models/workarea/payment/capture/credit_card_test.decorator +25 -0
  76. data/test/models/workarea/payment/credit_card_integration_test.decorator +8 -0
  77. data/test/models/workarea/payment/purchase/credit_card_test.decorator +78 -0
  78. data/test/models/workarea/payment/refund/credit_card_test.decorator +25 -0
  79. data/test/models/workarea/payment/store_credit_card_test.decorator +23 -0
  80. data/test/support/workarea/braintree_support_vcr_config.rb +23 -0
  81. data/test/test_helper.rb +16 -0
  82. data/test/vcr_cassettes/braintree/authorize_failure.yml +98 -0
  83. data/test/vcr_cassettes/braintree/authorize_success.yml +89 -0
  84. data/test/vcr_cassettes/braintree/capture_success.yml +64 -0
  85. data/test/vcr_cassettes/braintree/purchase_failure.yml +97 -0
  86. data/test/vcr_cassettes/braintree/purchase_success.yml +89 -0
  87. data/test/vcr_cassettes/braintree/refund_success.yml +64 -0
  88. data/test/vcr_cassettes/braintree/store_credit_card-sets_token_on_the_card.yml +86 -0
  89. data/test/vcr_cassettes/braintree/store_without_token.yml +82 -0
  90. data/test/vcr_cassettes/braintree/void_success.yml +60 -0
  91. data/test/vcr_cassettes/credit_card/auth_capture.yml +419 -0
  92. data/test/vcr_cassettes/credit_card/auth_void.yml +415 -0
  93. data/test/vcr_cassettes/credit_card/purchase_void.yml +415 -0
  94. data/test/vcr_cassettes/credit_card/store_auth.yml +227 -0
  95. data/test/vcr_cassettes/credit_card/store_purchase.yml +227 -0
  96. data/workarea-braintree.gemspec +20 -0
  97. metadata +166 -0
@@ -0,0 +1,14 @@
1
+ module Workarea
2
+ decorate Payment::Refund::CreditCard, with: :braintree do
3
+ def complete!
4
+ validate_reference!
5
+
6
+ transaction.response = handle_active_merchant_errors do
7
+ gateway.refund(
8
+ transaction.amount.cents,
9
+ transaction.reference.response.authorization
10
+ )
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module Workarea
2
+ decorate Payment::StoreCreditCard, with: :braintree do
3
+ def perform!
4
+ return true if @credit_card.token.present?
5
+
6
+ response = handle_active_merchant_errors do
7
+ gateway.store(@credit_card.to_active_merchant)
8
+ end
9
+
10
+ @credit_card.token = response.params['credit_card_token']
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails gems
3
+ # installed from the root of your application.
4
+
5
+ ENGINE_ROOT = File.expand_path("../..", __FILE__)
6
+ ENGINE_PATH = File.expand_path("../../lib/workarea/braintree/engine", __FILE__)
7
+
8
+ # Set up gems listed in the Gemfile.
9
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
10
+ require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
11
+
12
+ require "action_controller/railtie"
13
+ require "action_view/railtie"
14
+ require "action_mailer/railtie"
15
+ require "rails/test_unit/railtie"
16
+ require "sprockets/railtie"
17
+
18
+ require "rails/engine/commands"
@@ -0,0 +1 @@
1
+ Workarea::Braintree.auto_configure_gateway
@@ -0,0 +1,284 @@
1
+ module ActiveMerchant
2
+ module Billing
3
+ class BogusBraintreeGateway < BogusGateway
4
+ def initialize(options = {})
5
+ #noop
6
+ end
7
+
8
+ def authorize(money, credit_card_or_vault_id, options = {})
9
+ case normalize(credit_card_or_vault_id)
10
+ when /1$/
11
+ succuessful_auth_response
12
+ when /2$/
13
+ Response.new(false, FAILURE_MESSAGE, { authorized_amount: money, error: FAILURE_MESSAGE }, { test: true, error_code: STANDARD_ERROR_CODE[:processing_error] })
14
+ else
15
+ raise Error, error_message(credit_card_or_vault_id)
16
+ end
17
+ end
18
+
19
+ def capture(money, authorization, options = {})
20
+ params = {
21
+ "customer_vault_id" => nil,
22
+ "braintree_transaction" => {
23
+ "order_id" => nil,
24
+ "status" => "submitted_for_settlement",
25
+ "credit_card_details" => {
26
+ "masked_number" => "411111******1111",
27
+ "bin" => "411111",
28
+ "last_4" => "1111",
29
+ "card_type" => "Visa",
30
+ "token" => nil
31
+ },
32
+ "customer_details" => {
33
+ "id" => nil,
34
+ "email" => nil
35
+ },
36
+ "billing_details" => {
37
+ "street_address" => "22 South 3rd St",
38
+ "extended_address" => nil,
39
+ "company" => nil,
40
+ "locality" => "Philadelphia",
41
+ "region" => "PA",
42
+ "postal_code" => "19106",
43
+ "country_name" => "United States of America"
44
+ },
45
+ "shipping_details" => {
46
+ "street_address" => nil,
47
+ "extended_address" => nil,
48
+ "company" => nil,
49
+ "locality" => nil,
50
+ "region" => nil,
51
+ "postal_code" => nil,
52
+ "country_name" => nil
53
+ },
54
+ "vault_customer" => nil,
55
+ "merchant_account_id" => "a",
56
+ "processor_response_code" => "1000"
57
+ }
58
+ }
59
+ Response.new(true, SUCCESS_MESSAGE, params, test: true)
60
+ end
61
+
62
+ def purchase(money, credit_card_or_vault_id, options = {})
63
+ case normalize(credit_card_or_vault_id)
64
+ when /1$/
65
+ succuessful_purchase_response
66
+ when /2$/
67
+ Response.new(false, FAILURE_MESSAGE, { paid_amount: money, error: FAILURE_MESSAGE }, { test: true, error_code: STANDARD_ERROR_CODE[:processing_error] })
68
+ else
69
+ raise Error, error_message(credit_card_or_vault_id)
70
+ end
71
+ end
72
+
73
+ def refund(*args)
74
+ params = {
75
+ "braintree_transaction" => {
76
+ "order_id" => nil,
77
+ "status" => "submitted_for_settlement",
78
+ "credit_card_details" => {
79
+ "masked_number" => "424242******4242",
80
+ "bin" => "424242",
81
+ "last_4" => "4242",
82
+ "card_type" => "Visa",
83
+ "token" => nil
84
+ },
85
+ "customer_details" => {
86
+ "id" => nil,
87
+ "email" => nil
88
+ },
89
+ "billing_details" => {
90
+ "street_address" => nil,
91
+ "extended_address" => nil,
92
+ "company" => nil,
93
+ "locality" => "Philadelphia",
94
+ "region" => nil,
95
+ "postal_code" => nil,
96
+ "country_name" => "United States of America"
97
+ },
98
+ "shipping_details" => {
99
+ "street_address" => nil,
100
+ "extended_address" => nil,
101
+ "company" => nil,
102
+ "locality" => nil,
103
+ "region" => nil,
104
+ "postal_code" => nil,
105
+ "country_name" => nil
106
+ },
107
+ "vault_customer" => nil,
108
+ "merchant_account_id" => "a",
109
+ "processor_response_code" => "1002"
110
+ }
111
+ }
112
+ Response.new(true, SUCCESS_MESSAGE, params, test: true)
113
+ end
114
+
115
+ def store(paysource, options = {})
116
+ params = {
117
+ "braintree_customer" => {
118
+ "email" => "user@a.com",
119
+ "first_name" => "Bob",
120
+ "last_name" => "Bobsen",
121
+ "id" => "65236875",
122
+ "credit_cards" => [
123
+ {
124
+ "bin" => "424242",
125
+ "expiration_date" => "08/2022",
126
+ "token" => "f94qx1",
127
+ "last_4" => "4242",
128
+ "card_type" => "Visa",
129
+ "masked_number" => "424242******4242"
130
+ }
131
+ ]
132
+ },
133
+ "customer_vault_id" => "65236875",
134
+ "credit_card_token" => "f94qx1"
135
+ }
136
+
137
+ case normalize(paysource)
138
+ when /1$/
139
+ Response.new(true, SUCCESS_MESSAGE, params, test: true)
140
+ when /2$/
141
+ Response.new(false, FAILURE_MESSAGE, { billingid: nil, error: FAILURE_MESSAGE }, { test: true, error_code: STANDARD_ERROR_CODE[:processing_error] })
142
+ else
143
+ raise Error, error_message(paysource)
144
+ end
145
+ end
146
+
147
+ def void(authorization, options = {})
148
+ params = {
149
+ "braintree_transaction" => {
150
+ "order_id" => nil,
151
+ "status" => "voided",
152
+ "credit_card_details" => {
153
+ "masked_number" => "424242******4242",
154
+ "bin" => "424242",
155
+ "last_4" => "4242",
156
+ "card_type" => "Visa",
157
+ "token" => nil
158
+ },
159
+ "customer_details" => {
160
+ "id" => nil,
161
+ "email" => nil
162
+ },
163
+ "billing_details" => {
164
+ "street_address" => nil,
165
+ "extended_address" => nil,
166
+ "company" => nil,
167
+ "locality" => nil,
168
+ "region" => nil,
169
+ "postal_code" => nil,
170
+ "country_name" => nil
171
+ },
172
+ "shipping_details" => {
173
+ "street_address" => nil,
174
+ "extended_address" => nil,
175
+ "company" => nil,
176
+ "locality" => nil,
177
+ "region" => nil,
178
+ "postal_code" => nil,
179
+ "country_name" => nil
180
+ },
181
+ "vault_customer" => nil,
182
+ "merchant_account_id" => "a",
183
+ "processor_response_code" => "1000"
184
+ }
185
+ }
186
+ Response.new(true, SUCCESS_MESSAGE, params, test: true)
187
+ end
188
+
189
+ def method_missing(method, *args)
190
+ return Response.new(true, "Bogus Gateway: Forced success", {}, { test: true }) if self.class.supported_methods.include?(method)
191
+ super
192
+ end
193
+
194
+ private
195
+
196
+ def succuessful_auth_response
197
+ params = {
198
+ "customer_vault_id" => "65236875",
199
+ "braintree_transaction" => {
200
+ "order_id" => nil,
201
+ "status" => "authorized",
202
+ "credit_card_details" => {
203
+ "masked_number" => "424242******4242",
204
+ "bin" => "424242",
205
+ "last_4" => "4242",
206
+ "card_type" => "Visa",
207
+ "token" => 1
208
+ },
209
+ "customer_details" => {
210
+ "id" => nil,
211
+ "email" => nil
212
+ },
213
+ "billing_details" => {
214
+ "street_address" => "22 South 3rd St",
215
+ "extended_address" => nil,
216
+ "company" => "WebLinc",
217
+ "locality" => "Philadelphia",
218
+ "region" => "PA",
219
+ "postal_code" => "19106",
220
+ "country_name" => "United States of America"
221
+ },
222
+ "shipping_details" => {
223
+ "street_address" => nil,
224
+ "extended_address" => nil,
225
+ "company" => nil,
226
+ "locality" => nil,
227
+ "region" => nil,
228
+ "postal_code" => nil,
229
+ "country_name" => nil
230
+ },
231
+ "vault_customer" => nil,
232
+ "merchant_account_id" => "a",
233
+ "processor_response_code" => "1000"
234
+ }
235
+ }
236
+ Response.new(true, SUCCESS_MESSAGE, params, test: true)
237
+ end
238
+
239
+ def succuessful_purchase_response
240
+ params = {
241
+ "customer_vault_id" => "65236875",
242
+ "braintree_transaction" => {
243
+ "order_id" => nil,
244
+ "status" => "authorized",
245
+ "credit_card_details" => {
246
+ "masked_number" => "424242******4242",
247
+ "bin" => "424242",
248
+ "last_4" => "4242",
249
+ "card_type" => "Visa",
250
+ "token" => "1"
251
+ },
252
+ "customer_details" => {
253
+ "id" => nil,
254
+ "email" => nil
255
+ },
256
+ "billing_details" => {
257
+ "street_address" => "22 South 3rd St",
258
+ "extended_address" => nil,
259
+ "company" => "WebLinc",
260
+ "locality" => "Philadelphia",
261
+ "region" => "PA",
262
+ "postal_code" => "19106",
263
+ "country_name" => "United States of America"
264
+ },
265
+ "shipping_details" => {
266
+ "street_address" => nil,
267
+ "extended_address" => nil,
268
+ "company" => nil,
269
+ "locality" => nil,
270
+ "region" => nil,
271
+ "postal_code" => nil,
272
+ "country_name" => nil
273
+ },
274
+ "vault_customer" => nil,
275
+ "merchant_account_id" => "a",
276
+ "processor_response_code" => "1000",
277
+ "submit_for_settlement" => true
278
+ }
279
+ }
280
+ Response.new(true, SUCCESS_MESSAGE, params, test: true)
281
+ end
282
+ end
283
+ end
284
+ end
@@ -0,0 +1,25 @@
1
+ namespace :workarea do
2
+ namespace :braintree do
3
+ desc "settles a transaction in braintree sandbox"
4
+ task :settle_test_transaction, [:transaction_id] => :environment do |_, args|
5
+ unless Rails.env.development?
6
+ warn "Only permitted in dev"
7
+ exit(1)
8
+ end
9
+
10
+ unless args[:transaction_id].present?
11
+ warn "need transaction_id"
12
+ exit(1)
13
+ end
14
+
15
+ Braintree::Configuration.environment = :sandbox
16
+ secrets = Rails.application.secrets.braintree.deep_symbolize_keys
17
+ [:merchant_id, :public_key, :private_key].each do |key|
18
+ puts key
19
+ Braintree::Configuration.send("#{key}=", secrets[key])
20
+ end
21
+
22
+ Braintree::TestTransaction.settle args[:transaction_id]
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,26 @@
1
+ require "workarea/braintree/engine"
2
+ require "workarea/braintree/version"
3
+
4
+ require "active_merchant/billing/bogus_braintree_gateway"
5
+
6
+ module Workarea
7
+ module Braintree
8
+ def self.auto_configure_gateway
9
+ if Rails.application.secrets.braintree.present?
10
+ self.gateway = ActiveMerchant::Billing::BraintreeGateway.new(
11
+ Rails.application.secrets.braintree.deep_symbolize_keys
12
+ )
13
+ else
14
+ self.gateway = ActiveMerchant::Billing::BogusBraintreeGateway.new
15
+ end
16
+ end
17
+
18
+ def self.gateway
19
+ Workarea.config.gateways.credit_card
20
+ end
21
+
22
+ def self.gateway=(gateway)
23
+ Workarea.config.gateways.credit_card = gateway
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,8 @@
1
+ module Workarea
2
+ module Braintree
3
+ class Engine < ::Rails::Engine
4
+ include Workarea::Plugin
5
+ isolate_namespace Workarea::Braintree
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Workarea
2
+ module Braintree
3
+ VERSION = "1.0.3"
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require_relative 'config/application'
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,4 @@
1
+
2
+ //= link_tree ../images
3
+ //= link_directory ../javascripts .js
4
+ //= link_directory ../stylesheets .css
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */