solidus_gateway_checkout_v2 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b4553466121a1142278574daa84f17c3b9e2b35c
4
+ data.tar.gz: d843f8152afe2d8fe4de2a5fbd7c95ccb91ad122
5
+ SHA512:
6
+ metadata.gz: 4322ff8f704df7d0d735331aa68c511013d97875f5e8be9778630bbf7ff40e3b4d7990900dd0eaea929ecf684550840066722099f18a81b1398b0c60316a8be2
7
+ data.tar.gz: d738d9ce3b724bfcb71dc3403661e82ffdf2a70b4cf967c588fd86eab5b5cffe8fe1f2d7ff7dbb16215bce098d214d59b3d81d7ebeebf3f1807e690d9f5d9488
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ \#*
2
+ *~
3
+ .#*
4
+ .DS_Store
5
+ tmp
6
+ spec/dummy
7
+ Gemfile.lock
8
+ .rvmrc
9
+ coverage
10
+ .ruby-version
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,82 @@
1
+ # Contributing
2
+
3
+ *(Originally copied from [Spree Static Content's Contribution guidelines](https://github.com/spree-contrib/spree_static_content/blob/master/CONTRIBUTING.md)*
4
+
5
+ Solidus Gateway Checkout V2 is an open source project and we encourage contributions.
6
+
7
+ In the spirit of [free software][1], **everyone** is encouraged to help improve this project.
8
+
9
+ Here are some ways *you* can contribute:
10
+
11
+ * by using prerelease versions
12
+ * by reporting [bugs][2]
13
+ * by suggesting new features
14
+ * by writing [translations][3]
15
+ * by writing or editing documentation
16
+ * by writing specifications
17
+ * by writing code (*no patch is too small*: fix typos, add comments, clean up inconsistent whitespace)
18
+ * by refactoring code
19
+ * by resolving [issues][2]
20
+ * by reviewing patches
21
+
22
+ ---
23
+
24
+ ## Filing an issue
25
+
26
+ When filing an issue on this extension, please first do these things:
27
+
28
+ * Verify you can reproduce this issue in a brand new application.
29
+ * Run through the steps to reproduce the issue again.
30
+
31
+ In the issue itself please provide:
32
+
33
+ * A comprehensive list of steps to reproduce the issue.
34
+ * What you're *expecting* to happen compared with what's *actually* happening.
35
+ * The version of Spree *and* the version of Rails.
36
+ * A list of all extensions.
37
+ * Any relevant stack traces ("Full trace" preferred)
38
+ * Your `Gemfile`
39
+
40
+ In 99% of cases, this information is enough to determine the cause and solution to the problem that is being described.
41
+
42
+ ---
43
+
44
+ ## Pull requests
45
+
46
+ We gladly accept pull requests to fix bugs and, in some circumstances, add new features to this extension.
47
+
48
+ Here's a quick guide:
49
+
50
+ 1. Fork the repo.
51
+
52
+ 2. Run the tests. We only take pull requests with passing tests, and it's great to know that you have a clean slate.
53
+
54
+ 3. Create new branch then make changes and add tests for your changes. Only refactoring and documentation changes require no new tests. If you are adding functionality or fixing a bug, we need tests!
55
+
56
+ 4. Push to your fork and submit a pull request. If the changes will apply cleanly to the latest stable branches and master branch, you will only need to submit one pull request.
57
+
58
+ At this point you're waiting on us. We may suggest some changes or improvements or alternatives.
59
+
60
+ Some things that will increase the chance that your pull request is accepted, taken straight from the Ruby on Rails guide:
61
+
62
+ * Use Rails idioms and helpers.
63
+ * Include tests that fail without your code, and pass with it.
64
+ * Update the documentation, the surrounding one, examples elsewhere, guides, whatever is affected by your contribution.
65
+
66
+ ---
67
+
68
+ ## TL;DR
69
+
70
+ * Fork the repo
71
+ * Clone your repo
72
+ * Run `bundle install`
73
+ * Run `bundle exec rake test_app` to create the test application in `spec/dummy`
74
+ * Make your changes
75
+ * Ensure specs pass by running `bundle exec rspec spec`
76
+ * Submit your pull request
77
+
78
+ And in case we didn't emphasize it enough: **we love tests!**
79
+
80
+ [1]: http://www.fsf.org/licensing/essays/free-sw.html
81
+ [2]: https://github.com/whelton/solidus_gateway_checkout_v2/issues
82
+ [3]: https://github.com/whelton/solidus_gateway_checkout_v2/tree/master/config/locales
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "solidus", github: "solidusio/solidus", branch: "master"
4
+
5
+ group :development, :test do
6
+ gem "pry-rails"
7
+ end
8
+
9
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2016 James Whelton and contributors.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ * Neither the name Solidus nor the names of its contributors may be used to
13
+ endorse or promote products derived from this software without specific
14
+ prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Solidus Gateway Checkout V2
2
+
3
+ Adds [Checkout.com V2](checkout.com) Gateway to Soldius, supporting both server and card tokenisation payments (via the JS library.)
4
+
5
+ ---
6
+ ## Basic Installation
7
+
8
+ Add to your `Gemfile`:
9
+
10
+ ```ruby
11
+ gem 'solidus_gateway_checkout_v2'
12
+ ```
13
+
14
+ Make sure to **restart your app**. Navigate to *Configuration >
15
+ Payment Methods > New Payment Method* in the admin panel and you should see
16
+ that Checkout V2 has been added to the list.
17
+
18
+
19
+ That's all!
20
+
21
+ ---
22
+
23
+ ## Contributing
24
+
25
+ See corresponding [guidelines][1] and check out the [issues][2].
26
+
27
+ ---
28
+
29
+ Copyright (c) 2015 [James Whelton][3] and [contributors][4], released under the [New BSD License][5]
30
+
31
+ [1]: https://github.com/whelton/solidus_gateway_checkout_v2/blob/master/CONTRIBUTING.md
32
+ [2]: https://github.com/whelton/solidus_gateway_checkout_v2/issues
33
+ [3]: https://github.com/whelton
34
+ [4]: https://github.com/whelton/solidus_gateway_checkout_v2/graphs/contributors
35
+ [5]: https://github.com/whelton/solidus_gateway_checkout_v2/blob/master/LICENSE.md
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ require 'spree/testing_support/common_rake'
6
+
7
+ RSpec::Core::RakeTask.new
8
+
9
+ task :default do
10
+ if Dir["spec/dummy"].empty?
11
+ Rake::Task[:test_app].invoke
12
+ Dir.chdir("../../")
13
+ end
14
+ Rake::Task[:spec].invoke
15
+ end
16
+
17
+ desc "Generates a dummy app for testing"
18
+ task :test_app do
19
+ ENV['LIB_NAME'] = 'solidus_gateway_checkout_v2'
20
+ Rake::Task['common:test_app'].invoke
21
+ end
@@ -0,0 +1,33 @@
1
+
2
+ class Spree::Gateway::CheckoutV2Gateway < Spree::Gateway
3
+
4
+ preference :secret_key, :string
5
+ preference :publishable_key, :string
6
+ preference :use_card_tokenisation, :boolean, default: true
7
+ preference :test, :boolean, default: true
8
+
9
+ def method_type
10
+ 'checkout_v2'
11
+ end
12
+
13
+ def provider_class
14
+ ActiveMerchant::Billing::CheckoutV2
15
+ end
16
+
17
+ def authorize(money, creditcard, gateway_options)
18
+ if creditcard.number.blank? && creditcard.gateway_payment_profile_id.present?
19
+ provider.authorize(money, creditcard.gateway_payment_profile_id, gateway_options)
20
+ else
21
+ provider.authorize(money, creditcard, gateway_options)
22
+ end
23
+ end
24
+
25
+ def purchase(money, creditcard, gateway_options)
26
+ if creditcard.number.blank? && creditcard.gateway_payment_profile_id.present?
27
+ provider.purchase(money, creditcard.gateway_payment_profile_id, gateway_options)
28
+ else
29
+ provider.purchase(money, creditcard, gateway_options)
30
+ end
31
+ end
32
+
33
+ end
data/bin/rails ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
4
+ ENGINE_PATH = File.expand_path('../../lib/spree_gateway/engine', __FILE__)
5
+
6
+ require 'rails/all'
7
+ require 'rails/engine/commands'
@@ -0,0 +1,4 @@
1
+ ---
2
+ en:
3
+ spree:
4
+ payment_has_been_cancelled: The payment has been cancelled.
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Spree::Core::Engine.add_routes do
2
+
3
+ end
@@ -0,0 +1,218 @@
1
+ # From https://github.com/activemerchant/active_merchant/blob/8f8c46e65969896c869dfb7dbef3a3b47921e1c4/lib/active_merchant/billing/gateways/checkout_v2.rb
2
+ #
3
+ # Solidus currently (version '1.1.1' at time of writing) uses Active Merchant at '~> 1.48.0'
4
+ # CheckoutV2 Gateway was added in Active Merchant at '1.51.0'
5
+ # so Solidus does not currently have access to it
6
+ #
7
+ # This has been modified to authorize with card token if provided as payment method
8
+
9
+ module ActiveMerchant #:nodoc:
10
+ module Billing #:nodoc:
11
+ class CheckoutV2 < Gateway
12
+ self.display_name = "Checkout.com V2 Gateway"
13
+ self.homepage_url = "https://www.checkout.com/"
14
+ self.live_url = "https://api2.checkout.com/v2"
15
+ self.test_url = "http://sandbox.checkout.com/api2/v2"
16
+
17
+ self.supported_countries = ['AD', 'AT', 'BE', 'BG', 'CH', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FO', 'FI', 'FR', 'GB', 'GI', 'GL', 'GR', 'HR', 'HU', 'IE', 'IS', 'IL', 'IT', 'LI', 'LT', 'LU', 'LV', 'MC', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SE', 'SI', 'SM', 'SK', 'SJ', 'TR', 'VA']
18
+ self.default_currency = "USD"
19
+ self.money_format = :cents
20
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
21
+
22
+ def initialize(options={})
23
+ requires!(options, :secret_key)
24
+ super
25
+ end
26
+
27
+ def purchase(amount, payment_method, options={})
28
+ MultiResponse.run do |r|
29
+ r.process { authorize(amount, payment_method, options) }
30
+ r.process { capture(amount, r.authorization, options) }
31
+ end
32
+ end
33
+
34
+ def authorize(amount, payment_method, options={})
35
+ post = {}
36
+ post[:autoCapture] = "n"
37
+ add_invoice(post, amount, options)
38
+
39
+ if payment_method.is_a?(String) && payment_method.include?('card_tok_')
40
+ post[:cardToken] = payment_method
41
+ post[:email] = options[:email]
42
+
43
+ commit(:authorize_token, post)
44
+ else
45
+ add_payment_method(post, payment_method)
46
+ add_customer_data(post, options)
47
+
48
+ commit(:authorize, post)
49
+ end
50
+ end
51
+
52
+ def capture(amount, authorization, options={})
53
+ post = {}
54
+ add_invoice(post, amount, options)
55
+ add_customer_data(post, options)
56
+
57
+ commit(:capture, post, authorization)
58
+ end
59
+
60
+ def void(authorization, options={})
61
+ post = {}
62
+ commit(:void, post, authorization)
63
+ end
64
+
65
+ def refund(amount, authorization, options={})
66
+ post = {}
67
+ add_invoice(post, amount, options)
68
+ add_customer_data(post, options)
69
+
70
+ commit(:refund, post, authorization)
71
+ end
72
+
73
+ def verify(credit_card, options={})
74
+ MultiResponse.run(:use_first_response) do |r|
75
+ r.process { authorize(100, credit_card, options) }
76
+ r.process(:ignore_result) { void(r.authorization, options) }
77
+ end
78
+ end
79
+
80
+ def supports_scrubbing?
81
+ true
82
+ end
83
+
84
+ def scrub(transcript)
85
+ transcript.
86
+ gsub(%r((Authorization: )[^\\]*)i, '\1[FILTERED]').
87
+ gsub(%r(("number\\":\\")\d+), '\1[FILTERED]').
88
+ gsub(%r(("cvv\\":\\")\d+), '\1[FILTERED]')
89
+ end
90
+
91
+ private
92
+
93
+ def add_invoice(post, money, options)
94
+ post[:value] = amount(money)
95
+ post[:trackId] = options[:order_id]
96
+ post[:currency] = options[:currency] || currency(money)
97
+ end
98
+
99
+ def add_payment_method(post, payment_method)
100
+ post[:card] = {}
101
+ post[:card][:name] = payment_method.name
102
+ post[:card][:number] = payment_method.number
103
+ post[:card][:cvv] = payment_method.verification_value
104
+ post[:card][:expiryYear] = format(payment_method.year, :four_digits)
105
+ post[:card][:expiryMonth] = format(payment_method.month, :two_digits)
106
+ end
107
+
108
+ def add_customer_data(post, options)
109
+ post[:email] = options[:email] || "unspecified@example.com"
110
+ address = options[:billing_address]
111
+ if(address && post[:card])
112
+ post[:card][:billingDetails] = {}
113
+ post[:card][:billingDetails][:address1] = address[:address1]
114
+ post[:card][:billingDetails][:address2] = address[:address2]
115
+ post[:card][:billingDetails][:city] = address[:city]
116
+ post[:card][:billingDetails][:state] = address[:state]
117
+ post[:card][:billingDetails][:country] = address[:country]
118
+ post[:card][:billingDetails][:postcode] = address[:zip]
119
+ post[:card][:billingDetails][:phone] = { number: address[:phone] } unless address[:phone].blank?
120
+ end
121
+ end
122
+
123
+ def commit(action, post, authorization = nil)
124
+ begin
125
+ raw_response = ssl_post(url(post, action, authorization), post.to_json, headers)
126
+ response = parse(raw_response)
127
+ rescue ResponseError => e
128
+ raise unless(e.response.code.to_s =~ /4\d\d/)
129
+ response = parse(e.response.body)
130
+ end
131
+
132
+ succeeded = success_from(response)
133
+ Response.new(
134
+ succeeded,
135
+ message_from(succeeded, response),
136
+ response,
137
+ authorization: authorization_from(response),
138
+ error_code: error_code_from(succeeded, response),
139
+ test: test?,
140
+ avs_result: avs_result(action, response),
141
+ cvv_result: cvv_result(action, response))
142
+ end
143
+
144
+ def headers
145
+ {
146
+ "Authorization" => @options[:secret_key],
147
+ "Content-Type" => "application/json;charset=UTF-8"
148
+ }
149
+ end
150
+
151
+ def url(post, action, authorization)
152
+ if action == :authorize
153
+ "#{base_url}/charges/card"
154
+ elsif action == :authorize_token
155
+ "#{base_url}/charges/token"
156
+ else
157
+ "#{base_url}/charges/#{authorization}/#{action}"
158
+ end
159
+ end
160
+
161
+ def base_url
162
+ test? ? test_url : live_url
163
+ end
164
+
165
+ def avs_result(action, response)
166
+ action == :purchase ? AVSResult.new(code: response["card"]["avsCheck"]) : nil
167
+ end
168
+
169
+ def cvv_result(action, response)
170
+ action == :purchase ? CVVResult.new(response["card"]["cvvCheck"]) : nil
171
+ end
172
+
173
+ def parse(body)
174
+ JSON.parse(body)
175
+ rescue JSON::ParserError
176
+ {
177
+ "message" => "Invalid JSON response received from CheckoutV2Gateway. Please contact CheckoutV2Gateway if you continue to receive this message.",
178
+ "raw_response" => scrub(body)
179
+ }
180
+ end
181
+
182
+ def success_from(response)
183
+ response["responseCode"] == ("10000" || "10100")
184
+ end
185
+
186
+ def message_from(succeeded, response)
187
+ if succeeded
188
+ "Succeeded"
189
+ elsif response["errors"]
190
+ response["message"] + ": " + response["errors"].first
191
+ else
192
+ response["responseMessage"] || response["message"] || "Unable to read error message"
193
+ end
194
+ end
195
+
196
+ STANDARD_ERROR_CODE_MAPPING = {
197
+ "20014" => STANDARD_ERROR_CODE[:invalid_number],
198
+ "20100" => STANDARD_ERROR_CODE[:invalid_expiry_date],
199
+ "20054" => STANDARD_ERROR_CODE[:expired_card],
200
+ "40104" => STANDARD_ERROR_CODE[:incorrect_cvc],
201
+ "40108" => STANDARD_ERROR_CODE[:incorrect_zip],
202
+ "40111" => STANDARD_ERROR_CODE[:incorrect_address],
203
+ "20005" => STANDARD_ERROR_CODE[:card_declined],
204
+ "20088" => STANDARD_ERROR_CODE[:processing_error],
205
+ "20001" => STANDARD_ERROR_CODE[:call_issuer],
206
+ "30004" => STANDARD_ERROR_CODE[:pickup_card]
207
+ }
208
+
209
+ def authorization_from(raw)
210
+ raw["id"]
211
+ end
212
+
213
+ def error_code_from(succeeded, response)
214
+ succeeded ? nil : STANDARD_ERROR_CODE_MAPPING[response["responseCode"]]
215
+ end
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,4 @@
1
+ require "spree_core"
2
+ require "spree_gateway_checkout_v2/engine"
3
+ require "sass/rails"
4
+ require "coffee_script"
@@ -0,0 +1,30 @@
1
+ module SpreeGatewayCheckoutV2
2
+ class Engine < Rails::Engine
3
+ engine_name 'solidus_gateway_checkout_v2'
4
+
5
+ config.autoload_paths += %W(#{config.root}/lib)
6
+
7
+ initializer "spree.gateway.payment_methods", :after => "spree.register.payment_methods" do |app|
8
+ app.config.spree.payment_methods << Spree::Gateway::CheckoutV2Gateway
9
+ end
10
+
11
+ def self.activate
12
+ if SpreeGatewayCheckoutV2::Engine.frontend_available?
13
+ Dir.glob(File.join(File.dirname(__FILE__), "../../controllers/frontend/*/*_decorator*.rb")) do |c|
14
+ Rails.configuration.cache_classes ? require(c) : load(c)
15
+ end
16
+ end
17
+ end
18
+
19
+
20
+ def self.frontend_available?
21
+ @@frontend_available ||= ::Rails::Engine.subclasses.map(&:instance).map{ |e| e.class.to_s }.include?('Spree::Frontend::Engine')
22
+ end
23
+
24
+ if self.frontend_available?
25
+ paths["app/views"] << "lib/views/frontend"
26
+ end
27
+
28
+ config.to_prepare &method(:activate).to_proc
29
+ end
30
+ end
@@ -0,0 +1,83 @@
1
+ <%= render "spree/checkout/payment/gateway", payment_method: payment_method %>
2
+
3
+ <% if payment_method.preferences[:use_card_tokenisation] %>
4
+ <!-- Using Card Tokenisation For Checkout V2 Gateway -->
5
+ <script type="text/javascript" src="https://<%= payment_method.preferences[:test_mode] ? 'sandbox.checkout.com/js/v1/checkoutkit.js' : 'cdn.checkout.com/js/checkoutkit.js' %>"></script>
6
+ <script type="text/javascript">
7
+ // Payment Method Element & Id
8
+ Spree.checkoutV2PaymentMethod = $('#payment_method_' + <%= payment_method.id %>);
9
+ Spree.checkoutV2PaymentMethodId = Spree.checkoutV2PaymentMethod.prop('id').split("_")[2];
10
+ // CheckoutKit Credentials
11
+ CheckoutKit.setPublicKey('<%= payment_method.preferred_publishable_key %>');
12
+ CheckoutKit.setCustomerEmail('<%= current_order.email %>');
13
+ // CheckoutKit API Error Event Handler
14
+ CheckoutKit.addEventHandler(CheckoutKit.Events.API_ERROR, function(response){
15
+ // Create Error Messages
16
+ var messages = '<b>'+response.data.message+'</b>';
17
+ messages += '<ul>';
18
+ $.each(response.data.errors, function(index, value){
19
+ messages += '<li>'+value+'</li>';
20
+ });
21
+ messages += '</ul>';
22
+ // Show Errors
23
+ $('#checkoutV2Error').html(messages);
24
+ $('#checkoutV2Error').show();
25
+ // Enable Inputs
26
+ Spree.checkoutV2PaymentMethod.find('#name_on_card_'+Spree.checkoutV2PaymentMethodId+', #card_number, #card_expiry, #card_code').prop("disabled", false);
27
+ $('#checkout_form_payment input[type="submit"]').removeClass('disabled').prop('disabled', false);
28
+ });
29
+ // Response Handler
30
+ var checkoutV2ResponseHandler = function(response){
31
+ // Disable Inputs (Meaning they won't be submitted with form)
32
+ Spree.checkoutV2PaymentMethod.find('#card_number, #card_expiry, #card_code').prop("disabled", true);
33
+ // Enable Name Input
34
+ Spree.checkoutV2PaymentMethod.find('#name_on_card_'+Spree.checkoutV2PaymentMethodId).prop("disabled", false);
35
+ // Create Hidden Inputs With Data From API
36
+ Spree.checkoutV2PaymentMethod.append("<input type='hidden' id='checkout_v2_token' name='payment_source[" + Spree.checkoutV2PaymentMethodId + "][gateway_payment_profile_id]' value='" + response.id + "'/>");
37
+ Spree.checkoutV2PaymentMethod.append("<input type='hidden' name='payment_source[" + Spree.checkoutV2PaymentMethodId + "][paymentMethod]' value='" + response.card.paymentMethod + "'/>");
38
+ Spree.checkoutV2PaymentMethod.append("<input type='hidden' name='payment_source[" + Spree.checkoutV2PaymentMethodId + "][last_digits]' value='" + response.card.last4 + "'/>");
39
+ Spree.checkoutV2PaymentMethod.append("<input type='hidden' name='payment_source[" + Spree.checkoutV2PaymentMethodId + "][month]' value='" + response.card.expiryMonth + "'/>");
40
+ Spree.checkoutV2PaymentMethod.append("<input type='hidden' name='payment_source[" + Spree.checkoutV2PaymentMethodId + "][year]' value='" + response.card.expiryYear + "'/>");
41
+ // Submit
42
+ return Spree.checkoutV2PaymentMethod.parents("form").trigger('submit');
43
+ };
44
+ // On Page Ready
45
+ $(document).ready(function() {
46
+ // Prepend div to Payment Method Element to display any errors
47
+ Spree.checkoutV2PaymentMethod.prepend("<div id='checkoutV2Error' class='errorExplanation' style='display:none'></div>");
48
+ // Form Submission Handler
49
+ $('#checkout_form_payment').submit(function(e) {
50
+ var expiration, card;
51
+ // Hide any existing errors
52
+ $('#checkoutV2Error').hide();
53
+ // Check if the token input exists
54
+ // Meaning we already gotten a token and can do a normal submission
55
+ if ( $( "#checkout_v2_token" ).length ){
56
+ return true;
57
+ }
58
+ // If CheckoutV2 Payment Method Element is visible, stop form submission and create card token
59
+ if (Spree.checkoutV2PaymentMethod.is(':visible')) {
60
+ e.preventDefault(); // Stop form submission
61
+ // Disable Inputs
62
+ Spree.checkoutV2PaymentMethod.find('#name_on_card_'+Spree.checkoutV2PaymentMethodId+', #card_number, #card_expiry, #card_code').prop("disabled", true);
63
+ // Create Card Token
64
+ expiration = $('.cardExpiry:visible').payment('cardExpiryVal');
65
+ card = {
66
+ number: $('.cardNumber:visible').val(),
67
+ name: $('#name_on_card_'+Spree.checkoutV2PaymentMethodId+':visible').val(),
68
+ expiryMonth: expiration.month || 0,
69
+ expiryYear: expiration.year || 0,
70
+ cvv: $('.cardCode:visible').val()
71
+ };
72
+ CheckoutKit.createCardToken(card, function(response){
73
+ // If response has a card and id and not of type error, call the response handler.
74
+ // If it is an error, the added error handler above will pick it up
75
+ if (('id' in response) && ('card' in response) && !(response.type == 'error')) {
76
+ checkoutV2ResponseHandler(response);
77
+ }
78
+ });
79
+ }
80
+ });
81
+ });
82
+ </script>
83
+ <% end %>
@@ -0,0 +1,32 @@
1
+ # encoding: UTF-8
2
+
3
+ Gem::Specification.new do |s|
4
+ s.platform = Gem::Platform::RUBY
5
+ s.name = "solidus_gateway_checkout_v2"
6
+ s.version = "1.0.1"
7
+ s.summary = "Checkout V2 Payment Gateway for Solidus"
8
+ s.description = s.summary
9
+ s.required_ruby_version = ">= 2.1"
10
+
11
+ s.author = "James Whelton"
12
+ s.email = "james@whelton.io"
13
+ s.homepage = "https://github.com/whelton/solidus_gateway_checkout_v2"
14
+ s.license = %q{BSD-3}
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- spec/*`.split("\n")
18
+ s.require_path = "lib"
19
+ s.requirements << "none"
20
+
21
+ s.add_dependency "solidus_core", "~> 1.1"
22
+
23
+ s.add_development_dependency "rspec-rails", "~> 3.2"
24
+ s.add_development_dependency "simplecov"
25
+ s.add_development_dependency "sqlite3"
26
+ s.add_development_dependency "sass-rails"
27
+ s.add_development_dependency "coffee-rails"
28
+ s.add_development_dependency "factory_girl", "~> 4.4"
29
+ s.add_development_dependency "capybara"
30
+ s.add_development_dependency "poltergeist", "~> 1.5.0"
31
+ s.add_development_dependency "database_cleaner", "1.2.0"
32
+ end
@@ -0,0 +1,47 @@
1
+ require "simplecov"
2
+ SimpleCov.start "rails"
3
+
4
+ ENV["RAILS_ENV"] ||= "test"
5
+
6
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
7
+
8
+ require "rspec/rails"
9
+
10
+ require "capybara/rspec"
11
+ require 'capybara/poltergeist'
12
+
13
+ require "database_cleaner"
14
+ require "braintree"
15
+ require "ffaker"
16
+
17
+ require "spree/testing_support/factories"
18
+ require "spree/testing_support/order_walkthrough"
19
+
20
+ Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")].each { |f| require f }
21
+
22
+ RSpec.configure do |config|
23
+ config.infer_spec_type_from_file_location!
24
+ config.mock_with :rspec
25
+
26
+ config.filter_run focus: true
27
+ config.run_all_when_everything_filtered = true
28
+ config.use_transactional_fixtures = false
29
+
30
+ config.include FactoryGirl::Syntax::Methods
31
+
32
+ config.before :suite do
33
+ DatabaseCleaner.clean_with :truncation
34
+ end
35
+
36
+ config.before do
37
+ DatabaseCleaner.strategy = RSpec.current_example.metadata[:js] ? :truncation : :transaction
38
+ DatabaseCleaner.start
39
+ end
40
+
41
+ config.after do
42
+ DatabaseCleaner.clean
43
+ end
44
+
45
+ Capybara.javascript_driver = :poltergeist
46
+ FactoryGirl.find_definitions
47
+ end
metadata ADDED
@@ -0,0 +1,202 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: solidus_gateway_checkout_v2
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - James Whelton
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-01-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: solidus_core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.2'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: simplecov
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sqlite3
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: sass-rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: coffee-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: factory_girl
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '4.4'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '4.4'
111
+ - !ruby/object:Gem::Dependency
112
+ name: capybara
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: poltergeist
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 1.5.0
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 1.5.0
139
+ - !ruby/object:Gem::Dependency
140
+ name: database_cleaner
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '='
144
+ - !ruby/object:Gem::Version
145
+ version: 1.2.0
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '='
151
+ - !ruby/object:Gem::Version
152
+ version: 1.2.0
153
+ description: Checkout V2 Payment Gateway for Solidus
154
+ email: james@whelton.io
155
+ executables: []
156
+ extensions: []
157
+ extra_rdoc_files: []
158
+ files:
159
+ - ".gitignore"
160
+ - ".rspec"
161
+ - CONTRIBUTING.md
162
+ - Gemfile
163
+ - LICENSE.md
164
+ - README.md
165
+ - Rakefile
166
+ - app/models/spree/gateway/checkout_v2_gateway.rb
167
+ - bin/rails
168
+ - config/locales/en.yml
169
+ - config/routes.rb
170
+ - lib/active_merchant/billing/checkout_v2.rb
171
+ - lib/solidus_gateway_checkout_v2.rb
172
+ - lib/spree_gateway_checkout_v2/engine.rb
173
+ - lib/views/frontend/spree/checkout/payment/_checkout_v2.html.erb
174
+ - solidus_gateway_checkout_v2.gemspec
175
+ - spec/spec_helper.rb
176
+ homepage: https://github.com/whelton/solidus_gateway_checkout_v2
177
+ licenses:
178
+ - BSD-3
179
+ metadata: {}
180
+ post_install_message:
181
+ rdoc_options: []
182
+ require_paths:
183
+ - lib
184
+ required_ruby_version: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: '2.1'
189
+ required_rubygems_version: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - ">="
192
+ - !ruby/object:Gem::Version
193
+ version: '0'
194
+ requirements:
195
+ - none
196
+ rubyforge_project:
197
+ rubygems_version: 2.4.5
198
+ signing_key:
199
+ specification_version: 4
200
+ summary: Checkout V2 Payment Gateway for Solidus
201
+ test_files:
202
+ - spec/spec_helper.rb