exact4r 0.5 → 0.5.1

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.
@@ -2,7 +2,7 @@ require 'net/https'
2
2
 
3
3
  module EWS # :nodoc:
4
4
  module Transaction # :nodoc:
5
-
5
+
6
6
  # A Transporter is responsible for communicating with the E-xact Web Service in
7
7
  # whichever dialect is chosen by the user. The available options are:
8
8
  # :json REST with JSON payload
@@ -16,7 +16,7 @@ module EWS # :nodoc:
16
16
  # Once configured to connect to a particular service, it can be used repeatedly
17
17
  # to send as many transactions as required.
18
18
  class Transporter
19
-
19
+
20
20
  # Initialize a Transporter.
21
21
  #
22
22
  # You can specify the URL you would like the Transporter to connect to,
@@ -33,37 +33,38 @@ module EWS # :nodoc:
33
33
  # basis, if you choose to do so, by specifying it as a parameter to the <tt>send</tt> method.
34
34
  def initialize(url = "https://api.e-xact.com/", options = {})
35
35
  @url = URI.parse(url)
36
- @server_cert = options[:server_cert] || "certs/exact.cer"
37
- @issuer_cert = options[:issuer_cert] || "certs/equifax_ca.cer"
36
+ base = File.dirname(__FILE__)
37
+ @server_cert = options[:server_cert] || base+"/../../../certs/exact.cer"
38
+ @issuer_cert = options[:issuer_cert] || base+"/../../../certs/equifax_ca.cer"
38
39
  @transport_type = options[:issuer_cert] || :rest
39
40
  end
40
-
41
+
41
42
  # Send a transaction request to the server
42
43
  #
43
- # <tt>request</tt>:: the Request object to encode for transmission to the server
44
+ # <tt>request</tt>:: the Request object to encode for transmission to the server
44
45
  # <tt>transport_type</tt>:: (optional) the transport type to use for this transaction only. If it not specified, the default transport type for this Transporter will be used
45
- def send(request, transport_type = nil)
46
+ def submit(request, transport_type = nil)
46
47
  raise "Request not supplied" if request.nil?
47
48
  return false unless request.valid?
48
-
49
+
49
50
  transport_type ||= @transport_type
50
-
51
+
51
52
  raise "Transport type #{transport_type} is not supported" unless @@transport_types.include? transport_type
52
-
53
+
53
54
  if !request.is_find_transaction? or transport_type == :soap
54
55
  content = post(request, transport_type)
55
56
  else
56
57
  content = get(request, transport_type)
57
58
  end
58
-
59
+
59
60
  EWS::Transaction::Mapping.send "#{transport_type}_to_response", content
60
61
  end
61
-
62
+
62
63
  private
63
64
 
64
65
  def post(request, transport_type)
65
66
  # build the request
66
- req = Net::HTTP::Post.new(@url.path + "/transaction.#{@@transport_types[transport_type]}")
67
+ req = Net::HTTP::Post.new(@url.path + "transaction.#{@@transport_types[transport_type]}")
67
68
  req.basic_auth(request.gateway_id, request.password)
68
69
  if transport_type == :soap
69
70
  # add the SOAPAction header
@@ -72,7 +73,7 @@ module EWS # :nodoc:
72
73
  end
73
74
  req.content_type = (transport_type == :json) ? "application/json" : "application/xml"
74
75
  req.body = EWS::Transaction::Mapping.send "request_to_#{transport_type.to_s}", request
75
-
76
+
76
77
  response = get_connection.request(req)
77
78
 
78
79
  case response
@@ -84,10 +85,10 @@ module EWS # :nodoc:
84
85
 
85
86
  def get(request, transport_type)
86
87
  # build the request
87
- req = Net::HTTP::Get.new(@url.path + "/transaction/#{request.transaction_tag}.#{@@transport_types[transport_type]}")
88
+ req = Net::HTTP::Get.new(@url.path + "transaction/#{request.transaction_tag}.#{@@transport_types[transport_type]}")
88
89
  req.basic_auth(request.gateway_id, request.password)
89
90
  req.content_type = (transport_type == :json) ? "application/json" : "application/xml"
90
-
91
+
91
92
  response = get_connection.request(req)
92
93
 
93
94
  case response
@@ -96,9 +97,10 @@ module EWS # :nodoc:
96
97
  response.error!
97
98
  end
98
99
  end
99
-
100
+
100
101
  def get_connection
101
102
  connection = Net::HTTP.new(@url.host, @url.port)
103
+ connection.set_debug_output $stdout if $DEBUG
102
104
  if @url.scheme == 'https'
