spree_veritrans 1.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +1 -0
- data/Gemfile +6 -0
- data/README.md +26 -0
- data/app/models/active_merchant/billing/veritrans_gateway.rb +130 -0
- data/app/models/spree/gateway/veritrans_gateway.rb +88 -0
- data/config/locales/en.yml +12 -0
- data/lib/assets/javascripts/spree/frontend/spree_veritans.js +1 -0
- data/lib/assets/stylesheets/spree/frontend/spree_veritrans.css +3 -0
- data/lib/spree_veritrans.rb +4 -0
- data/lib/spree_veritrans/engine.rb +42 -0
- data/lib/views/backend/spree/admin/log_entries/_veritrans.html.erb +28 -0
- data/lib/views/backend/spree/admin/payments/source_forms/_veritrans.html.erb +1 -0
- data/lib/views/backend/spree/admin/payments/source_views/_veritrans.html.erb +1 -0
- data/lib/views/frontend/spree/checkout/payment/_veritrans.html.erb +109 -0
- data/spec/features/veritrans_checkout_spec.rb +98 -0
- data/spec/models/gateway/veritrans_gateway_spec.rb +132 -0
- data/spec/spec_helper.rb +50 -0
- data/spree_veritrans.gemspec +36 -0
- metadata +290 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: efed8e2800e36f96917e53bb62db12e8e60b4b87
|
4
|
+
data.tar.gz: 9ed89efdcaeaca3e0c5e29d1231e41f58ed5db56
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b827e565a47257ad33e11a79951136e248bbd72ba39ef9604a7e3cf151aafbbaecd231cc29c9b159fee81a62aa3b7e1e86cc79dd125f8e7d8875cce6888bdbd5
|
7
|
+
data.tar.gz: 1ff654282e9e96bb8808540d518637e60af6829b7f358b9ea479b4931356d42f860fbe6098354d3a601db0f9d5c33a56135a73dcb25253b38905aae17169c7c0
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Spree Veritrans
|
2
|
+
|
3
|
+
Veritrans Payment Gateway for Spree Commerce,
|
4
|
+
( this is only to use VT-Direct methods with 3D Secure transactions / normal transactions )
|
5
|
+
|
6
|
+
## How to use
|
7
|
+
|
8
|
+
### Add gem spree_veritrans
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'spree_veritrans'
|
12
|
+
```
|
13
|
+
|
14
|
+
bundle install
|
15
|
+
|
16
|
+
### Configure Keys on Admin Section
|
17
|
+
Goto admin section page, create new Payment method and select
|
18
|
+
Spree::Gateway::VeritransGateway as the provider
|
19
|
+
click Save and add client_key, server_key and url_api, you
|
20
|
+
also can use the 3D secure by enable it on admin section.
|
21
|
+
|
22
|
+
#### Get help
|
23
|
+
|
24
|
+
* [Veritrans sandbox login](https://my.sandbox.veritrans.co.id/login)
|
25
|
+
* [Veritrans sandbox registration](https://my.sandbox.veritrans.co.id/register)
|
26
|
+
* [Veritrans documentation](http://docs.veritrans.co.id)
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'uri'
|
3
|
+
require 'excon'
|
4
|
+
require 'active_support/core_ext/hash/slice'
|
5
|
+
|
6
|
+
module ActiveMerchant
|
7
|
+
module Billing
|
8
|
+
class VeritransGateway < Gateway
|
9
|
+
|
10
|
+
# == Veritrans Error Codes
|
11
|
+
# 400 Validation error ( Validation Error, merchant send bad request data example; validation error )
|
12
|
+
# => invalid transaction type
|
13
|
+
# => invalid credit card format
|
14
|
+
#
|
15
|
+
# 401 Access Denied Invalid client key or server key
|
16
|
+
# 402 Access Denied Merchant doesn't have access for this payment type
|
17
|
+
# 406 Duplicate Order ID Order ID has been used before or transaction has been paid.
|
18
|
+
# 410 Account Inactive Merchant account is deactivated or not active for a long period
|
19
|
+
# 411 Token error Token id is missing, invalid, or timed out
|
20
|
+
|
21
|
+
self.supported_cardtypes = [:visa, :master]
|
22
|
+
self.display_name = 'Veritrans'
|
23
|
+
|
24
|
+
# POST /v2/charge { payment_type: "vtdirect" }
|
25
|
+
# Docs http://docs.veritrans.co.id/sandbox/charge.html
|
26
|
+
def charge(data, config)
|
27
|
+
make_request(:post, config[:url_api] + "/v2/charge", data, config[:server_key])
|
28
|
+
end
|
29
|
+
|
30
|
+
# POST /v2/{id}/cancel
|
31
|
+
# Docs http://docs.veritrans.co.id/en/api/methods.html#Cancel
|
32
|
+
def cancel(transaction_id, config)
|
33
|
+
make_request(:post, config[:url_api] + "/v2/#{URI.escape(transaction_id)}/cancel", {}, config[:server_key])
|
34
|
+
end
|
35
|
+
|
36
|
+
# POST /v2/{id}/approve
|
37
|
+
# Docs http://docs.veritrans.co.id/en/api/methods.html#Approve
|
38
|
+
def approve(payment_id, options = {})
|
39
|
+
#request_with_logging(:post, config.api_host + "/v2/#{URI.escape(payment_id)}/approve", options)
|
40
|
+
end
|
41
|
+
|
42
|
+
# POST /v2/capture
|
43
|
+
# Docs http://docs.veritrans.co.id/en/api/methods.html#Capture
|
44
|
+
def capture(transaction_id, gross_amount, config)
|
45
|
+
make_request(:post, config[:url_api] + "/v2/capture", { transaction_id: transaction_id, gross_amount: gross_amount }, config[:server_key])
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def basic_auth_header(server_key)
|
51
|
+
key = Base64.strict_encode64(server_key + ":")
|
52
|
+
"Basic #{key}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def make_request(method, url, data, server_key = SERVER_KEY)
|
56
|
+
default_options = {}
|
57
|
+
|
58
|
+
# Add authentication and content type
|
59
|
+
# Docs http://docs.veritrans.co.id/sandbox/introduction.html
|
60
|
+
request_options = {
|
61
|
+
:path => URI.parse(url).path,
|
62
|
+
:headers => {
|
63
|
+
:Authorization => basic_auth_header(server_key),
|
64
|
+
:Accept => "application/json",
|
65
|
+
:"Content-Type" => "application/json",
|
66
|
+
:"User-Agent" => "Spree Veritrans gateway engine"
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
if method.to_s.upcase == "GET"
|
71
|
+
request_options[:query] = URI.encode_www_form(data)
|
72
|
+
else
|
73
|
+
request_options[:body] = _json_encode(data)
|
74
|
+
end
|
75
|
+
|
76
|
+
connection_options = {
|
77
|
+
read_timeout: 40,
|
78
|
+
write_timeout: 40,
|
79
|
+
connect_timeout: 40
|
80
|
+
}.deep_merge(default_options)
|
81
|
+
|
82
|
+
request = Excon.new(url, connection_options)
|
83
|
+
response = request.send(method, request_options)
|
84
|
+
|
85
|
+
result = _json_decode(response.body)
|
86
|
+
result = result.inject({}){|res,(k,v)| res[k.to_sym] = v; res}
|
87
|
+
success = result[:status_code] == "200"
|
88
|
+
msg = result[:status_message]
|
89
|
+
|
90
|
+
Response.new(success, msg, result, {
|
91
|
+
fraud_review: result[:fraud_status],
|
92
|
+
authorization: result[:transaction_id],
|
93
|
+
error_code: success ? nil : result[:status_code]
|
94
|
+
})
|
95
|
+
|
96
|
+
rescue Excon::Errors::SocketError => error
|
97
|
+
msg = "Internal server error, no response from backend. Try again later"
|
98
|
+
error_response = Excon::Response.new(
|
99
|
+
body: "{'status_code': '500', 'status_message': #{msg} }",
|
100
|
+
status: '500'
|
101
|
+
)
|
102
|
+
result = _json_decode(error_response.body)
|
103
|
+
result = result.inject({}){|res,(k,v)| res[k.to_sym] = v; res}
|
104
|
+
Response.new(false, msg, result, {
|
105
|
+
error_code: "500"
|
106
|
+
})
|
107
|
+
end
|
108
|
+
|
109
|
+
# Failback for activesupport
|
110
|
+
def _json_encode(params)
|
111
|
+
if defined?(ActiveSupport) && defined?(ActiveSupport::JSON)
|
112
|
+
ActiveSupport::JSON.encode(params)
|
113
|
+
else
|
114
|
+
require 'json' unless defined?(JSON)
|
115
|
+
JSON.generate(params)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def _json_decode(params)
|
120
|
+
if defined?(ActiveSupport) && defined?(ActiveSupport::JSON)
|
121
|
+
ActiveSupport::JSON.decode(params)
|
122
|
+
else
|
123
|
+
require 'json' unless defined?(JSON)
|
124
|
+
JSON.parse(params)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require "countries"
|
2
|
+
require "money"
|
3
|
+
|
4
|
+
module Spree
|
5
|
+
class Gateway::VeritransGateway < Gateway
|
6
|
+
|
7
|
+
preference :client_key, :string
|
8
|
+
preference :server_key, :string
|
9
|
+
preference :url_api, :string
|
10
|
+
preference :use_3d_secure, :boolean, :default => false
|
11
|
+
|
12
|
+
def method_type
|
13
|
+
'veritrans'
|
14
|
+
end
|
15
|
+
|
16
|
+
def provider_class
|
17
|
+
ActiveMerchant::Billing::VeritransGateway
|
18
|
+
end
|
19
|
+
|
20
|
+
def purchase(money, creditcard, gateway_options)
|
21
|
+
money = veritrans_gross_amount(money)
|
22
|
+
provider.charge(create_data_for_auth_or_charge(money, creditcard, gateway_options), { url_api: preferred_url_api, server_key: preferred_server_key })
|
23
|
+
end
|
24
|
+
|
25
|
+
def authorize(money, creditcard, gateway_options)
|
26
|
+
money = veritrans_gross_amount(money)
|
27
|
+
provider.charge(create_data_for_auth_or_charge(money, creditcard, gateway_options, preferred_use_3d_secure ? nil : "authorize"), { url_api: preferred_url_api, server_key: preferred_server_key })
|
28
|
+
end
|
29
|
+
|
30
|
+
def capture(money, response_code, gateway_options)
|
31
|
+
money = veritrans_gross_amount(money)
|
32
|
+
provider.capture(response_code, money, { url_api: preferred_url_api, server_key: preferred_server_key })
|
33
|
+
end
|
34
|
+
|
35
|
+
def void(response_code, gateway_options)
|
36
|
+
provider.cancel(response_code, { url_api: preferred_url_api, server_key: preferred_server_key })
|
37
|
+
end
|
38
|
+
|
39
|
+
def cancel(response_code)
|
40
|
+
provider.cancel(response_code, { url_api: preferred_url_api, server_key: preferred_server_key })
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def veritrans_gross_amount(money)
|
46
|
+
money = money.to_s
|
47
|
+
2.times { money.chomp!("0") }
|
48
|
+
money.to_i
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_data_for_auth_or_charge(money, creditcard, gateway_options, type = nil)
|
52
|
+
data = {}
|
53
|
+
data[:payment_type] = "credit_card"
|
54
|
+
data[:transaction_details] = { order_id: gateway_options[:order_id], gross_amount: money }
|
55
|
+
data[:credit_card] = {}
|
56
|
+
data[:credit_card][:token_id] = creditcard.gateway_payment_profile_id if creditcard.gateway_payment_profile_id
|
57
|
+
data[:credit_card][:type] = type unless type.nil?
|
58
|
+
data[:customer_details] = {}
|
59
|
+
data[:customer_details][:first_name] = creditcard.name
|
60
|
+
data[:customer_details][:email] = gateway_options[:email]
|
61
|
+
data[:customer_details][:billing_address] = {}
|
62
|
+
data[:customer_details][:billing_address][:first_name] = gateway_options[:billing_address][:name]
|
63
|
+
data[:customer_details][:billing_address][:last_name] = ""
|
64
|
+
data[:customer_details][:billing_address][:address] = "#{ gateway_options[:billing_address][:address1] } #{ gateway_options[:billing_address][:address2] }"
|
65
|
+
data[:customer_details][:billing_address][:city] = gateway_options[:billing_address][:city]
|
66
|
+
data[:customer_details][:billing_address][:postal_code] = gateway_options[:billing_address][:zip]
|
67
|
+
data[:customer_details][:billing_address][:phone] = gateway_options[:billing_address][:phone]
|
68
|
+
data[:customer_details][:billing_address][:country_code] = get_alpha3_country_code(gateway_options[:billing_address][:country])
|
69
|
+
data[:customer_details][:shipping_address] = {}
|
70
|
+
data[:customer_details][:shipping_address][:first_name] = gateway_options[:shipping_address][:name]
|
71
|
+
data[:customer_details][:shipping_address][:last_name] = ""
|
72
|
+
data[:customer_details][:shipping_address][:address] = "#{ gateway_options[:shipping_address][:address1] } #{ gateway_options[:billing_address][:address2] }"
|
73
|
+
data[:customer_details][:shipping_address][:city] = gateway_options[:shipping_address][:city]
|
74
|
+
data[:customer_details][:shipping_address][:postal_code] = gateway_options[:shipping_address][:zip]
|
75
|
+
data[:customer_details][:shipping_address][:phone] = gateway_options[:shipping_address][:phone]
|
76
|
+
data[:customer_details][:shipping_address][:country_code] = get_alpha3_country_code(gateway_options[:shipping_address][:country])
|
77
|
+
return data
|
78
|
+
end
|
79
|
+
|
80
|
+
def get_alpha3_country_code(country_code)
|
81
|
+
c = ISO3166::Country.new(country_code)
|
82
|
+
c.data["alpha3"]
|
83
|
+
rescue
|
84
|
+
return ""
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
---
|
2
|
+
en:
|
3
|
+
spree:
|
4
|
+
payment_has_been_cancelled: The payment has been cancelled.
|
5
|
+
log_entry:
|
6
|
+
veritrans:
|
7
|
+
message: Message
|
8
|
+
charge_id: Veritrans Charge ID
|
9
|
+
card_id: Veritrans Card ID
|
10
|
+
cvv_result: CVV Result
|
11
|
+
cvc_check: CVC Check
|
12
|
+
address_zip_check: Address ZIP check
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require spree/frontend
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module SpreeVeritrans
|
2
|
+
class Engine < Rails::Engine
|
3
|
+
engine_name 'spree_veritrans'
|
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::VeritransGateway
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.activate
|
12
|
+
if SpreeVeritrans::Engine.frontend_available?
|
13
|
+
Rails.application.config.assets.precompile += [
|
14
|
+
'lib/assets/javascripts/spree/frontend/spree_veritrans.js',
|
15
|
+
'lib/assets/javascripts/spree/frontend/spree_veritrans.css',
|
16
|
+
]
|
17
|
+
Dir.glob(File.join(File.dirname(__FILE__), "../../controllers/frontend/*/*_decorator*.rb")) do |c|
|
18
|
+
Rails.configuration.cache_classes ? require(c) : load(c)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.backend_available?
|
24
|
+
@@backend_available ||= ::Rails::Engine.subclasses.map(&:instance).map{ |e| e.class.to_s }.include?('Spree::Backend::Engine')
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.frontend_available?
|
28
|
+
@@frontend_available ||= ::Rails::Engine.subclasses.map(&:instance).map{ |e| e.class.to_s }.include?('Spree::Frontend::Engine')
|
29
|
+
end
|
30
|
+
|
31
|
+
if self.backend_available?
|
32
|
+
paths["app/views"] << "lib/views/backend"
|
33
|
+
end
|
34
|
+
|
35
|
+
if self.frontend_available?
|
36
|
+
paths["app/controllers"] << "lib/controllers/frontend"
|
37
|
+
paths["app/views"] << "lib/views/frontend"
|
38
|
+
end
|
39
|
+
|
40
|
+
config.to_prepare &method(:activate).to_proc
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<tr>
|
2
|
+
<td><%= Spree.t(:message, :scope => [:log_entry, :veritrans]) %></td>
|
3
|
+
<td><%= entry.parsed_details.message %></td>
|
4
|
+
</tr>
|
5
|
+
<tr>
|
6
|
+
<td><%= Spree.t(:charge_id, :scope => [:log_entry, :veritrans]) %></td>
|
7
|
+
<td><%= entry.parsed_details.params['id'] %></td>
|
8
|
+
</tr>
|
9
|
+
<% if card = entry.parsed_details.params['card'] %>
|
10
|
+
<tr>
|
11
|
+
<td><%= Spree.t(:card_id, :scope => [:log_entry, :veritrans]) %></td>
|
12
|
+
<td><%= card['id'] %></td>
|
13
|
+
</tr>
|
14
|
+
|
15
|
+
<tr>
|
16
|
+
<td><%= Spree.t(:cvc_check, :scope => [:log_entry, :veritrans]) %></td>
|
17
|
+
<td><%= card['cvc_check'] %></td>
|
18
|
+
</tr>
|
19
|
+
|
20
|
+
<tr>
|
21
|
+
<td><%= Spree.t(:address_zip_check, :scope => [:log_entry, :veritrans]) %></td>
|
22
|
+
<td><%= card['address_zip_check'] %></td>
|
23
|
+
</tr>
|
24
|
+
<% end %>
|
25
|
+
<tr>
|
26
|
+
<td><%= Spree.t(:cvv_result, :scope => [:log_entry, :veritrans]) %></td>
|
27
|
+
<td><%= entry.parsed_details.cvv_result['message'].to_s %></td>
|
28
|
+
</tr>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render "spree/admin/payments/source_forms/gateway", payment_method: payment_method, previous_cards: payment_method.reusable_sources(@order) %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render "spree/admin/payments/source_views/gateway", payment: payment %>
|
@@ -0,0 +1,109 @@
|
|
1
|
+
<%= render "spree/checkout/payment/gateway", payment_method: payment_method %>
|
2
|
+
|
3
|
+
<%= javascript_include_tag "#{payment_method.preferred_url_api}/v2/assets/veritrans.js" %>
|
4
|
+
|
5
|
+
<script type="text/javascript">
|
6
|
+
Veritrans.url = "<%= payment_method.preferred_url_api %>/v2/token";
|
7
|
+
Veritrans.client_key = "<%= payment_method.preferred_client_key %>";
|
8
|
+
</script>
|
9
|
+
|
10
|
+
<script>
|
11
|
+
var param_map = {
|
12
|
+
card_number: '#card_number',
|
13
|
+
card_exp_month: '#card_expiry',
|
14
|
+
card_exp_year: '#card_expiry',
|
15
|
+
card_cvv: '#card_code'
|
16
|
+
}
|
17
|
+
<%- if payment_method.preferred_use_3d_secure -%>
|
18
|
+
// Open 3DSecure dialog box
|
19
|
+
function openDialog(url) {
|
20
|
+
$('.modal').on('shown.bs.modal',function(){
|
21
|
+
$(this).find('iframe').attr('src',url);
|
22
|
+
})
|
23
|
+
$('.modal').modal({show:true});
|
24
|
+
}
|
25
|
+
|
26
|
+
// Close 3DSecure dialog box
|
27
|
+
function closeDialog() {
|
28
|
+
$('.modal').modal('hide');
|
29
|
+
}
|
30
|
+
<%- end -%>
|
31
|
+
|
32
|
+
// data params
|
33
|
+
function VT_createTokenData() {
|
34
|
+
var expiration = $('.cardExpiry:visible').payment('cardExpiryVal');
|
35
|
+
return {
|
36
|
+
card_number: $('.cardNumber:visible').val(),
|
37
|
+
card_cvv: $('.cardCode:visible').val(),
|
38
|
+
card_exp_month: expiration.month || 0,
|
39
|
+
card_exp_year: expiration.year || 0,
|
40
|
+
<%- if payment_method.preferred_use_3d_secure -%>
|
41
|
+
secure: true,
|
42
|
+
<%- end -%>
|
43
|
+
gross_amount: <%= @order.total.to_i -%>
|
44
|
+
};
|
45
|
+
}
|
46
|
+
|
47
|
+
Spree.veritransPaymentMethod = $('#payment_method_' + <%= payment_method.id %>);
|
48
|
+
|
49
|
+
var veritransResponseHandler = function(response) {
|
50
|
+
var paymentMethodId, token_id;
|
51
|
+
<%- if payment_method.preferred_use_3d_secure -%>
|
52
|
+
if (response.redirect_url) {
|
53
|
+
Spree.veritransPaymentMethod.find('#card_number, #card_expiry, #card_code').prop("disabled", true);
|
54
|
+
openDialog(response.redirect_url);
|
55
|
+
}
|
56
|
+
else
|
57
|
+
<%- end -%>
|
58
|
+
if (response.status_code == '200') {
|
59
|
+
<%- if payment_method.preferred_use_3d_secure -%>
|
60
|
+
// success 3d secure or success normal
|
61
|
+
//close 3d secure dialog if any
|
62
|
+
closeDialog();
|
63
|
+
<%- end -%>
|
64
|
+
token_id = response.token_id;
|
65
|
+
paymentMethodId = Spree.veritransPaymentMethod.prop('id').split("_")[2];
|
66
|
+
// store token data in input #token_id and then submit form to merchant server
|
67
|
+
Spree.veritransPaymentMethod.append("<input type='hidden' class='veritransToken' name='payment_source[" + paymentMethodId + "][gateway_payment_profile_id]' value='" + token_id + "'/>");
|
68
|
+
return Spree.veritransPaymentMethod.parents("form").trigger('submit');
|
69
|
+
} else {
|
70
|
+
<%- if payment_method.preferred_use_3d_secure -%>
|
71
|
+
closeDialog();
|
72
|
+
<%- end -%>
|
73
|
+
$('#veritransError').html(response.status_message);
|
74
|
+
if (response.validation_messages) {
|
75
|
+
$.map( response.validation_messages, function( data, i ) {
|
76
|
+
$.each([ "card_number", "card_cvv", "card_exp_month", "card_exp_year" ], function( i, val ) {
|
77
|
+
if(data.indexOf(val) !== -1) {
|
78
|
+
Spree.veritransPaymentMethod.find(param_map[val]).addClass('error');
|
79
|
+
}
|
80
|
+
});
|
81
|
+
});
|
82
|
+
}
|
83
|
+
return $('#veritransError').show();
|
84
|
+
}
|
85
|
+
};
|
86
|
+
|
87
|
+
$(document).ready(function() {
|
88
|
+
Spree.veritransPaymentMethod.prepend("<div id='veritransError' class='errorExplanation' style='display:none'></div>");
|
89
|
+
return $('#checkout_form_payment [data-hook=buttons]').click(function() {
|
90
|
+
$('#veritransError').hide();
|
91
|
+
Spree.veritransPaymentMethod.find('#card_number, #card_expiry, #card_code').removeClass('error');
|
92
|
+
if (Spree.veritransPaymentMethod.is(':visible')) {
|
93
|
+
Veritrans.token(VT_createTokenData, veritransResponseHandler);
|
94
|
+
return false;
|
95
|
+
}
|
96
|
+
});
|
97
|
+
});
|
98
|
+
</script>
|
99
|
+
|
100
|
+
<%- if payment_method.preferred_use_3d_secure -%>
|
101
|
+
<div id="veritansModal" class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
|
102
|
+
<div class="modal-dialog modal-lg" style="width:400px">
|
103
|
+
<div class="modal-content">
|
104
|
+
<iframe src="" frameborder="0" width="400px" height="420px"></iframe>
|
105
|
+
</div>
|
106
|
+
</div>
|
107
|
+
</div>
|
108
|
+
<%- end -%>
|
109
|
+
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Veritrans checkout" do
|
4
|
+
let!(:country) { create(:country, :states_required => true) }
|
5
|
+
let!(:state) { create(:state, :country => country) }
|
6
|
+
let!(:shipping_method) { create(:shipping_method) }
|
7
|
+
let!(:stock_location) { create(:stock_location) }
|
8
|
+
let!(:mug) { create(:product, :name => "RoR Mug") }
|
9
|
+
let!(:stripe_payment_method) do
|
10
|
+
Spree::Gateway::VeritransGateway.create!(
|
11
|
+
:name => "Veritrans",
|
12
|
+
:preferred_client_key => "VT-client-BO3Lm5WmKlzxg9FI",
|
13
|
+
:preferred_server_key => "VT-server-HvU2kqGsVjV08_t79cN8yPiK",
|
14
|
+
:preferred_url_api => "https://api.sandbox.veritrans.co.id"
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
let!(:zone) { create(:zone) }
|
19
|
+
|
20
|
+
before do
|
21
|
+
user = create(:user)
|
22
|
+
|
23
|
+
order = OrderWalkthrough.up_to(:delivery)
|
24
|
+
order.stub :confirmation_required? => true
|
25
|
+
|
26
|
+
order.reload
|
27
|
+
order.user = user
|
28
|
+
order.update!
|
29
|
+
|
30
|
+
Spree::CheckoutController.any_instance.stub(:current_order => order)
|
31
|
+
Spree::CheckoutController.any_instance.stub(:try_spree_current_user => user)
|
32
|
+
Spree::CheckoutController.any_instance.stub(:skip_state_validation? => true)
|
33
|
+
|
34
|
+
visit spree.checkout_state_path(:payment)
|
35
|
+
end
|
36
|
+
|
37
|
+
# This will pass the CC data to the server and the VeritransGateway class handles it
|
38
|
+
it "cannot process a valid payment without tokenid" do
|
39
|
+
fill_in "Card Number", :with => "4011 1111 1111 1112"
|
40
|
+
fill_in "Card Code", :with => "123"
|
41
|
+
fill_in "Expiration", :with => "01 / 20"
|
42
|
+
click_button "Save and Continue"
|
43
|
+
page.current_url.should include("/checkout/confirm")
|
44
|
+
click_button "Place Order"
|
45
|
+
page.should have_content("Token id is missing, invalid, or timed out")
|
46
|
+
end
|
47
|
+
|
48
|
+
# This will fetch a token from Veritrans.com and then pass that to the webserver.
|
49
|
+
# The server then processes the payment using that token.
|
50
|
+
it "can process a valid payment (with JS)", :js => true do
|
51
|
+
fill_in "Card Number", :with => "4011 1111 1111 1112"
|
52
|
+
# Otherwise ccType field does not get updated correctly
|
53
|
+
page.execute_script("$('.cardNumber').trigger('change')")
|
54
|
+
fill_in "Card Code", :with => "123"
|
55
|
+
fill_in "Expiration", :with => "01 / 20"
|
56
|
+
click_button "Save and Continue"
|
57
|
+
sleep(5) # Wait for Veritrans API to return + form to submit
|
58
|
+
page.current_url.should include("/checkout/confirm")
|
59
|
+
click_button "Place Order"
|
60
|
+
page.should have_content("Your order has been processed successfully")
|
61
|
+
end
|
62
|
+
|
63
|
+
it "shows an error with an invalid credit card number", :js => true do
|
64
|
+
click_button "Save and Continue"
|
65
|
+
page.should have_content("Invalid card_number association")
|
66
|
+
page.should have_css('#card_number.error')
|
67
|
+
end
|
68
|
+
|
69
|
+
it "shows an error with invalid security fields", :js => true do
|
70
|
+
fill_in "Card Number", :with => "4011 1111 1111 1112"
|
71
|
+
fill_in "Expiration", :with => "01 / 20"
|
72
|
+
click_button "Save and Continue"
|
73
|
+
page.should have_content("card_cvv must be 3 digits")
|
74
|
+
page.should have_content("card_cvv is required")
|
75
|
+
page.should have_content("card_cvv does not match with regular expression")
|
76
|
+
page.should have_css('#card_code.error')
|
77
|
+
end
|
78
|
+
|
79
|
+
it "shows an error with invalid expiry month field", :js => true do
|
80
|
+
fill_in "Card Number", :with => "4011 1111 1111 1112"
|
81
|
+
fill_in "Expiration", :with => "00 / 20"
|
82
|
+
fill_in "Card Code", :with => "123"
|
83
|
+
click_button "Save and Continue"
|
84
|
+
page.should have_content("card_exp_month must be between 1 and 12")
|
85
|
+
page.should have_css('#card_expiry.error')
|
86
|
+
end
|
87
|
+
|
88
|
+
it "shows an error with invalid expiry year field", :js => true do
|
89
|
+
fill_in "Card Number", :with => "4011 1111 1111 1112"
|
90
|
+
fill_in "Expiration", :with => "12 / "
|
91
|
+
fill_in "Card Code", :with => "123"
|
92
|
+
click_button "Save and Continue"
|
93
|
+
page.should have_content("card_exp_year must be greater than this year")
|
94
|
+
page.should have_content("card_expire_month must be greater than this year's month")
|
95
|
+
page.should have_content("card_exp_year must be 4 digits")
|
96
|
+
page.should have_css('#card_expiry.error')
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spree::Gateway::VeritransGateway do
|
4
|
+
let(:client_key) { 'XXXX-YYYY' }
|
5
|
+
let(:server_key) { 'YYYY-ZZZZ' }
|
6
|
+
let(:url_api) { 'https://api/url' }
|
7
|
+
let(:email) { 'customer@example.com' }
|
8
|
+
let(:source) { Spree::CreditCard.new(gateway_payment_profile_id: 'tok_profileid') }
|
9
|
+
|
10
|
+
let(:payment) {
|
11
|
+
double('Spree::Payment',
|
12
|
+
source: source,
|
13
|
+
order: double('Spree::Order',
|
14
|
+
email: email,
|
15
|
+
bill_address: bill_address
|
16
|
+
)
|
17
|
+
)
|
18
|
+
}
|
19
|
+
|
20
|
+
let(:provider) do
|
21
|
+
double('provider').tap do |p|
|
22
|
+
p.stub(:purchase)
|
23
|
+
p.stub(:authorize)
|
24
|
+
p.stub(:capture)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
let(:gateway_options) {
|
29
|
+
{
|
30
|
+
order_id: "xxx",
|
31
|
+
email: email,
|
32
|
+
billing_address: {
|
33
|
+
name: "#{ Faker::Name.first_name } #{ Faker::Name.last_name }",
|
34
|
+
address1: Faker::Address.street_address,
|
35
|
+
address2: Faker::Address.street_name,
|
36
|
+
city: Faker::Address.city,
|
37
|
+
zip: Faker::AddressUS.zip_code,
|
38
|
+
phone: Faker::PhoneNumber.phone_number,
|
39
|
+
country: Faker::Address.country_code
|
40
|
+
},
|
41
|
+
shipping_address: {
|
42
|
+
name: "#{ Faker::Name.first_name } #{ Faker::Name.last_name }",
|
43
|
+
address1: Faker::Address.street_address,
|
44
|
+
address2: Faker::Address.street_name,
|
45
|
+
city: Faker::Address.city,
|
46
|
+
zip: Faker::AddressUS.zip_code,
|
47
|
+
phone: Faker::PhoneNumber.phone_number,
|
48
|
+
country: Faker::Address.country_code
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
before do
|
54
|
+
subject.preferences = { client_key: client_key, server_key: server_key, url_api: url_api }
|
55
|
+
subject.stub(:provider).and_return provider
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'purchasing' do
|
59
|
+
after do
|
60
|
+
subject.purchase(19900000, source, gateway_options)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'send the payment to the provider' do
|
64
|
+
provider.should_receive(:charge).with(anything, { url_api: url_api, server_key: server_key })
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'authorizing' do
|
69
|
+
after do
|
70
|
+
subject.authorize(19900000, source, gateway_options)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'send the authorization to the provider' do
|
74
|
+
provider.should_receive(:charge).with(anything, { url_api: url_api, server_key: server_key })
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'capturing' do
|
79
|
+
after do
|
80
|
+
subject.capture(12000000, '1234', {})
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'convert the amount to gross_amount' do
|
84
|
+
provider.should_receive(:capture).with('1234', 120000, { url_api: url_api, server_key: server_key })
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'capture with payment class' do
|
89
|
+
let(:gateway) do
|
90
|
+
gateway = described_class.new(active: true)
|
91
|
+
gateway.set_preference :server_key, server_key
|
92
|
+
gateway.set_preference :url_api, url_api
|
93
|
+
gateway.stub(:provider).and_return provider
|
94
|
+
gateway.stub :source_required => true
|
95
|
+
gateway
|
96
|
+
end
|
97
|
+
|
98
|
+
let(:order) { Spree::Order.create }
|
99
|
+
|
100
|
+
let(:card) do
|
101
|
+
# mock_model(Spree::CreditCard, :gateway_customer_profile_id => 'cus_abcde',
|
102
|
+
# :imported => false)
|
103
|
+
create :credit_card, gateway_customer_profile_id: 'cus_abcde', imported: false
|
104
|
+
end
|
105
|
+
|
106
|
+
let(:payment) do
|
107
|
+
payment = Spree::Payment.new
|
108
|
+
payment.source = card
|
109
|
+
payment.order = order
|
110
|
+
payment.payment_method = gateway
|
111
|
+
payment.amount = 9855
|
112
|
+
payment.state = 'pending'
|
113
|
+
payment.response_code = '12345'
|
114
|
+
payment
|
115
|
+
end
|
116
|
+
|
117
|
+
let!(:success_response) do
|
118
|
+
double('success_response', :success? => true,
|
119
|
+
:authorization => '123',
|
120
|
+
:avs_result => { 'code' => 'avs-code' },
|
121
|
+
:cvv_result => { 'code' => 'cvv-code', 'message' => "CVV Result"})
|
122
|
+
end
|
123
|
+
|
124
|
+
after do
|
125
|
+
payment.capture!
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'gets correct amount' do
|
129
|
+
provider.should_receive(:capture).with('12345', 9855,{ url_api: url_api, server_key: server_key }).and_return(success_response)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
ENV["RAILS_ENV"] = "test"
|
2
|
+
|
3
|
+
require File.expand_path("../dummy/config/environment.rb", __FILE__)
|
4
|
+
|
5
|
+
require 'rspec/rails'
|
6
|
+
require 'rspec/active_model/mocks'
|
7
|
+
require 'capybara/rspec'
|
8
|
+
require 'capybara/rails'
|
9
|
+
require 'capybara/poltergeist'
|
10
|
+
require 'database_cleaner'
|
11
|
+
require 'ffaker'
|
12
|
+
require 'pry'
|
13
|
+
require 'rspec/active_model/mocks'
|
14
|
+
|
15
|
+
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
|
16
|
+
|
17
|
+
require 'spree/testing_support/factories'
|
18
|
+
require 'spree/testing_support/order_walkthrough'
|
19
|
+
require 'spree/testing_support/preferences'
|
20
|
+
|
21
|
+
FactoryGirl.find_definitions
|
22
|
+
|
23
|
+
RSpec.configure do |config|
|
24
|
+
config.infer_spec_type_from_file_location!
|
25
|
+
config.mock_with :rspec
|
26
|
+
config.raise_errors_for_deprecations!
|
27
|
+
config.use_transactional_fixtures = false
|
28
|
+
#config.filter_run focus: true
|
29
|
+
#config.filter_run_excluding slow: true
|
30
|
+
|
31
|
+
config.include FactoryGirl::Syntax::Methods
|
32
|
+
config.include Spree::TestingSupport::Preferences
|
33
|
+
|
34
|
+
config.before :suite do
|
35
|
+
DatabaseCleaner.strategy = :transaction
|
36
|
+
DatabaseCleaner.clean_with :truncation
|
37
|
+
end
|
38
|
+
|
39
|
+
config.before do
|
40
|
+
DatabaseCleaner.strategy = RSpec.current_example.metadata[:js] ? :truncation : :transaction
|
41
|
+
DatabaseCleaner.start
|
42
|
+
reset_spree_preferences
|
43
|
+
end
|
44
|
+
|
45
|
+
config.after do
|
46
|
+
DatabaseCleaner.clean
|
47
|
+
end
|
48
|
+
|
49
|
+
Capybara.javascript_driver = :poltergeist
|
50
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
Gem::Specification.new do |s|
|
3
|
+
s.platform = Gem::Platform::RUBY
|
4
|
+
s.name = 'spree_veritrans'
|
5
|
+
s.version = '1.0.0'
|
6
|
+
s.summary = 'Additional Payment Gateways for Spree Commerce using Veritrans'
|
7
|
+
s.description = s.summary
|
8
|
+
|
9
|
+
s.author = 'fajri fachriansyah'
|
10
|
+
s.email = 'fajri82@gmail.com'
|
11
|
+
s.homepage = 'http://www.spreecommerce.com'
|
12
|
+
s.license = %q{BSD-3}
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
16
|
+
s.require_path = 'lib'
|
17
|
+
s.requirements << 'none'
|
18
|
+
|
19
|
+
s.add_dependency 'spree_core', '~> 3.0.0'
|
20
|
+
s.add_runtime_dependency 'excon', '~> 0.20'
|
21
|
+
s.add_runtime_dependency 'countries', '1.0.0'
|
22
|
+
|
23
|
+
s.add_development_dependency 'capybara'
|
24
|
+
s.add_development_dependency 'coffee-rails', '~> 4.0.0'
|
25
|
+
s.add_development_dependency 'database_cleaner', '1.2.0'
|
26
|
+
s.add_development_dependency 'factory_girl', '~> 4.4'
|
27
|
+
s.add_development_dependency 'ffaker'
|
28
|
+
s.add_development_dependency 'launchy'
|
29
|
+
s.add_development_dependency 'sqlite3'
|
30
|
+
s.add_development_dependency 'poltergeist', '~> 1.6.0'
|
31
|
+
s.add_development_dependency 'pry'
|
32
|
+
s.add_development_dependency 'rspec-activemodel-mocks'
|
33
|
+
s.add_development_dependency 'rspec-rails', '~> 2.99'
|
34
|
+
s.add_development_dependency 'sass-rails', '~> 4.0.2'
|
35
|
+
s.add_development_dependency 'selenium-webdriver'
|
36
|
+
end
|
metadata
ADDED
@@ -0,0 +1,290 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spree_veritrans
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- fajri fachriansyah
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-09-03 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: spree_core
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: excon
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.20'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.20'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: countries
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.0.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.0.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: capybara
|
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: coffee-rails
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 4.0.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 4.0.0
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: database_cleaner
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.2.0
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.2.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: ffaker
|
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: launchy
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: sqlite3
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: poltergeist
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: 1.6.0
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: 1.6.0
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: pry
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: rspec-activemodel-mocks
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: rspec-rails
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - "~>"
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '2.99'
|
202
|
+
type: :development
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - "~>"
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '2.99'
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: sass-rails
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - "~>"
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: 4.0.2
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - "~>"
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: 4.0.2
|
223
|
+
- !ruby/object:Gem::Dependency
|
224
|
+
name: selenium-webdriver
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
226
|
+
requirements:
|
227
|
+
- - ">="
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: '0'
|
230
|
+
type: :development
|
231
|
+
prerelease: false
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
233
|
+
requirements:
|
234
|
+
- - ">="
|
235
|
+
- !ruby/object:Gem::Version
|
236
|
+
version: '0'
|
237
|
+
description: Additional Payment Gateways for Spree Commerce using Veritrans
|
238
|
+
email: fajri82@gmail.com
|
239
|
+
executables: []
|
240
|
+
extensions: []
|
241
|
+
extra_rdoc_files: []
|
242
|
+
files:
|
243
|
+
- ".gitignore"
|
244
|
+
- ".rspec"
|
245
|
+
- Gemfile
|
246
|
+
- README.md
|
247
|
+
- app/models/active_merchant/billing/veritrans_gateway.rb
|
248
|
+
- app/models/spree/gateway/veritrans_gateway.rb
|
249
|
+
- config/locales/en.yml
|
250
|
+
- lib/assets/javascripts/spree/frontend/spree_veritans.js
|
251
|
+
- lib/assets/stylesheets/spree/frontend/spree_veritrans.css
|
252
|
+
- lib/spree_veritrans.rb
|
253
|
+
- lib/spree_veritrans/engine.rb
|
254
|
+
- lib/views/backend/spree/admin/log_entries/_veritrans.html.erb
|
255
|
+
- lib/views/backend/spree/admin/payments/source_forms/_veritrans.html.erb
|
256
|
+
- lib/views/backend/spree/admin/payments/source_views/_veritrans.html.erb
|
257
|
+
- lib/views/frontend/spree/checkout/payment/_veritrans.html.erb
|
258
|
+
- spec/features/veritrans_checkout_spec.rb
|
259
|
+
- spec/models/gateway/veritrans_gateway_spec.rb
|
260
|
+
- spec/spec_helper.rb
|
261
|
+
- spree_veritrans.gemspec
|
262
|
+
homepage: http://www.spreecommerce.com
|
263
|
+
licenses:
|
264
|
+
- BSD-3
|
265
|
+
metadata: {}
|
266
|
+
post_install_message:
|
267
|
+
rdoc_options: []
|
268
|
+
require_paths:
|
269
|
+
- lib
|
270
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
271
|
+
requirements:
|
272
|
+
- - ">="
|
273
|
+
- !ruby/object:Gem::Version
|
274
|
+
version: '0'
|
275
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
276
|
+
requirements:
|
277
|
+
- - ">="
|
278
|
+
- !ruby/object:Gem::Version
|
279
|
+
version: '0'
|
280
|
+
requirements:
|
281
|
+
- none
|
282
|
+
rubyforge_project:
|
283
|
+
rubygems_version: 2.4.8
|
284
|
+
signing_key:
|
285
|
+
specification_version: 4
|
286
|
+
summary: Additional Payment Gateways for Spree Commerce using Veritrans
|
287
|
+
test_files:
|
288
|
+
- spec/features/veritrans_checkout_spec.rb
|
289
|
+
- spec/models/gateway/veritrans_gateway_spec.rb
|
290
|
+
- spec/spec_helper.rb
|