workarea-cyber_source 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 (78) 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 +14 -0
  7. data/.rails-rubocop.yml +140 -0
  8. data/.rubocop.yml +8 -0
  9. data/CHANGELOG.md +39 -0
  10. data/CODE_OF_CONDUCT.md +3 -0
  11. data/CONTRIBUTING.md +3 -0
  12. data/Gemfile +11 -0
  13. data/LICENSE +52 -0
  14. data/README.md +27 -0
  15. data/Rakefile +59 -0
  16. data/app/models/workarea/payment/authorize/credit_card.decorator +45 -0
  17. data/app/models/workarea/payment/capture/credit_card.decorator +14 -0
  18. data/app/models/workarea/payment/purchase/credit_card.decorator +48 -0
  19. data/app/models/workarea/payment/refund/credit_card.decorator +14 -0
  20. data/app/models/workarea/payment/store_credit_card.decorator +13 -0
  21. data/bin/rails +20 -0
  22. data/config/initializers/gateway.rb +1 -0
  23. data/lib/active_merchant/billing/bogus_cyber_source_gateway.rb +97 -0
  24. data/lib/active_merchant/billing/cyber_source_fix.rb +34 -0
  25. data/lib/workarea/cyber_source.rb +36 -0
  26. data/lib/workarea/cyber_source/engine.rb +8 -0
  27. data/lib/workarea/cyber_source/version.rb +5 -0
  28. data/test/dummy/Rakefile +6 -0
  29. data/test/dummy/bin/bundle +3 -0
  30. data/test/dummy/bin/rails +4 -0
  31. data/test/dummy/bin/rake +4 -0
  32. data/test/dummy/bin/setup +38 -0
  33. data/test/dummy/bin/update +29 -0
  34. data/test/dummy/bin/yarn +11 -0
  35. data/test/dummy/config.ru +5 -0
  36. data/test/dummy/config/application.rb +28 -0
  37. data/test/dummy/config/boot.rb +5 -0
  38. data/test/dummy/config/cable.yml +10 -0
  39. data/test/dummy/config/environment.rb +5 -0
  40. data/test/dummy/config/environments/development.rb +56 -0
  41. data/test/dummy/config/environments/production.rb +91 -0
  42. data/test/dummy/config/environments/test.rb +44 -0
  43. data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
  44. data/test/dummy/config/initializers/assets.rb +14 -0
  45. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  46. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  47. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  48. data/test/dummy/config/initializers/inflections.rb +16 -0
  49. data/test/dummy/config/initializers/mime_types.rb +4 -0
  50. data/test/dummy/config/initializers/workarea.rb +5 -0
  51. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  52. data/test/dummy/config/locales/en.yml +33 -0
  53. data/test/dummy/config/puma.rb +56 -0
  54. data/test/dummy/config/routes.rb +5 -0
  55. data/test/dummy/config/secrets.yml +32 -0
  56. data/test/dummy/config/spring.rb +6 -0
  57. data/test/dummy/db/seeds.rb +2 -0
  58. data/test/dummy/log/.keep +0 -0
  59. data/test/dummy/package.json +5 -0
  60. data/test/integration/workarea/cyber_source_integration_test.rb +191 -0
  61. data/test/models/workarea/payment/authorize/credit_card_test.decorator +68 -0
  62. data/test/models/workarea/payment/capture/credit_card_test.decorator +17 -0
  63. data/test/models/workarea/payment/purchase/credit_card_test.decorator +60 -0
  64. data/test/models/workarea/payment/refund/credit_card_test.decorator +17 -0
  65. data/test/models/workarea/payment/store_credit_card_test.decorator +15 -0
  66. data/test/support/workarea/cyber_source_support_vcr_config.rb +23 -0
  67. data/test/support/workarea/workarea_3_2_backports.rb +57 -0
  68. data/test/teaspoon_env.rb +6 -0
  69. data/test/test_helper.rb +11 -0
  70. data/test/vcr_cassettes/cyber_source/auth_capture.yml +254 -0
  71. data/test/vcr_cassettes/cyber_source/auth_capture_refund.yml +323 -0
  72. data/test/vcr_cassettes/cyber_source/auth_void.yml +250 -0
  73. data/test/vcr_cassettes/cyber_source/purchase_refund.yml +251 -0
  74. data/test/vcr_cassettes/cyber_source/purchase_void.yml +247 -0
  75. data/test/vcr_cassettes/cyber_source/store_auth.yml +179 -0
  76. data/test/vcr_cassettes/cyber_source/store_purchase.yml +180 -0
  77. data/workarea-cyber_source.gemspec +19 -0
  78. metadata +133 -0
