workarea-braintree 1.0.3

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 (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
+ */