103
105
  connection.use_ssl = true
104
106
  connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
@@ -125,4 +127,4 @@ module EWS # :nodoc:
125
127
 
126
128
  end
127
129
  end
128
- end
130
+ end
data/lib/exact4r.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require 'rubygems'
2
- require 'activesupport'
3
2
 
4
3
  require 'ews/transaction/mapping'
5
4
  require 'ews/transaction/request'
data/spec/donncha.rb ADDED
@@ -0,0 +1,46 @@
1
+ # require File.dirname(__FILE__) + "/spec_helper"
2
+ #
3
+ # describe "smaple" do
4
+ # it "should work" do
5
+ # r1 = {"requested_aci": 0, "trfid": 12715148, "sequence_no": "212", "auth_number": "ET3442", "abuff_length": 6, "currency_str": "USD", "trace_no": "028001", "bank_resp_code": "000", "returned_aci": 0, "tx_state": 0, "cc_number": "4111111111111111", "sys": 0, "cavv_response": 0, "txflag1": 0, "trans_no": "01", "bank_message": "APPROVED", "transaction_type": "00", "input_method": 0, "time_received": "2008/05/28 20:34:42 +0000", "retrieval_ref_no": "05283442", "cc_expiry": "1005", "transaction_id": 0, "credit_card_type": "Visa", "txflag2": 0, "gateway_id": "AD0008-01", "crc": 0, "ecommerce_flag": 0, "time_sent": "2008/05/28 20:34:42 +0000", "auth_source_code": "5", "cardholder_name": "Simon Brown", "transaction_tag": 2384, "enc": 2, "terminal_ptr": 16459632, "reversal_ind": "O", "exact_resp_code": "00", "amount": "1013", "terminal_id": "001", "cvd_presence_ind": 0, "transaction_approved": 1, "optional": "~uVisa", "transaction_tag2": 0, "processing_centre": 1, "exact_message": "Transaction Normal", "sub": 0, "cmd": 65418, "len": 493, "pid": 333}
6
+ # r2 = {"requested_aci": 0, "trfid": 0 , "sequence_no": "212", "auth_number": "ET3442", "abuff_length": 0, "bank_resp_code": "000", "returned_aci": 0, "tx_state": 0, "cc_number": "4111111111111111", "sys": 0, "cavv_response": 0, "txflag1": 0, "bank_message": "APPROVED", "transaction_type": "00", "input_method": 0, "time_received": "2008/05/28 20:34:41 +0000", "cc_expiry": "1005", "transaction_id": 0, "txflag2": 0, "gateway_id": "AD0008-01", "crc": 0, "ecommerce_flag": 0, "time_sent": "1899/12/30 00:00:00 +0000", "cardholder_name": "Simon Brown", "transaction_tag": 2384, "enc": 2, "terminal_ptr": 0, "exact_resp_code": "00", "amount": "1013", "terminal_id": "001", "cvd_presence_ind": 0, "transaction_approved": 1, "transaction_tag2": 2384, "processing_centre": 5, "exact_message": "Transaction Normalumber", "sub": 0, "cmd": 65418, "len": 487, "pid": 345}
7
+ # end
8
+ # end
9
+
10
+ require 'net/https'
11
+
12
+ def validate_certificate(is_ok, ctx)
13
+ # Only check the server certificate, not the issuer.
14
+ unless (ctx.current_cert.subject.to_s == ctx.current_cert.issuer.to_s)
15
+ is_ok &&= File.open("certs/exact.cer").read == ctx.current_cert.to_pem
16
+ end
17
+ is_ok
18
+ end
19
+
20
+ # @url = URI.parse("https://olb.au.virginmoney.com/esis/Login/SrvPage")
21
+ @url = URI.parse("https://pos.e-xact.com/")
22
+
23
+ # https://olb.au.virginmoney.com/esis/Login/SrvPage
24
+ begin
25
+ connection = Net::HTTP.new(@url.host, @url.port)
26
+ #
27
+ if @url.scheme == 'https'
28
+ connection.use_ssl = true
29
+ connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
30
+ connection.ca_file = "certs/equifax_ca.cer"
31
+ connection.verify_callback = method(:validate_certificate)
32
+ end
33
+
34
+ req = Net::HTTP::Get.new(@url.path)
35
+
36
+ response = connection.request(req)
37
+ rescue => e
38
+ puts e.message
39
+ puts e.backtrace
40
+ end
41
+ # puts response
42
+ # case response
43
+ # when Net::HTTPSuccess then response.body
44
+ # else
45
+ # response.error!
46
+ # end
@@ -0,0 +1,85 @@
1
+ require File.dirname(__FILE__) + "/spec_helper"
2
+
3
+ describe "Mapping TO formats" do
4
+
5
+ it "should generate a JSON payload" do
6
+ r = EWS::Transaction::Request.new(basic_params)
7
+
8
+ json = EWS::Transaction::Mapping.request_to_json(r)
9
+
10
+ res = ActiveSupport::JSON.decode(json)
11
+ res["amount"].should == "10.13"
12
+ res["cardholder_name"].should == "Simon Brown"
13
+ res["cc_number"].should == "4111111111111111"
14
+ res["cc_expiry"].should == "1005"
15
+ end
16
+
17
+ it "should generate a REST payload" do
18
+ r = EWS::Transaction::Request.new(basic_params)
19
+
20
+ rest = EWS::Transaction::Mapping.request_to_rest(r)
21
+
22
+ xml = REXML::Document.new(rest)
23
+ txn = REXML::XPath.first(xml, "//Transaction")
24
+ REXML::XPath.first(txn, "Card_Number").text.should == "4111111111111111"
25
+ REXML::XPath.first(txn, "CardHoldersName").text.should == "Simon Brown"
26
+ REXML::XPath.first(txn, "Transaction_Type").text.should == "00"
27
+ REXML::XPath.first(txn, "Expiry_Date").text.should == "1005"
28
+ REXML::XPath.first(txn, "DollarAmount").text.should == "10.13"
29
+ end
30
+
31
+ it "should generate a SOAP payload" do
32
+ r = EWS::Transaction::Request.new(basic_params)
33
+
34
+ soap = EWS::Transaction::Mapping.request_to_soap(r)
35
+
36
+ xml = REXML::Document.new(soap)
37
+ txn = REXML::XPath.first(xml, "//SendAndCommitSource")
38
+ REXML::XPath.first(txn, "Card_Number").text.should == "4111111111111111"
39
+ REXML::XPath.first(txn, "CardHoldersName").text.should == "Simon Brown"
40
+ REXML::XPath.first(txn, "Transaction_Type").text.should == "00"
41
+ REXML::XPath.first(txn, "Expiry_Date").text.should == "1005"
42
+ REXML::XPath.first(txn, "DollarAmount").text.should == "10.13"
43
+ end
44
+ end
45
+
46
+ describe "Mapping FROM formats" do
47
+
48
+ it "should parse a JSON payload" do
49
+ payload = <<PAYLOAD
50
+ {"bank_message": "APPROVED", "transaction_type": "00", "transaction_tag": 2238, "exact_message": "Transaction Normal"}
51
+ PAYLOAD
52
+
53
+ r = EWS::Transaction::Mapping.json_to_response(payload)
54
+
55
+ r.exact_message.should == "Transaction Normal"
56
+ r.error_description.should be_nil
57
+ r.bank_message.should == "APPROVED"
58
+ r.transaction_tag.should == 2238
59
+ r.transaction_type.should == "00"
60
+ end
61
+
62
+ it "should parse a REST payload" do
63
+ payload = <<PAYLOAD
64
+ <?xml version="1.0" encoding="UTF-8"?>
65
+ <TransactionResult>
66
+ <Error_Description></Error_Description>
67
+ <Bank_Message>APPROVED</Bank_Message>
68
+ <Transaction_Tag>2239</Transaction_Tag>
69
+ <EXact_Message>Transaction Normal</EXact_Message>
70
+ <Transaction_Type>00</Transaction_Type>
71
+ </TransactionResult>
72
+ PAYLOAD
73
+
74
+ r = EWS::Transaction::Mapping.rest_to_response(payload)
75
+
76
+ r.exact_message.should == "Transaction Normal"
77
+ r.error_description.should be_nil
78
+ r.bank_message.should == "APPROVED"
79
+ r.transaction_tag.should == 2239
80
+ r.transaction_type.should == "00"
81
+ end
82
+
83
+ it "should parse a SOAP payload"
84
+
85
+ end
@@ -0,0 +1,123 @@
1
+ require File.dirname(__FILE__) + "/spec_helper"
2
+
3
+ describe "Request" do
4
+
5
+ it "should allow construction from empty hash" do
6
+ r = EWS::Transaction::Request.new
7
+ end
8
+
9
+ it "should assign values" do
10
+ r = EWS::Transaction::Request.new(basic_params)
11
+
12
+ r.amount.should == "10.13"
13
+ r.cardholder_name.should == "Simon Brown"
14
+ r.cc_number.should == "4111111111111111"
15
+ r.cc_expiry.should == "1005"
16
+ end
17
+
18
+ it "should require gateway_id and password " do
19
+ EWS::Transaction::Request.new(basic_params).should be_valid
20
+
21
+ EWS::Transaction::Request.new(basic_params(:gateway_id => nil)).should_not be_valid
22
+ EWS::Transaction::Request.new(basic_params(:gateway_id => "")).should_not be_valid
23
+
24
+ EWS::Transaction::Request.new(basic_params(:password => nil)).should_not be_valid
25
+ EWS::Transaction::Request.new(basic_params(:password => "")).should_not be_valid
26
+ end
27
+
28
+ it "should validate amount, cc_number and cc_expiry" do
29
+ # validation: amounts
30
+ [:amount, :surcharge_amount, :tax1_amount, :tax2_amount].each do |amount_attr|
31
+ EWS::Transaction::Request.new(basic_params(amount_attr => "10.13")).should be_valid
32
+ EWS::Transaction::Request.new(basic_params(amount_attr => "10.")).should be_valid
33
+ EWS::Transaction::Request.new(basic_params(amount_attr => "0.13")).should be_valid
34
+ EWS::Transaction::Request.new(basic_params(amount_attr => 10.13)).should be_valid
35
+ EWS::Transaction::Request.new(basic_params(amount_attr => 0.13)).should be_valid
36
+ EWS::Transaction::Request.new(basic_params(amount_attr => 10)).should be_valid
37
+ EWS::Transaction::Request.new(basic_params(amount_attr => "10.1s3")).should_not be_valid
38
+ EWS::Transaction::Request.new(basic_params(amount_attr => "1s0.13")).should_not be_valid
39
+ EWS::Transaction::Request.new(basic_params(amount_attr => "dopey")).should_not be_valid
40
+ end
41
+
42
+ # validation: card number
43
+ EWS::Transaction::Request.new(basic_params(:cc_number => "4111111111111111")).should be_valid
44
+ EWS::Transaction::Request.new(basic_params(:cc_number => "4111111111111112")).should_not be_valid
45
+
46
+ # validation: card expiry (should be in YYMM format)
47
+ EWS::Transaction::Request.new(basic_params(:cc_expiry => "1009")).should be_valid
48
+ EWS::Transaction::Request.new(basic_params(:cc_expiry => "0708")).should_not be_valid
49
+ end
50
+
51
+ it "should be valid when symbol or value supplied for transaction_type" do
52
+ EWS::Transaction::Request.new(basic_params(:transaction_type => "00")).should be_valid
53
+ EWS::Transaction::Request.new(basic_params(:transaction_type => :purchase)).should be_valid
54
+
55
+ EWS::Transaction::Request.new(basic_params(:transaction_type => nil)).should_not be_valid
56
+ EWS::Transaction::Request.new(basic_params(:transaction_type => "")).should_not be_valid
57
+ EWS::Transaction::Request.new(basic_params(:transaction_type => "barry")).should_not be_valid
58
+ end
59
+ end
60
+
61
+ describe "Submitting New Requests" do
62
+
63
+ before :all do
64
+ @transporter = EWS::Transaction::Transporter.new
65
+ end
66
+
67
+ it "should work without a specified transport_type" do
68
+ txn = basic_new_transaction
69
+ resp = @transporter.submit(txn)
70
+
71
+ resp.exact_resp_code.should == "00"
72
+ resp.exact_message.should == "Transaction Normal"
73
+ resp.bank_message.should == "APPROVED"
74
+ resp.transaction_tag.should_not be_nil
75
+ end
76
+
77
+ it "should support all transport types" do
78
+ [:json, :rest, :soap].each do |type|
79
+ txn = basic_new_transaction
80
+ resp = @transporter.submit(txn, type)
81
+
82
+ resp.exact_resp_code.should == "00"
83
+ resp.exact_message.should == "Transaction Normal"
84
+ resp.bank_message.should == "APPROVED"
85
+ resp.transaction_tag.should_not be_nil
86
+ end
87
+ end
88
+
89
+ end
90
+
91
+ describe "Submitting Find Requests" do
92
+
93
+ before :each do
94
+ @transporter = EWS::Transaction::Transporter.new
95
+
96
+ txn = basic_new_transaction
97
+ @transaction_tag = @transporter.submit(txn, :json).transaction_tag
98
+ end
99
+
100
+ it "should work without a specified transport_type" do
101
+ txn = basic_find_transaction(:transaction_tag => @transaction_tag)
102
+ resp = @transporter.submit(txn)
103
+
104
+ resp.exact_resp_code.should == "00"
105
+ resp.exact_message.should == "Transaction Normal"
106
+ resp.bank_message.should == "APPROVED"
107
+ resp.transaction_tag.should_not be_nil
108
+ end
109
+
110
+ it "should support all transport types" do
111
+ [:json, :rest, :soap].each do |type|
112
+ txn = basic_find_transaction(:transaction_tag => @transaction_tag)
113
+ resp = @transporter.submit(txn, type)
114
+
115
+ resp.transaction_tag.should == @transaction_tag
116
+ resp.cc_number == "4111111111111"
117
+ resp.exact_resp_code.should == "00"
118
+ resp.exact_message.should == "Transaction Normal"
119
+ resp.bank_message.should == "APPROVED"
120
+ end
121
+ end
122
+
123
+ end
@@ -0,0 +1,41 @@
1
+ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
2
+
3
+ require 'spec'
4
+ require 'lib/exact4r'
5
+
6
+ def basic_params(options = {})
7
+ {
8
+ :transaction_type => :purchase,
9
+ :amount => "10.13",
10
+ :cardholder_name => "Simon Brown",
11
+ :cc_number => "4111111111111111",
12
+ :cc_expiry => "1005",
13
+ :gateway_id => "someone",
14
+ :password => "somehow"
15
+ }.merge(options)
16
+ end
17
+
18
+ def basic_find_transaction(options = {})
19
+ params = {
20
+ :transaction_type => :transaction_details,
21
+ :gateway_id => "AD0008-01",
22
+ :password => "7nfcpc7n"
23
+ }.merge(options)
24
+
25
+ ::EWS::Transaction::Request.new(params)
26
+ end
27
+
28
+ def basic_new_transaction(options = {})
29
+ params = {
30
+ :transaction_type => :purchase,
31
+ :amount => "10.13",
32
+ :cardholder_name => "Simon Brown",
33
+ :cc_number => "4111111111111111",
34
+ :cc_expiry => "1005",
35
+ :reference_no => "987987",
36
+ :gateway_id => "AD0008-01",
37
+ :password => "7nfcpc7n"
38
+ }.merge(options)
39
+
40
+ ::EWS::Transaction::Request.new(params)
41
+ end
@@ -0,0 +1,62 @@
1
+ require File.dirname(__FILE__) + "/spec_helper"
2
+
3
+ describe "Transporter creating transactions" do
4
+
5
+ it "should raise an exception when transport_type is not one of :json, :rest or :soap" do
6
+ lambda {
7
+ tr = ::EWS::Transaction::Transporter.new
8
+ tr.submit(basic_new_transaction, :banana)
9
+ }.should raise_error
10
+ end
11
+
12
+ it "should not throw errors" do
13
+ txn = basic_new_transaction
14
+
15
+ lambda {
16
+ tr = ::EWS::Transaction::Transporter.new
17
+ tr.submit(txn, json)
18
+ }.should_not raise_error(RuntimeError)
19
+ end
20
+
21
+
22
+ end
23
+
24
+ describe "Transporter finding transactions" do
25
+
26
+ before :each do
27
+ txn = basic_new_transaction
28
+ @tr = ::EWS::Transaction::Transporter.new
29
+ r = @tr.submit(txn, :json)
30
+ @transaction_tag = r.transaction_tag
31
+ end
32
+
33
+ it "should support all transport types" do
34
+ [:json, :rest, :soap].each do |type|
35
+ txn = basic_find_transaction(:transaction_tag => @transaction_tag)
36
+ resp = @tr.submit(txn, type)
37
+
38
+ resp.transaction_tag.should == @transaction_tag
39
+ resp.cc_number == "4111111111111"
40
+ resp.exact_resp_code.should == "00"
41
+ resp.exact_message.should == "Transaction Normal"
42
+ resp.bank_message.should == "APPROVED"
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ describe "Transporter creating and finding transactions" do
49
+
50
+ it "should support all transport types" do
51
+ [:json, :rest, :soap].each do |type|
52
+ tr = ::EWS::Transaction::Transporter.new
53
+ new_txn = tr.submit(basic_new_transaction, type)
54
+ new_txn.transaction_tag.should_not be_nil
55
+
56
+ found_txn = tr.submit(basic_find_transaction(:transaction_tag => new_txn.transaction_tag), :json)
57
+ found_txn.should_not be_nil
58
+ found_txn.transaction_tag.should == new_txn.transaction_tag
59
+ end
60
+ end
61
+
62
+ end