@@ -0,0 +1,45 @@
1
+ module Workarea
2
+ decorate Payment::Authorize::CreditCard, with: :cyber_source do
3
+ decorated { delegate :address, to: :tender }
4
+
5
+ def initialize(tender, transaction, options = {})
6
+ super
7
+ @options = @options.merge(
8
+ email: email,
9
+ billing_address: billing_address,
10
+ order_id: order_id
11
+ )
12
+ end
13
+
14
+ def complete!
15
+ return unless Payment::StoreCreditCard.new(tender, options).save!
16
+
17
+ transaction.response = handle_active_merchant_errors do
18
+ gateway.authorize(transaction.amount.cents, tender.token, options)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def order_id
25
+ tender.payment.id
26
+ end
27
+
28
+ def email
29
+ return unless tender.profile.present?
30
+
31
+ tender.profile.email
32
+ end
33
+
34
+ def billing_address
35
+ {
36
+ address1: address.street,
37
+ address2: address.street_2,
38
+ city: address.city,
39
+ state: address.region,
40
+ country: address.country.try(:alpha2),
41
+ zip: address.postal_code
42
+ }
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,14 @@
1
+ module Workarea
2
+ decorate Payment::Capture::CreditCard, with: :cyber_source do
3
+ def complete!
4
+ validate_reference!
5
+
6
+ transaction.response = handle_active_merchant_errors do
7
+ gateway.capture(
8
+ transaction.amount.cents,
9
+ transaction.reference.response.authorization
10
+ )
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,48 @@
1
+ module Workarea
2
+ decorate Payment::Purchase::CreditCard, with: :cyber_source do
3
+ decorated { delegate :address, to: :tender }
4
+
5
+ def initialize(tender, transaction, options = {})
6
+ super
7
+ @options = @options.merge(
8
+ email: email,
9
+ billing_address: billing_address,
10
+ order_id: order_id
11
+ )
12
+ end
13
+
14
+ def complete!
15
+ return unless Payment::StoreCreditCard.new(tender, options).save!
16
+
17
+ transaction.response = handle_active_merchant_errors do
18
+ gateway.purchase(transaction.amount.cents, tender.token, options)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def order_id
25
+ tender.payment.id
26
+ end
27
+
28
+ def email
29
+ return unless tender.profile.present?
30
+
31
+ tender.profile.email
32
+ end
33
+
34
+ def billing_address
35
+ {
36
+ name: nil,
37
+ company: nil,
38
+ address1: address.street,
39
+ address2: address.street_2,
40
+ city: address.city,
41
+ state: address.region,
42
+ country: address.country.try(:alpha2),
43
+ zip: address.postal_code,
44
+ phone: nil
45
+ }
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,14 @@
1
+ module Workarea
2
+ decorate Payment::Refund::CreditCard, with: :cyber_source 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: :cyber_source 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, @options)
8
+ end
9
+
10
+ @credit_card.token = response.authorization
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,20 @@
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/cyber_source/engine", __FILE__)
7
+ APP_PATH = File.expand_path("../../test/dummy/config/application", __FILE__)
8
+
9
+ # Set up gems listed in the Gemfile.
10
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
11
+ require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
12
+
13
+ require "action_controller/railtie"
14
+ require "action_view/railtie"
15
+ require "action_mailer/railtie"
16
+ require "rails/test_unit/railtie"
17
+ require "sprockets/railtie"
18
+ require "teaspoon-mocha"
19
+
20
+ require "rails/engine/commands"
@@ -0,0 +1 @@
1
+ Workarea::CyberSource.auto_configure_gateway
@@ -0,0 +1,97 @@
1
+ module ActiveMerchant
2
+ module Billing
3
+ class BogusCyberSourceGateway < BogusGateway
4
+ def store(paysource, options = {})
5
+ authorization = ";5118839074516426404010;Ahj/7wSTFX4pmYA85bCqKhDdq4ZOWjNklxakXpGAKXFqRekZpABykhk0kyro9JiuKBOTFX4pmYA85bCqAAAA5wQ4;store;;;5118839074516426404010"
6
+ case normalize(paysource)
7
+ when /1$/
8
+ Response.new(true, SUCCESS_MESSAGE, { billingid: "1" }, { test: true, authorization: authorization })
9
+ when /2$/
10
+ Response.new(false, FAILURE_MESSAGE, { billingid: nil, error: FAILURE_MESSAGE }, { test: true, error_code: STANDARD_ERROR_CODE[:processing_error] })
11
+ else
12
+ raise Error, error_message(paysource)
13
+ end
14
+ end
15
+
16
+ def authorize(money, credit_card_or_subscription, options = {})
17
+ case normalize(credit_card_or_subscription)
18
+ when /1$/, "5118839074516426404010"
19
+ succuessful_auth_response
20
+ when /2$/
21
+ Response.new(false, FAILURE_MESSAGE, { authorized_amount: money, error: FAILURE_MESSAGE }, { test: true, error_code: STANDARD_ERROR_CODE[:processing_error] })
22
+ else
23
+ raise Error, error_message(credit_card_or_subscription)
24
+ end
25
+ end
26
+
27
+ def purchase(money, credit_card_or_subscription, options = {})
28
+ case normalize(credit_card_or_subscription)
29
+ when /1$/, "5118839074516426404010"
30
+ succuessful_purchase_response
31
+ when /2$/
32
+ Response.new(false, FAILURE_MESSAGE, { authorized_amount: money, error: FAILURE_MESSAGE }, { test: true, error_code: STANDARD_ERROR_CODE[:processing_error] })
33
+ else
34
+ raise Error, error_message(credit_card_or_subscription)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def normalize(paysource)
41
+ if paysource.respond_to?(:account_number) && (paysource.try(:number).blank? || paysource.number.blank?)
42
+ paysource.account_number
43
+ elsif paysource.respond_to?(:number)
44
+ paysource.number.split(";")[6] || paysource.number
45
+ else
46
+ paysource.to_s.split(";")[6] || paysource.to_s
47
+ end
48
+ end
49
+
50
+ def succuessful_auth_response
51
+ authorization = "5a216efd87c68b548a1856df;5118839077736067504008;Ahj/7wSTFX4pnG3edheIKhDdq4ZOWbVqlwethj1gKXB62GPXpAn6OUkMmkmVdHpMVxQJyYq/FM427zsLxAAA6xxJ;authorize;500;;"
52
+ params = {
53
+ "merchantReferenceCode" => "5a1d848387c68b268bf205f9",
54
+ "requestID" => "5118839077736067504008",
55
+ "decision" => "ACCEPT",
56
+ "reasonCode" => "100",
57
+ "message" => "Successful transaction",
58
+ "requestToken" => "Ahj/7wSTFX4pnG3edheIKhDdq4ZOWbVqlwethj1gKXB62GPXpAn6OUkMmkmVdHpMVxQJyYq/FM427zsLxAAA6xxJ",
59
+ "currency" => "USD",
60
+ "amount" => "5.00",
61
+ "authorizationCode" => "831000",
62
+ "avsCode" => "Y",
63
+ "avsCodeRaw" => "Y",
64
+ "authorizedDateTime" => "2017-11-28T15:45:07Z",
65
+ "processorResponse" => "000",
66
+ "paymentNetworkTransactionID" => "558196000003814",
67
+ "cardCategory" => "A",
68
+ "ownerMerchantID" => "weblinc"
69
+ }
70
+ Response.new(true, SUCCESS_MESSAGE, params, test: true, authorization: authorization)
71
+ end
72
+
73
+ def succuessful_purchase_response
74
+ authorization = "5a609ec187c68b520db767eb;5161970476206134104008;Ahj//wSTF9S7HtFYm4/IESDdm1ZtGbZvKhyKjhnKtJcl3RY7YClyXdFjt6QJ+j6jDJpJl6MVzT24YE5MX1Lse0Vibj8g0UyQ;purchase;500;;"
75
+ params = {
76
+ "merchantReferenceCode" => "5a5f54b787c68be6e7c6a553",
77
+ "requestID" => "5161970476206134104008",
78
+ "decision" => "ACCEPT",
79
+ "reasonCode" => "100",
80
+ "message" => "Successful transaction",
81
+ "requestToken" => "Ahj//wSTF9S7HtFYm4/IESDdm1ZtGbZvKhyKjhnKtJcl3RY7YClyXdFjt6QJ+j6jDJpJl6MVzT24YE5MX1Lse0Vibj8g0UyQ",
82
+ "currency" => "USD",
83
+ "amount" => "5.00",
84
+ "authorizationCode" => "888888",
85
+ "avsCode" => "X",
86
+ "avsCodeRaw" => "I1",
87
+ "authorizedDateTime" => "2018-01-17T13:50:47Z",
88
+ "processorResponse" => "100",
89
+ "reconciliationID" => "73534367JCHT83JZ",
90
+ "ownerMerchantID" => "a",
91
+ "requestDateTime" => "2018-01-17T13:50:47Z"
92
+ }
93
+ Response.new(true, SUCCESS_MESSAGE, params, test: true, authorization: authorization)
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,34 @@
1
+ ActiveMerchant::Billing::CyberSourceGateway.class_eval do
2
+ def add_payment_method_or_subscription(xml, money, payment_method_or_reference, options)
3
+ if payment_method_or_reference.is_a?(String)
4
+ add_address(xml, nil, options[:billing_address], options)
5
+ add_purchase_data(xml, money, true, options)
6
+ add_subscription(xml, options, payment_method_or_reference)
7
+ elsif card_brand(payment_method_or_reference) == 'check'
8
+ add_address(xml, payment_method_or_reference, options[:billing_address], options)
9
+ add_purchase_data(xml, money, true, options)
10
+ add_check(xml, payment_method_or_reference)
11
+ else
12
+ add_address(xml, payment_method_or_reference, options[:billing_address], options)
13
+ add_address(xml, payment_method_or_reference, options[:shipping_address], options, true)
14
+ add_purchase_data(xml, money, true, options)
15
+ add_creditcard(xml, payment_method_or_reference)
16
+ end
17
+ end
18
+
19
+ def build_void_request(identification, options)
20
+ order_id, request_id, request_token, action, money, currency = identification.split(";")
21
+ options[:order_id] = order_id
22
+
23
+ xml = Builder::XmlMarkup.new :indent => 2
24
+ # normal active merchant only has if capture, but purchases should be the same as captures
25
+ # a pr was submited to active merchant, remove this if it ever gets mergex / fixed upstream
26
+ if action == "capture" || action == "purchase"
27
+ add_void_service(xml, request_id, request_token)
28
+ else
29
+ add_purchase_data(xml, money, true, options.merge(:currency => currency || default_currency))
30
+ add_auth_reversal_service(xml, request_id, request_token)
31
+ end
32
+ xml.target!
33
+ end
34
+ end
@@ -0,0 +1,36 @@
1
+ require "workarea"
2
+ require "workarea/storefront"
3
+ require "workarea/admin"
4
+ require "active_merchant/billing/bogus_cyber_source_gateway"
5
+ require "active_merchant/billing/cyber_source_fix"
6
+
7
+ require "workarea/cyber_source/engine"
8
+ require "workarea/cyber_source/version"
9
+
10
+ module Workarea
11
+ module CyberSource
12
+ def self.auto_configure_gateway
13
+ if Rails.application.secrets.cyber_source.present?
14
+ if ENV["HTTP_PROXY"].present?
15
+ uri = URI.parse(ENV["HTTP_PROXY"])
16
+ ActiveMerchant::Billing::CyberSourceGateway.proxy_address = uri.host
17
+ ActiveMerchant::Billing::CyberSourceGateway.proxy_port = uri.port
18
+ end
19
+
20
+ self.gateway = ActiveMerchant::Billing::CyberSourceGateway.new(
21
+ Rails.application.secrets.cyber_source.deep_symbolize_keys
22
+ )
23
+ else
24
+ self.gateway = ActiveMerchant::Billing::BogusCyberSourceGateway.new
25
+ end
26
+ end
27
+
28
+ def self.gateway
29
+ Workarea.config.gateways.credit_card
30
+ end
31
+
32
+ def self.gateway=(gateway)
33
+ Workarea.config.gateways.credit_card = gateway
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,8 @@
1
+ module Workarea
2
+ module CyberSource
3
+ class Engine < ::Rails::Engine
4
+ include Workarea::Plugin
5
+ isolate_namespace Workarea::CyberSource
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Workarea
2
+ module CyberSource
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,3 @@
1
+ #!/usr/bin/env ruby
2
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
3
+ load Gem.bin_path("bundler", "bundle")
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path("../config/application", __dir__)
3
+ require_relative "../config/boot"
4
+ require "rails/commands"
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative "../config/boot"
3
+ require "rake"
4
+ Rake.application.run
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env ruby
2
+ require "pathname"
3
+ require "fileutils"
4
+ include FileUtils
5
+
6
+ # path to your application root.
7
+ APP_ROOT = Pathname.new File.expand_path("../../", __FILE__)
8
+
9
+ def system!(*args)
10
+ system(*args) || abort("\n== Command #{args} failed ==")
11
+ end
12
+
13
+ chdir APP_ROOT do
14
+ # This script is a starting point to setup your application.
15
+ # Add necessary setup steps to this file.
16
+
17
+ puts "== Installing dependencies =="
18
+ system! "gem install bundler --conservative"
19
+ system("bundle check") || system!("bundle install")
20
+
21
+ # Install JavaScript dependencies if using Yarn
22
+ # system('bin/yarn')
23
+
24
+
25
+ # puts "\n== Copying sample files =="
26
+ # unless File.exist?('config/database.yml')
27
+ # cp 'config/database.yml.sample', 'config/database.yml'
28
+ # end
29
+
30
+ puts "\n== Preparing database =="
31
+ system! "bin/rails db:setup"
32
+
33
+ puts "\n== Removing old logs and tempfiles =="
34
+ system! "bin/rails log:clear tmp:clear"
35
+
36
+ puts "\n== Restarting application server =="
37
+ system! "bin/rails restart"
38
+ end
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ require "pathname"
3
+ require "fileutils"
4
+ include FileUtils
5
+
6
+ # path to your application root.
7
+ APP_ROOT = Pathname.new File.expand_path("../../", __FILE__)
8
+
9
+ def system!(*args)
10
+ system(*args) || abort("\n== Command #{args} failed ==")
11
+ end
12
+
13
+ chdir APP_ROOT do
14
+ # This script is a way to update your development environment automatically.
15
+ # Add necessary update steps to this file.
16
+
17
+ puts "== Installing dependencies =="
18
+ system! "gem install bundler --conservative"
19
+ system("bundle check") || system!("bundle install")
20
+
21
+ puts "\n== Updating database =="
22
+ system! "bin/rails db:migrate"
23
+
24
+ puts "\n== Removing old logs and tempfiles =="
25
+ system! "bin/rails log:clear tmp:clear"
26
+
27
+ puts "\n== Restarting application server =="
28
+ system! "bin/rails restart"
29
+ end