exact4r 1.2 → 1.4
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.
- data/CHANGELOG +7 -0
- data/VERSION +1 -1
- data/lib/ews/certificate_helper.rb +63 -0
- data/lib/ews/transaction/request.rb +4 -0
- data/lib/ews/transaction/validator.rb +15 -3
- data/lib/ews/transporter.rb +7 -49
- data/pkg/exact4r-1.2.gem +0 -0
- data/test/credentials.yml +19 -1
- data/test/exhaustive/forced_post_test.rb +7 -1
- data/test/exhaustive/referenced_void_test.rb +131 -0
- data/test/exhaustive/refund_correction_test.rb +1 -1
- data/test/exhaustive/tagged_update_test.rb +158 -0
- data/test/exhaustive/transaction_details_test.rb +6 -5
- data/test/exhaustive/void_test.rb +44 -7
- data/test/general/transporter_test.rb +21 -1
- data/test/test_helper.rb +6 -4
- metadata +31 -13
data/CHANGELOG
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.4
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module EWS # :nodoc:
|
2
|
+
module CertificateHelper
|
3
|
+
|
4
|
+
EXACT_ISSUER_CERT_FILE = File.dirname(__FILE__)+"/../../certs/valicert_class2_root.crt" unless defined?(EXACT_ISSUER_CERT_FILE)
|
5
|
+
EXACT_SERVER_CERT_FILE = File.dirname(__FILE__)+"/../../certs/e-xact.com.crt" unless defined?(EXACT_SERVER_CERT_FILE)
|
6
|
+
|
7
|
+
attr_accessor :issuer_cert_file, :server_cert
|
8
|
+
|
9
|
+
def configure_certificates(options)
|
10
|
+
self.issuer_cert_file = (options[:issuer_cert] || EXACT_ISSUER_CERT_FILE)
|
11
|
+
server_cert_file = (options[:server_cert] || EXACT_SERVER_CERT_FILE)
|
12
|
+
self.server_cert = File.new(server_cert_file).read
|
13
|
+
end
|
14
|
+
private :configure_certificates
|
15
|
+
|
16
|
+
def validate_certificate(is_ok, ctx)
|
17
|
+
cert = ctx.current_cert
|
18
|
+
return false if cert.nil?
|
19
|
+
|
20
|
+
# preverify failed?
|
21
|
+
return false unless is_ok
|
22
|
+
|
23
|
+
self_signed = false
|
24
|
+
ca = false
|
25
|
+
pathlen = nil
|
26
|
+
server_auth = true
|
27
|
+
self_signed = (cert.subject.cmp(cert.issuer) == 0)
|
28
|
+
|
29
|
+
# Check extensions for the certificate purpose according to http://www.openssl.org/docs/apps/x509.html (Certificate Extensions) and
|
30
|
+
# http://www.ietf.org/rfc/rfc3280.txt.
|
31
|
+
cert.extensions.each do |ex|
|
32
|
+
case ex.oid
|
33
|
+
when 'basicConstraints'
|
34
|
+
/CA:(TRUE|FALSE)(?:, pathlen:)*(\d*)/ =~ ex.value
|
35
|
+
ca ||= ($1 == 'TRUE')
|
36
|
+
pathlen = $2.to_i
|
37
|
+
when 'keyUsage'
|
38
|
+
usage = ex.value.split(/\s*,\s*/)
|
39
|
+
# a CA must have
|
40
|
+
ca &&= !usage.grep(/Certificate Sign/i).empty?
|
41
|
+
# Server Cert Must have
|
42
|
+
server_auth &&= !usage.grep(/Key Encipherment/i).empty?
|
43
|
+
when 'extendedKeyUsage'
|
44
|
+
usage = ex.value.split(/\s*,\s*/)
|
45
|
+
# Server Cert Must have
|
46
|
+
server_auth &&= !usage.grep(/TLS Web Server Authentication/i).empty?
|
47
|
+
when 'nsCertType'
|
48
|
+
usage = ex.value.split(/\s*,\s*/)
|
49
|
+
ca ||= !usage.grep(/SSL CA/i).empty?
|
50
|
+
server_auth ||= !usage.grep(/SSL Server/i).empty?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# We're looking for the server cert, so accept all CAs (which have already passed pre-verification)
|
55
|
+
return true if self_signed || ca
|
56
|
+
|
57
|
+
# ensure the server cert is the one we're expecting
|
58
|
+
return server_auth && self.server_cert == cert.to_pem
|
59
|
+
end
|
60
|
+
private :validate_certificate
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -37,6 +37,8 @@ module EWS # :nodoc:
|
|
37
37
|
# :tagged_void
|
38
38
|
# :tagged_refund
|
39
39
|
# :tagged_online_debit_refund
|
40
|
+
# :tagged_update
|
41
|
+
# :referenced_void
|
40
42
|
# :recurring_seed_pre_auth
|
41
43
|
# :recurring_seed_purchase
|
42
44
|
# :idebit_purchase
|
@@ -113,6 +115,8 @@ METHOD_EOS
|
|
113
115
|
:tagged_void => '33',
|
114
116
|
:tagged_refund => '34',
|
115
117
|
:tagged_online_debit_refund => '35',
|
118
|
+
:referenced_void => '36',
|
119
|
+
:tagged_update => '37',
|
116
120
|
:recurring_seed_pre_auth => '40',
|
117
121
|
:recurring_seed_purchase => '41',
|
118
122
|
:idebit_purchase => '50',
|
@@ -40,6 +40,8 @@ module EWS # :nodoc:
|
|
40
40
|
|
41
41
|
if self.transaction_type == "CR"
|
42
42
|
append_error(:transaction_tag, "transaction_tag must be supplied") if self.transaction_tag.to_i < 1
|
43
|
+
elsif self.transaction_type == "36"
|
44
|
+
validate_referenced_void
|
43
45
|
elsif %w(80 81).include?(self.transaction_type)
|
44
46
|
# do nothing, no validation required
|
45
47
|
elsif %w(50 54).include?(self.transaction_type)
|
@@ -166,12 +168,13 @@ module EWS # :nodoc:
|
|
166
168
|
def validate_for_transaction_tag
|
167
169
|
tt = self.transaction_type
|
168
170
|
|
169
|
-
# mandatory: transaction_type must == (30, 31, 32, 33, 34, 35)
|
170
|
-
append_error(:transaction_tag, "transaction_tag must only be set for tagged transactions") unless %w(30 31 32 33 34 35 CR).include?(tt)
|
171
|
+
# mandatory: transaction_type must == (30, 31, 32, 33, 34, 35, 37, CR)
|
172
|
+
append_error(:transaction_tag, "transaction_tag must only be set for tagged transactions") unless %w(30 31 32 33 34 35 37 CR).include?(tt)
|
171
173
|
|
172
174
|
# transaction_tag, auth_num & amount mandatory
|
173
175
|
mandatory = [:transaction_tag]
|
174
|
-
mandatory <<
|
176
|
+
mandatory << :authorization_num unless tt == 'CR'
|
177
|
+
mandatory << :amount unless %w(CR 37).include?(tt)
|
175
178
|
|
176
179
|
# ensure no cc details sent
|
177
180
|
append_error(:cc_number, "do not set cc_number for tagged transactions") unless self.cc_number.blank?
|
@@ -227,6 +230,15 @@ module EWS # :nodoc:
|
|
227
230
|
check_mandatory(mandatory)
|
228
231
|
end
|
229
232
|
|
233
|
+
def validate_referenced_void
|
234
|
+
[:cc_number, :pan, :track1, :track2, :transaction_tag].each do |attr_name|
|
235
|
+
append_error(attr_name, "#{attr_name} must not be set for referenced_void transactions") unless self.send(attr_name).nil?
|
236
|
+
end
|
237
|
+
|
238
|
+
check_mandatory([:reference_no, :customer_ref, :amount])
|
239
|
+
end
|
240
|
+
|
241
|
+
|
230
242
|
def check_mandatory(mandatory)
|
231
243
|
mandatory.each do |key|
|
232
244
|
append_error(key, "#{key} must be supplied") if self.send(key).blank?
|
data/lib/ews/transporter.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'net/https'
|
2
|
+
require File.dirname(__FILE__) + '/certificate_helper'
|
2
3
|
|
3
4
|
module EWS # :nodoc:
|
4
5
|
|
@@ -15,6 +16,7 @@ module EWS # :nodoc:
|
|
15
16
|
# Once configured to connect to a particular service, it can be used repeatedly
|
16
17
|
# to send as many transactions as required.
|
17
18
|
class Transporter
|
19
|
+
include CertificateHelper
|
18
20
|
|
19
21
|
# Initialize a Transporter.
|
20
22
|
#
|
@@ -23,6 +25,8 @@ module EWS # :nodoc:
|
|
23
25
|
#
|
24
26
|
# You can also specify a hash of options as follows:
|
25
27
|
# :transport_type the transport_type for this transporter (defaults to :rest)
|
28
|
+
# :server_cert the path to the server's certificate file (defaults to E-xact's Server Cert)
|
29
|
+
# :issuer_cert the path to the issuer's certificate file (defaults to E-xact's Issuer's Cert)
|
26
30
|
#
|
27
31
|
# The default certificates are those required to connect to https://api.e-xact.com and the
|
28
32
|
# default <tt>transport_type</tt> is <tt>:rest</tt>. The default <tt>transport_type</tt> can be overridden on a per-transaction
|
@@ -31,8 +35,7 @@ module EWS # :nodoc:
|
|
31
35
|
@url = URI.parse(url.gsub(/\/$/,''))
|
32
36
|
@transport_type = options[:transport_type] || :rest
|
33
37
|
|
34
|
-
|
35
|
-
@@server_cert ||= File.new(File.dirname(__FILE__)+"/../../certs/e-xact.com.crt").read
|
38
|
+
configure_certificates(options)
|
36
39
|
end
|
37
40
|
|
38
41
|
# Submit a transaction request to the server
|
@@ -52,7 +55,7 @@ module EWS # :nodoc:
|
|
52
55
|
request = build_http_request(transaction, transport_type, transport_details[:suffix])
|
53
56
|
request.basic_auth(transaction.gateway_id, transaction.password)
|
54
57
|
request.add_field "Accept", transport_details[:content_type]
|
55
|
-
request.add_field "User-Agent", "exact4r v1.
|
58
|
+
request.add_field "User-Agent", "exact4r v1.4"
|
56
59
|
request.add_field "Content-type", "#{transport_details[:content_type]}; charset=UTF-8"
|
57
60
|
|
58
61
|
response = get_connection.request(request)
|
@@ -106,56 +109,11 @@ private
|
|
106
109
|
@connection.use_ssl = true
|
107
110
|
@connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
108
111
|
@connection.verify_callback = method(:validate_certificate)
|
109
|
-
@connection.ca_file =
|
112
|
+
@connection.ca_file = self.issuer_cert_file
|
110
113
|
end
|
111
114
|
@connection
|
112
115
|
end
|
113
116
|
|
114
|
-
def validate_certificate(is_ok, ctx)
|
115
|
-
cert = ctx.current_cert
|
116
|
-
return false if cert.nil?
|
117
|
-
|
118
|
-
# preverify failed?
|
119
|
-
return false unless is_ok
|
120
|
-
|
121
|
-
self_signed = false
|
122
|
-
ca = false
|
123
|
-
pathlen = nil
|
124
|
-
server_auth = true
|
125
|
-
self_signed = (cert.subject.cmp(cert.issuer) == 0)
|
126
|
-
|
127
|
-
# Check extensions for the certificate purpose according to http://www.openssl.org/docs/apps/x509.html (Certificate Extensions) and
|
128
|
-
# http://www.ietf.org/rfc/rfc3280.txt.
|
129
|
-
cert.extensions.each do |ex|
|
130
|
-
case ex.oid
|
131
|
-
when 'basicConstraints'
|
132
|
-
/CA:(TRUE|FALSE)(?:, pathlen:)*(\d*)/ =~ ex.value
|
133
|
-
ca ||= ($1 == 'TRUE')
|
134
|
-
pathlen = $2.to_i
|
135
|
-
when 'keyUsage'
|
136
|
-
usage = ex.value.split(/\s*,\s*/)
|
137
|
-
# a CA must have
|
138
|
-
ca &&= !usage.grep(/Certificate Sign/i).empty?
|
139
|
-
# Server Cert Must have
|
140
|
-
server_auth &&= !usage.grep(/Key Encipherment/i).empty?
|
141
|
-
when 'extendedKeyUsage'
|
142
|
-
usage = ex.value.split(/\s*,\s*/)
|
143
|
-
# Server Cert Must have
|
144
|
-
server_auth &&= !usage.grep(/TLS Web Server Authentication/i).empty?
|
145
|
-
when 'nsCertType'
|
146
|
-
usage = ex.value.split(/\s*,\s*/)
|
147
|
-
ca ||= !usage.grep(/SSL CA/i).empty?
|
148
|
-
server_auth ||= !usage.grep(/SSL Server/i).empty?
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
# We're looking for the server cert, so accept all CAs (which have already passed pre-verification)
|
153
|
-
return true if self_signed || ca
|
154
|
-
|
155
|
-
# ensure the server cert is the one we're expecting
|
156
|
-
return server_auth && @@server_cert == cert.to_pem
|
157
|
-
end
|
158
|
-
|
159
117
|
# what transport types we support, and their corresponding suffixes
|
160
118
|
@@transport_types = {
|
161
119
|
:rest => {:suffix => "xml", :content_type => "application/xml"},
|
data/pkg/exact4r-1.2.gem
ADDED
Binary file
|
data/test/credentials.yml
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
DEV:
|
2
|
-
location: http://
|
2
|
+
location: http://localhost:3000/
|
3
3
|
tsys:
|
4
4
|
:gateway_id: AD0156-01
|
5
5
|
:password: 4apitest
|
@@ -16,6 +16,24 @@ DEV:
|
|
16
16
|
:gateway_id: AD0158-01
|
17
17
|
:password: 4apitest
|
18
18
|
|
19
|
+
QA:
|
20
|
+
location: https://api.qa.e-xact.com/
|
21
|
+
tsys:
|
22
|
+
:gateway_id: A04766-01
|
23
|
+
:password: 4apitest
|
24
|
+
emergis:
|
25
|
+
:gateway_id: A04763-01
|
26
|
+
:password: 4apitest
|
27
|
+
moneris:
|
28
|
+
:gateway_id: A04760-01
|
29
|
+
:password: 4apitest
|
30
|
+
chase:
|
31
|
+
:gateway_id: A04757-02
|
32
|
+
:password: 4apitest
|
33
|
+
chase_batch:
|
34
|
+
:gateway_id: A04757-01
|
35
|
+
:password: 4apitest
|
36
|
+
|
19
37
|
PROD:
|
20
38
|
location: https://api.e-xact.com/
|
21
39
|
tsys:
|
@@ -39,7 +39,9 @@ class ForcedPostTest < Test::Unit::TestCase
|
|
39
39
|
assert request.valid?
|
40
40
|
end
|
41
41
|
|
42
|
-
def test_by_credit_card
|
42
|
+
def test_by_credit_card
|
43
|
+
return if @@credentials.chase? || @@credentials.moneris?
|
44
|
+
|
43
45
|
request = EWS::Transaction::Request.new(cc_number_params.merge(:transaction_type => :forced_post))
|
44
46
|
request.amount = 11.25
|
45
47
|
request.authorization_num = "1234"
|
@@ -51,6 +53,8 @@ class ForcedPostTest < Test::Unit::TestCase
|
|
51
53
|
end
|
52
54
|
|
53
55
|
def test_by_track1
|
56
|
+
return if @@credentials.chase? || @@credentials.moneris?
|
57
|
+
|
54
58
|
request = EWS::Transaction::Request.new(track1_params.merge(:transaction_type => :forced_post))
|
55
59
|
request.amount = 11.25
|
56
60
|
request.authorization_num = "1234"
|
@@ -62,6 +66,8 @@ class ForcedPostTest < Test::Unit::TestCase
|
|
62
66
|
end
|
63
67
|
|
64
68
|
def test_by_track2
|
69
|
+
return if @@credentials.chase? || @@credentials.moneris?
|
70
|
+
|
65
71
|
request = EWS::Transaction::Request.new(track2_params.merge(:transaction_type => :forced_post))
|
66
72
|
request.amount = 11.25
|
67
73
|
request.authorization_num = "1234"
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../test_helper"
|
2
|
+
|
3
|
+
#
|
4
|
+
# A ReferencedVoid behaves the same as a TaggedVoid, except, instead of using transaction_tag,
|
5
|
+
# authorization_num and amount to lookup the transaction to be voided, you use reference_no,
|
6
|
+
# customer_ref and amount.
|
7
|
+
#
|
8
|
+
class ReferencedVoidTest < Test::Unit::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@transporter = EWS::Transporter.new(@@credentials.config['location'])
|
12
|
+
|
13
|
+
# do initial purchase
|
14
|
+
request = EWS::Transaction::Request.new(cc_number_params.merge({
|
15
|
+
:transaction_type => :purchase,
|
16
|
+
:amount => 11.25,
|
17
|
+
:reference_no => "reference_no_#{rand(10)}",
|
18
|
+
:customer_ref => "customer_ref_#{rand(10)}"
|
19
|
+
}))
|
20
|
+
assert request.valid?, request.errors.inspect
|
21
|
+
|
22
|
+
@purchase = @transporter.submit(request, :json)
|
23
|
+
assert @purchase.approved?
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_mandatory
|
27
|
+
request = EWS::Transaction::Request.new(:transaction_type => :referenced_void)
|
28
|
+
assert !request.valid?
|
29
|
+
assert_equal "gateway_id must be supplied", request.errors[:gateway_id]
|
30
|
+
|
31
|
+
request.gateway_id = @@credentials.current_gateway[:gateway_id]
|
32
|
+
assert !request.valid?
|
33
|
+
assert_equal "password must be supplied", request.errors[:password]
|
34
|
+
|
35
|
+
request.password = @@credentials.current_gateway[:password]
|
36
|
+
assert !request.valid?
|
37
|
+
assert_equal "reference_no must be supplied", request.errors[:reference_no]
|
38
|
+
|
39
|
+
request.reference_no = "something"
|
40
|
+
assert !request.valid?
|
41
|
+
assert_equal "customer_ref must be supplied", request.errors[:customer_ref]
|
42
|
+
|
43
|
+
request.customer_ref = "something"
|
44
|
+
assert !request.valid?
|
45
|
+
assert_equal "amount must be supplied", request.errors[:amount]
|
46
|
+
|
47
|
+
request.amount = 11.25
|
48
|
+
assert request.valid?
|
49
|
+
|
50
|
+
# don't set any CC information
|
51
|
+
[:cc_number, :pan, :track1, :track2, :transaction_tag].each do |attr_name|
|
52
|
+
request.send("#{attr_name}=", "something")
|
53
|
+
assert !request.valid?
|
54
|
+
assert_equal "#{attr_name} must not be set for referenced_void transactions", request.errors[attr_name]
|
55
|
+
request.send("#{attr_name}=", nil)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_json
|
60
|
+
request = EWS::Transaction::Request.new({
|
61
|
+
:transaction_type => :referenced_void,
|
62
|
+
:amount => 11.25,
|
63
|
+
:reference_no => @purchase.reference_no,
|
64
|
+
:customer_ref => @purchase.customer_ref
|
65
|
+
}.merge(@@credentials.current_gateway))
|
66
|
+
assert request.valid?, request.errors.inspect
|
67
|
+
|
68
|
+
assert_details_correct request, @transporter.submit(request, :json)
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_rest
|
72
|
+
request = EWS::Transaction::Request.new({
|
73
|
+
:transaction_type => :referenced_void,
|
74
|
+
:amount => 11.25,
|
75
|
+
:reference_no => @purchase.reference_no,
|
76
|
+
:customer_ref => @purchase.customer_ref
|
77
|
+
}.merge(@@credentials.current_gateway))
|
78
|
+
assert request.valid?, request.errors.inspect
|
79
|
+
|
80
|
+
assert_details_correct request, @transporter.submit(request, :rest)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_soap
|
84
|
+
request = EWS::Transaction::Request.new({
|
85
|
+
:transaction_type => :referenced_void,
|
86
|
+
:amount => 11.25,
|
87
|
+
:reference_no => @purchase.reference_no,
|
88
|
+
:customer_ref => @purchase.customer_ref
|
89
|
+
}.merge(@@credentials.current_gateway))
|
90
|
+
assert request.valid?, request.errors.inspect
|
91
|
+
|
92
|
+
assert_details_correct request, @transporter.submit(request, :soap)
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_requires_correct_amount
|
96
|
+
request = EWS::Transaction::Request.new({
|
97
|
+
:transaction_type => :referenced_void,
|
98
|
+
:amount => 3.50,
|
99
|
+
:reference_no => @purchase.reference_no,
|
100
|
+
:customer_ref => @purchase.customer_ref
|
101
|
+
}.merge(@@credentials.current_gateway))
|
102
|
+
assert request.valid?, request.errors.inspect
|
103
|
+
|
104
|
+
response = @transporter.submit(request, :json)
|
105
|
+
assert !response.approved?
|
106
|
+
|
107
|
+
request.amount = 13.50
|
108
|
+
response = @transporter.submit(request, :rest)
|
109
|
+
assert !response.approved?
|
110
|
+
|
111
|
+
request.amount = 11.25
|
112
|
+
assert_details_correct request, @transporter.submit(request, :soap)
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_multiple_voids_against_one_transaction
|
116
|
+
request = EWS::Transaction::Request.new({
|
117
|
+
:transaction_type => :referenced_void,
|
118
|
+
:amount => 11.25,
|
119
|
+
:reference_no => @purchase.reference_no,
|
120
|
+
:customer_ref => @purchase.customer_ref
|
121
|
+
}.merge(@@credentials.current_gateway))
|
122
|
+
assert request.valid?, request.errors.inspect
|
123
|
+
|
124
|
+
assert_details_correct request, @transporter.submit(request, :json)
|
125
|
+
|
126
|
+
# can't void an already-voided transaction
|
127
|
+
response = @transporter.submit(request, :json)
|
128
|
+
assert !response.approved?
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
@@ -43,7 +43,7 @@ class RefundCorrectionTest < Test::Unit::TestCase
|
|
43
43
|
assert request.valid?
|
44
44
|
end
|
45
45
|
|
46
|
-
def test_by_credit_card
|
46
|
+
def test_by_credit_card
|
47
47
|
return unless @@credentials.moneris?
|
48
48
|
|
49
49
|
request = EWS::Transaction::Request.new(cc_number_params.merge(:transaction_type => :refund_correction).merge(@@credentials.current_gateway))
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../test_helper"
|
2
|
+
|
3
|
+
#
|
4
|
+
# A TaggedUpdate request allows a merchant to edit the reference_no and customer_ref values of a
|
5
|
+
# previous transaction. Please note that this is NOT a financial transaction, it merely allows
|
6
|
+
# you to change the values stored in our DB for a given transaction.
|
7
|
+
#
|
8
|
+
# In common with all other tagged transactions, you supply the transaction_tag and authorization_num
|
9
|
+
# for the transaction whose values you wish to change, along with the new values for reference_no
|
10
|
+
# and/or customer_ref.
|
11
|
+
#
|
12
|
+
# NOTE: nil, empty string ("") or whitespace string (" ") are not permitted, and, although the
|
13
|
+
# request will be approved, the relevant attribute WILL NOT CHANGE.
|
14
|
+
#
|
15
|
+
class TaggedUpdateTest < Test::Unit::TestCase
|
16
|
+
|
17
|
+
def setup
|
18
|
+
@transporter = EWS::Transporter.new(@@credentials.config['location'])
|
19
|
+
|
20
|
+
# do initial purchase request
|
21
|
+
request = EWS::Transaction::Request.new(cc_number_params.merge(:transaction_type => :purchase))
|
22
|
+
request.amount = 11.25
|
23
|
+
request.reference_no = "reference_no"
|
24
|
+
request.customer_ref = "customer_ref"
|
25
|
+
assert request.valid?, request.errors.inspect
|
26
|
+
|
27
|
+
@purchase = @transporter.submit(request, :json)
|
28
|
+
assert @purchase.approved?, @purchase.to_yaml
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_mandatory
|
32
|
+
request = EWS::Transaction::Request.new(:transaction_type => :tagged_update)
|
33
|
+
assert !request.valid?
|
34
|
+
assert_equal "gateway_id must be supplied", request.errors[:gateway_id]
|
35
|
+
|
36
|
+
request.gateway_id = @@credentials.current_gateway[:gateway_id]
|
37
|
+
assert !request.valid?
|
38
|
+
assert_equal "password must be supplied", request.errors[:password]
|
39
|
+
|
40
|
+
request.password = @@credentials.current_gateway[:password]
|
41
|
+
assert !request.valid?
|
42
|
+
assert_equal "One of the following must be supplied: cc_number, track1, track2 or transaction_tag.", request.errors[:base]
|
43
|
+
|
44
|
+
request.transaction_tag = 1234
|
45
|
+
assert !request.valid?
|
46
|
+
assert_equal "authorization_num must be supplied", request.errors[:authorization_num]
|
47
|
+
|
48
|
+
request.authorization_num = "TH6754"
|
49
|
+
assert request.valid?, request.errors.inspect
|
50
|
+
|
51
|
+
request.cc_number = "4111111111111111"
|
52
|
+
assert !request.valid?
|
53
|
+
assert_equal "do not set cc_number for tagged transactions", request.errors[:cc_number]
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_json
|
57
|
+
request = tagged_update_request(@purchase)
|
58
|
+
assert request.valid?, request.errors.inspect
|
59
|
+
|
60
|
+
response = @transporter.submit(request, :json)
|
61
|
+
assert response.approved?
|
62
|
+
|
63
|
+
# we're getting the details of the original transction returned
|
64
|
+
assert_equal @purchase.transaction_tag, response.transaction_tag
|
65
|
+
assert_equal "something_new", response.reference_no
|
66
|
+
assert_equal "something_old", response.customer_ref
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_rest
|
70
|
+
request = tagged_update_request(@purchase)
|
71
|
+
assert request.valid?, request.errors.inspect
|
72
|
+
|
73
|
+
response = @transporter.submit(request, :rest)
|
74
|
+
|
75
|
+
# we're getting the details of the original transction returned
|
76
|
+
assert_equal @purchase.transaction_tag, response.transaction_tag
|
77
|
+
assert_equal "something_new", response.reference_no
|
78
|
+
assert_equal "something_old", response.customer_ref
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_soap
|
82
|
+
request = tagged_update_request(@purchase)
|
83
|
+
assert request.valid?, request.errors.inspect
|
84
|
+
|
85
|
+
response = @transporter.submit(request, :soap)
|
86
|
+
|
87
|
+
# we're getting the details of the original transction returned
|
88
|
+
assert_equal @purchase.transaction_tag, response.transaction_tag
|
89
|
+
assert_equal "something_new", response.reference_no
|
90
|
+
assert_equal "something_old", response.customer_ref
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_multiple_updates
|
94
|
+
request1 = tagged_update_request(@purchase)
|
95
|
+
assert request1.valid?, request1.errors.inspect
|
96
|
+
|
97
|
+
response1 = @transporter.submit(request1, :soap)
|
98
|
+
assert_equal "something_new", response1.reference_no
|
99
|
+
assert_equal "something_old", response1.customer_ref
|
100
|
+
|
101
|
+
request2 = tagged_update_request(@purchase, {
|
102
|
+
:reference_no => "bananas",
|
103
|
+
:customer_ref => "oranges"
|
104
|
+
})
|
105
|
+
assert request2.valid?, request2.errors.inspect
|
106
|
+
|
107
|
+
response2 = @transporter.submit(request2, :soap)
|
108
|
+
assert_equal "bananas", response2.reference_no
|
109
|
+
assert_equal "oranges", response2.customer_ref
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_updating_single_attribute
|
113
|
+
# change only reference_no
|
114
|
+
request1 = tagged_update_request(@purchase, {:customer_ref => nil})
|
115
|
+
assert request1.valid?, request1.errors.inspect
|
116
|
+
|
117
|
+
response1 = @transporter.submit(request1, :soap)
|
118
|
+
assert_equal "something_new", response1.reference_no
|
119
|
+
assert_equal "customer_ref", response1.customer_ref
|
120
|
+
|
121
|
+
# change only customer_ref
|
122
|
+
request2 = tagged_update_request(@purchase, {:reference_no => nil})
|
123
|
+
assert request2.valid?, request2.errors.inspect
|
124
|
+
|
125
|
+
response2 = @transporter.submit(request2, :soap)
|
126
|
+
assert_equal "something_new", response2.reference_no
|
127
|
+
assert_equal "something_old", response2.customer_ref
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_empty_strings_ignored
|
131
|
+
request1 = tagged_update_request(@purchase, {:customer_ref => ""})
|
132
|
+
assert request1.valid?, request1.errors.inspect
|
133
|
+
|
134
|
+
response1 = @transporter.submit(request1, :soap)
|
135
|
+
assert_equal "something_new", response1.reference_no
|
136
|
+
assert_equal "customer_ref", response1.customer_ref
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_whitepaces_strings_ignored
|
140
|
+
request1 = tagged_update_request(@purchase, {:customer_ref => " "})
|
141
|
+
assert request1.valid?, request1.errors.inspect
|
142
|
+
|
143
|
+
response1 = @transporter.submit(request1, :soap)
|
144
|
+
assert_equal "something_new", response1.reference_no
|
145
|
+
assert_equal "customer_ref", response1.customer_ref
|
146
|
+
end
|
147
|
+
|
148
|
+
def tagged_update_request(original_txn, options = {})
|
149
|
+
EWS::Transaction::Request.new({
|
150
|
+
:transaction_type => :tagged_update,
|
151
|
+
:transaction_tag => original_txn.transaction_tag,
|
152
|
+
:authorization_num => original_txn.authorization_num,
|
153
|
+
:reference_no => "something_new",
|
154
|
+
:customer_ref => "something_old"
|
155
|
+
}.merge(options).merge(@@credentials.current_gateway))
|
156
|
+
end
|
157
|
+
private :tagged_update_request
|
158
|
+
end
|
@@ -70,18 +70,19 @@ class TransactionDetailsTest < Test::Unit::TestCase
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def assert_details_match_original_response(original_response, details_response)
|
73
|
+
# exclude: client_ip, pan
|
73
74
|
[:logon_message, :error_number, :error_description, :transaction_error, :transaction_approved, :exact_resp_code, :exact_message,
|
74
75
|
:bank_resp_code, :bank_message, :bank_resp_code_2, :sequence_no, :avs, :cvv2, :retrieval_ref_no, :cavv_response, :merchant_name,
|
75
76
|
:merchant_address, :merchant_city, :merchant_province, :merchant_country, :merchant_postal, :merchant_url, :gateway_id, :password,
|
76
|
-
:transaction_type, :amount, :surcharge_amount, :cc_number, :transaction_tag, :track1, :track2, :
|
77
|
+
:transaction_type, :amount, :surcharge_amount, :cc_number, :transaction_tag, :track1, :track2, :authorization_num, :cc_expiry,
|
77
78
|
:cardholder_name, :cc_verification_str1, :cc_verification_str2, :cvd_presence_ind, :tax1_amount, :tax1_number, :tax2_amount,
|
78
79
|
:tax2_number, :secure_auth_required, :secure_auth_result, :ecommerce_flag, :xid, :cavv, :cavv_algorithm, :reference_no, :customer_ref,
|
79
|
-
:reference_3, :language, :
|
80
|
+
:reference_3, :language, :client_email, :user_name, :zip_code].each do |attr_name|
|
81
|
+
next if attr_name == :cc_expiry && %(35 50 54).include?(original_response.transaction_type)
|
82
|
+
|
80
83
|
o_value = original_response.send(attr_name).to_s
|
81
84
|
d_value = details_response.send(attr_name).to_s
|
82
|
-
|
83
|
-
puts "#{attr_name}: #{o_value} / #{d_value}"
|
84
|
-
end
|
85
|
+
assert_equal o_value, d_value, "#{attr_name}: #{o_value} / #{d_value}"
|
85
86
|
end
|
86
87
|
end
|
87
88
|
private :assert_details_match_original_response
|
@@ -40,42 +40,79 @@ class VoidTest < Test::Unit::TestCase
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def test_by_credit_card
|
43
|
-
return if @@credentials.
|
44
|
-
|
43
|
+
return if @@credentials.moneris?
|
44
|
+
|
45
|
+
response = send_purchase(cc_number_params)
|
46
|
+
|
45
47
|
request = EWS::Transaction::Request.new(cc_number_params.merge(:transaction_type => :void))
|
46
48
|
request.amount = 11.25
|
47
|
-
request.authorization_num =
|
49
|
+
request.authorization_num = response.authorization_num
|
48
50
|
assert request.valid?, request.errors.inspect
|
49
51
|
|
50
52
|
assert_details_correct request, @transporter.submit(request, :json)
|
53
|
+
|
54
|
+
response = send_purchase(cc_number_params)
|
55
|
+
request.authorization_num = response.authorization_num
|
56
|
+
|
51
57
|
assert_details_correct request, @transporter.submit(request, :rest)
|
58
|
+
|
59
|
+
response = send_purchase(cc_number_params)
|
60
|
+
request.authorization_num = response.authorization_num
|
61
|
+
|
52
62
|
assert_details_correct request, @transporter.submit(request, :soap)
|
53
63
|
end
|
54
64
|
|
55
65
|
def test_by_track1
|
56
|
-
return if @@credentials.
|
66
|
+
return if @@credentials.moneris?
|
57
67
|
|
68
|
+
response = send_purchase(track1_params)
|
69
|
+
|
58
70
|
request = EWS::Transaction::Request.new(track1_params.merge(:transaction_type => :void))
|
59
71
|
request.amount = 11.25
|
60
|
-
request.authorization_num =
|
72
|
+
request.authorization_num = response.authorization_num
|
61
73
|
assert request.valid?, request.errors.inspect
|
62
74
|
|
63
75
|
assert_details_correct request, @transporter.submit(request, :json)
|
76
|
+
|
77
|
+
response = send_purchase(track1_params)
|
78
|
+
request.authorization_num = response.authorization_num
|
79
|
+
|
64
80
|
assert_details_correct request, @transporter.submit(request, :rest)
|
81
|
+
|
82
|
+
response = send_purchase(track1_params)
|
83
|
+
request.authorization_num = response.authorization_num
|
84
|
+
|
65
85
|
assert_details_correct request, @transporter.submit(request, :soap)
|
66
86
|
end
|
67
87
|
|
68
88
|
def test_by_track2
|
69
|
-
return if @@credentials.
|
89
|
+
return if @@credentials.moneris?
|
70
90
|
|
91
|
+
response = send_purchase(track2_params)
|
92
|
+
|
71
93
|
request = EWS::Transaction::Request.new(track2_params.merge(:transaction_type => :void))
|
72
94
|
request.amount = 11.25
|
73
|
-
request.authorization_num =
|
95
|
+
request.authorization_num = response.authorization_num
|
74
96
|
assert request.valid?, request.errors.inspect
|
75
97
|
|
76
98
|
assert_details_correct request, @transporter.submit(request, :json)
|
99
|
+
|
100
|
+
response = send_purchase(track2_params)
|
101
|
+
request.authorization_num = response.authorization_num
|
102
|
+
|
77
103
|
assert_details_correct request, @transporter.submit(request, :rest)
|
104
|
+
|
105
|
+
response = send_purchase(track2_params)
|
106
|
+
request.authorization_num = response.authorization_num
|
107
|
+
|
78
108
|
assert_details_correct request, @transporter.submit(request, :soap)
|
79
109
|
end
|
80
110
|
|
111
|
+
def send_purchase(params)
|
112
|
+
request = EWS::Transaction::Request.new(params.merge(:transaction_type => :purchase, :amount => 11.25))
|
113
|
+
assert request.valid?, request.errors.inspect
|
114
|
+
response = @transporter.submit(request, :json)
|
115
|
+
assert response.approved?
|
116
|
+
response
|
117
|
+
end
|
81
118
|
end
|
@@ -48,7 +48,27 @@ class TransporterTest < Test::Unit::TestCase
|
|
48
48
|
|
49
49
|
assert_not_nil resp
|
50
50
|
assert_equal 404, resp.error_number
|
51
|
-
assert_equal "Not Found", resp.error_description
|
51
|
+
assert_equal "Not Found", resp.error_description.strip
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_uses_supplied_certificates
|
55
|
+
req = ::EWS::Transaction::Request.new({
|
56
|
+
:transaction_type => :purchase,
|
57
|
+
:amount => "10.13",
|
58
|
+
:cardholder_name => "Simon Brown",
|
59
|
+
:cc_number => "4111111111111111",
|
60
|
+
:cc_expiry => "1012",
|
61
|
+
:reference_no => "987987",
|
62
|
+
}.merge(@@credentials.current_gateway))
|
63
|
+
|
64
|
+
tr = ::EWS::Transporter.new(@@credentials.config['location'], {
|
65
|
+
:issuer_cert => File.dirname(__FILE__)+"/../../certs/valicert_class2_root.crt",
|
66
|
+
:server_cert => File.dirname(__FILE__)+"/../../certs/e-xact.com.crt"
|
67
|
+
})
|
68
|
+
resp = tr.submit(req, :json)
|
69
|
+
|
70
|
+
assert_not_nil resp
|
71
|
+
assert resp.approved?
|
52
72
|
end
|
53
73
|
|
54
74
|
end
|
data/test/test_helper.rb
CHANGED
@@ -38,7 +38,7 @@ end
|
|
38
38
|
|
39
39
|
def assert_details_correct(request, response)
|
40
40
|
assert_not_nil response, "response should not be nil"
|
41
|
-
assert response.approved?, "#{response.error_number} / #{response.error_description} / #{response.exact_message} / #{response.bank_message}"
|
41
|
+
assert response.approved?, "#{response.error_number} / #{response.error_description} / #{response.exact_resp_code} / #{response.exact_message} / #{response.bank_message}"
|
42
42
|
|
43
43
|
assert_not_nil response.transaction_tag
|
44
44
|
assert_not_nil response.authorization_num
|
@@ -49,9 +49,11 @@ def assert_details_correct(request, response)
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def assert_card_details(response)
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
unless %w(35 50 54).include?(response.transaction_type)
|
53
|
+
assert_match /............1111/, response.cc_number
|
54
|
+
assert_equal TEST_CARD_HOLDER, response.cardholder_name
|
55
|
+
assert_equal TEST_CARD_EXPIRY, response.cc_expiry
|
56
|
+
end
|
55
57
|
end
|
56
58
|
|
57
59
|
def basic_params(options = {})
|
metadata
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: exact4r
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 4
|
8
|
+
version: "1.4"
|
5
9
|
platform: ruby
|
6
10
|
authors:
|
7
11
|
- E-xact Transactions Ltd.
|
@@ -9,29 +13,37 @@ autorequire:
|
|
9
13
|
bindir: bin
|
10
14
|
cert_chain: []
|
11
15
|
|
12
|
-
date: 2010-
|
16
|
+
date: 2010-07-09 00:00:00 +10:00
|
13
17
|
default_executable:
|
14
18
|
dependencies:
|
15
19
|
- !ruby/object:Gem::Dependency
|
16
20
|
name: activesupport
|
17
|
-
|
18
|
-
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
23
|
requirements:
|
21
24
|
- - ">="
|
22
25
|
- !ruby/object:Gem::Version
|
26
|
+
segments:
|
27
|
+
- 2
|
28
|
+
- 0
|
29
|
+
- 2
|
23
30
|
version: 2.0.2
|
24
|
-
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
25
33
|
- !ruby/object:Gem::Dependency
|
26
34
|
name: builder
|
27
|
-
|
28
|
-
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
37
|
requirements:
|
31
38
|
- - ">="
|
32
39
|
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 2
|
42
|
+
- 1
|
43
|
+
- 2
|
33
44
|
version: 2.1.2
|
34
|
-
|
45
|
+
type: :runtime
|
46
|
+
version_requirements: *id002
|
35
47
|
description:
|
36
48
|
email: dredmond@e-xact.com
|
37
49
|
executables: []
|
@@ -49,6 +61,7 @@ files:
|
|
49
61
|
- ./certs/exact.cer
|
50
62
|
- ./certs/valicert_class2_root.crt
|
51
63
|
- ./CHANGELOG
|
64
|
+
- ./lib/ews/certificate_helper.rb
|
52
65
|
- ./lib/ews/transaction/fake_response.rb
|
53
66
|
- ./lib/ews/transaction/mapping.rb
|
54
67
|
- ./lib/ews/transaction/request.rb
|
@@ -58,6 +71,7 @@ files:
|
|
58
71
|
- ./lib/ews/transporter.rb
|
59
72
|
- ./lib/exact4r.rb
|
60
73
|
- ./LICENCE
|
74
|
+
- ./pkg/exact4r-1.2.gem
|
61
75
|
- ./Rakefile
|
62
76
|
- ./README
|
63
77
|
- ./test/credentials.rb
|
@@ -73,6 +87,7 @@ files:
|
|
73
87
|
- ./test/exhaustive/purchase_test.rb
|
74
88
|
- ./test/exhaustive/recurring_seed_pre_auth_test.rb
|
75
89
|
- ./test/exhaustive/recurring_seed_purchase_test.rb
|
90
|
+
- ./test/exhaustive/referenced_void_test.rb
|
76
91
|
- ./test/exhaustive/refund_correction_test.rb
|
77
92
|
- ./test/exhaustive/refund_test.rb
|
78
93
|
- ./test/exhaustive/secure_storage_test.rb
|
@@ -81,6 +96,7 @@ files:
|
|
81
96
|
- ./test/exhaustive/tagged_pre_auth_test.rb
|
82
97
|
- ./test/exhaustive/tagged_purchase_test.rb
|
83
98
|
- ./test/exhaustive/tagged_refund_test.rb
|
99
|
+
- ./test/exhaustive/tagged_update_test.rb
|
84
100
|
- ./test/exhaustive/tagged_void_test.rb
|
85
101
|
- ./test/exhaustive/transaction_details_test.rb
|
86
102
|
- ./test/exhaustive/void_test.rb
|
@@ -122,18 +138,20 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
122
138
|
requirements:
|
123
139
|
- - ">="
|
124
140
|
- !ruby/object:Gem::Version
|
141
|
+
segments:
|
142
|
+
- 0
|
125
143
|
version: "0"
|
126
|
-
version:
|
127
144
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
145
|
requirements:
|
129
146
|
- - ">="
|
130
147
|
- !ruby/object:Gem::Version
|
148
|
+
segments:
|
149
|
+
- 0
|
131
150
|
version: "0"
|
132
|
-
version:
|
133
151
|
requirements: []
|
134
152
|
|
135
153
|
rubyforge_project: exact4r
|
136
|
-
rubygems_version: 1.3.
|
154
|
+
rubygems_version: 1.3.6
|
137
155
|
signing_key:
|
138
156
|
specification_version: 3
|
139
157
|
summary: E-xact Web Services Client Library.
|