hps 2.1.2 → 2.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -4
- data/lib/hps.rb +12 -0
- data/lib/hps/configuration.rb +4 -4
- data/lib/hps/entities/hps_check.rb +18 -0
- data/lib/hps/entities/hps_check_holder.rb +10 -0
- data/lib/hps/entities/hps_check_response.rb +45 -0
- data/lib/hps/entities/hps_check_response_details.rb +9 -0
- data/lib/hps/infrastructure/hps_account_type.rb +11 -0
- data/lib/hps/infrastructure/hps_check_exception.rb +13 -0
- data/lib/hps/infrastructure/hps_check_type.rb +11 -0
- data/lib/hps/infrastructure/hps_data_entry_mode.rb +11 -0
- data/lib/hps/infrastructure/hps_gateway_response_validation.rb +20 -0
- data/lib/hps/infrastructure/hps_input_validation.rb +13 -0
- data/lib/hps/infrastructure/hps_sec_code.rb +27 -0
- data/lib/hps/services/hps_charge_service.rb +94 -94
- data/lib/hps/services/hps_check_service.rb +110 -0
- data/lib/hps/services/hps_service.rb +11 -2
- data/lib/hps/version.rb +1 -1
- data/tests/check_tests.rb +50 -0
- data/tests/test_check.rb +77 -0
- data/tests/test_helper.rb +3 -2
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe094a2e028c26d7589d019cc4b65cddb785eaf9
|
4
|
+
data.tar.gz: e20c7eca17da26e189def2911b818e4483162f32
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '096e7db7554ff2df05fb79f396c31fcc6a4023bb7fe591112e719a9f1076b8b52575f83cf287c7f4b311dd87e174a341457ad1d6704f6ebbcaeff86878d1df33'
|
7
|
+
data.tar.gz: f6876b71ee04b70af33db644226c485ecd7c6d38825a82883be5e371b455cfe49508612ff4d4498972bd13fec8e7b3edbc2acc00accb022abdc43fff9f04bf77
|
data/README.md
CHANGED
@@ -15,6 +15,8 @@ This SDK makes it easy to integrate your Ruby application with Heartland's [**Po
|
|
15
15
|
|
16
16
|
Supported Gateway Calls
|
17
17
|
|
18
|
+
* CheckSale
|
19
|
+
* CheckVoid
|
18
20
|
* CreditAccountVerify (4.3)
|
19
21
|
* CreditAddToBatch (4.4)
|
20
22
|
* CreditAuth (4.5)
|
@@ -31,7 +33,7 @@ Supported Gateway Calls
|
|
31
33
|
| [![](http://developer.heartlandpaymentsystems.com/Resource/Download/sdk-readme-icon-secure)](#data-security) | [![](http://developer.heartlandpaymentsystems.com/Resource/Download/sdk-readme-icon-resources)](#documentation-and-examples) | [![](http://developer.heartlandpaymentsystems.com/Resource/Download/sdk-readme-icon-tools)](#certification--testing) | [![](http://developer.heartlandpaymentsystems.com/Resource/Download/sdk-readme-icon-keys)](#api-keys) | <a href="http://developer.heartlandpaymentsystems.com/Account/Register" target="_blank">Register an Account</a> <br> <a href="http://www.heartlandpaymentsystems.com/partners/" target="_blank">Partner with Heartland</a> <br> <a href="http://developer.heartlandpaymentsystems.com/SecureSubmit/Support" target="_blank">Developer Support</a> |
|
32
34
|
|
33
35
|
|
34
|
-
####Developer Support
|
36
|
+
#### Developer Support
|
35
37
|
|
36
38
|
You are not alone! If you have any questions while you are working through your development process, please feel free to <a href="mailto:entapp_devportal@e-hps.com?Subject=Developer Support Request">reach out to our team for assistance</a>.
|
37
39
|
|
@@ -113,7 +115,7 @@ Testing your implementation in our Certification/Sandbox environment helps to id
|
|
113
115
|
|
114
116
|
*Quick Tip*: You can get a head start on your certification by reviewing the [certification tests](https://github.com/hps/heartland-ruby/tree/master/tests) in the included test suite.
|
115
117
|
|
116
|
-
####Test Card Data
|
118
|
+
#### Test Card Data
|
117
119
|
|
118
120
|
The following card numbers are used by our Certification environment to verify that your tests worked. Note that while variations (such as 4111111111111111) will work for general testing the cards listed below are required to complete certification.
|
119
121
|
|
@@ -178,7 +180,7 @@ The following card numbers are used by our Certification environment to verify t
|
|
178
180
|
</tbody>
|
179
181
|
</table>
|
180
182
|
|
181
|
-
####Testing Exceptions
|
183
|
+
#### Testing Exceptions
|
182
184
|
|
183
185
|
During your integration you will want to test for specific issuer responses such as 'Card Declined'. Because our sandbox does not actually reach out to issuers we have devised specific transaction amounts that will trigger [issuer response codes](https://cert.api2.heartlandportico.com/Gateway/PorticoDevGuide/build/PorticoDeveloperGuide/Issuer%20Response%20Codes.html) and [gateway response codes](https://cert.api2.heartlandportico.com/Gateway/PorticoDevGuide/build/PorticoDeveloperGuide/Gateway%20Response%20Codes.html). Please <a href="mailto:SecureSubmitCert@e-hps.com?subject=Hard Coded Values Spreadsheet Request">contact</a> Heartland for a complete listing of values you can charge to simulate AVS, CVV and Transaction declines, errors, and other responses that you can catch in your code:
|
184
186
|
|
@@ -207,7 +209,7 @@ All our code is open sourced and we encourage fellow developers to contribute an
|
|
207
209
|
6. Create new Pull Request
|
208
210
|
|
209
211
|
|
210
|
-
####Included Test Suite
|
212
|
+
#### Included Test Suite
|
211
213
|
|
212
214
|
The included test suite can help ensure your contribution doesn't cause unexpected errors and is a terrific resource of working examples that you can reference. As mentioned earlier, the [certification folder](http://github.hps.com/DevPortal/Ruby-SDK/blob/master/tests/cert_tests.rb) contains tests that mirror the types of requirements you will encounter when you certify your integration for production.
|
213
215
|
|
data/lib/hps.rb
CHANGED
@@ -25,6 +25,10 @@ require "hps/entities/hps_transaction_header"
|
|
25
25
|
require "hps/entities/hps_transaction_type"
|
26
26
|
require "hps/entities/hps_transaction_details"
|
27
27
|
require "hps/entities/hps_void"
|
28
|
+
require "hps/entities/hps_check"
|
29
|
+
require "hps/entities/hps_check_holder"
|
30
|
+
require "hps/entities/hps_check_response"
|
31
|
+
require "hps/entities/hps_check_response_details"
|
28
32
|
|
29
33
|
# Infrastructure
|
30
34
|
require "hps/infrastructure/hps_sdk_codes"
|
@@ -35,10 +39,18 @@ require "hps/infrastructure/card_exception"
|
|
35
39
|
require "hps/infrastructure/invalid_request_exception"
|
36
40
|
require "hps/infrastructure/hps_exception_mapper"
|
37
41
|
require "hps/infrastructure/hps_track_data_method"
|
42
|
+
require "hps/infrastructure/hps_account_type"
|
43
|
+
require "hps/infrastructure/hps_check_type"
|
44
|
+
require "hps/infrastructure/hps_data_entry_mode"
|
45
|
+
require "hps/infrastructure/hps_sec_code"
|
46
|
+
require "hps/infrastructure/hps_input_validation"
|
47
|
+
require "hps/infrastructure/hps_gateway_response_validation"
|
48
|
+
require "hps/infrastructure/hps_check_exception"
|
38
49
|
|
39
50
|
# Services
|
40
51
|
require "hps/services/hps_service"
|
41
52
|
require "hps/services/hps_charge_service"
|
53
|
+
require "hps/services/hps_check_service"
|
42
54
|
require "hps/services/hps_batch_service"
|
43
55
|
|
44
56
|
module Hps
|
data/lib/hps/configuration.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
module Hps
|
2
2
|
module Configuration
|
3
3
|
|
4
|
-
VALID_CONFIG_KEYS = [ :service_uri, :user_name, :password, :developer_id, :version_number, :license_id, :device_id, :site_id, :site_trace, :secret_api_key ].freeze
|
4
|
+
VALID_CONFIG_KEYS = [ :service_uri, :user_name, :password, :developer_id, :version_number, :license_id, :device_id, :site_id, :site_trace, :secret_api_key, :http_options ].freeze
|
5
5
|
|
6
6
|
attr_accessor *VALID_CONFIG_KEYS
|
7
7
|
|
8
8
|
def configure
|
9
9
|
yield self
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def options
|
13
13
|
Hash[ * VALID_CONFIG_KEYS.map { |key| [key, send(key)] }.flatten ]
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
end
|
17
|
-
end
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Hps
|
2
|
+
class HpsCheck
|
3
|
+
attr_accessor :routing_number,
|
4
|
+
:account_number,
|
5
|
+
:check_number,
|
6
|
+
:check_type,
|
7
|
+
:check_holder,
|
8
|
+
:micr_number,
|
9
|
+
:account_type,
|
10
|
+
:data_entry_mode,
|
11
|
+
:check_verify,
|
12
|
+
:sec_code
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@data_entry_mode = HpsDataEntryMode.manual
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Hps
|
2
|
+
class HpsCheckResponse < HpsTransaction
|
3
|
+
attr_accessor :authorization_code,
|
4
|
+
:customer_id,
|
5
|
+
:details
|
6
|
+
|
7
|
+
def self.from_hash(rsp, txn_type)
|
8
|
+
header = rsp["Header"]
|
9
|
+
data = rsp["Transaction"][txn_type.to_s]
|
10
|
+
|
11
|
+
result = HpsCheckResponse.new(HpsService.new.hydrate_transaction_header(header))
|
12
|
+
result.transaction_id = header["GatewayTxnId"]
|
13
|
+
result.authorization_code = data["AuthCode"]
|
14
|
+
result.reference_number = data["RefNbr"]
|
15
|
+
result.response_code = data["RspCode"]
|
16
|
+
result.response_text = data["RspMessage"]
|
17
|
+
|
18
|
+
if data["CheckRspInfo"]
|
19
|
+
result.details = []
|
20
|
+
check_info = data["CheckRspInfo"]
|
21
|
+
if check_info.is_a? Hash
|
22
|
+
result.details = HpsCheckResponse.hydrate_rsp_details(check_info)
|
23
|
+
else
|
24
|
+
check_info.map { |details|
|
25
|
+
result.details.push HpsCheckResponse.hydrate_rsp_details(details)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
result
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def self.hydrate_rsp_details(check_info)
|
36
|
+
details = HpsCheckResponseDetails.new
|
37
|
+
details.message_type = check_info["Type"]
|
38
|
+
details.code = check_info["Code"]
|
39
|
+
details.message = check_info["Message"]
|
40
|
+
details.field_number = check_info["FieldNumber"]
|
41
|
+
details.field_name = check_info["FieldName"]
|
42
|
+
details
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Hps
|
2
|
+
class HpsCheckException < HpsException
|
3
|
+
attr_accessor :transaction_id,
|
4
|
+
:details,
|
5
|
+
:code
|
6
|
+
|
7
|
+
def initialize(transaction_id, details, code, message = nil)
|
8
|
+
@transaction_id = transaction_id
|
9
|
+
@details = details
|
10
|
+
super(message, code)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Hps
|
2
|
+
class HpsGatewayResponseValidation
|
3
|
+
def self.check_response(response, expected_type)
|
4
|
+
response_code = response["Header"]["GatewayRspCode"]
|
5
|
+
response_text = response["Header"]["GatewayRspMsg"]
|
6
|
+
transaction_id = response["Header"]["GatewayTxnId"]
|
7
|
+
|
8
|
+
if !response_code.eql? "0"
|
9
|
+
exception = Hps::ExceptionMapper.new.map_gateway_exception(transaction_id, response_code, response_text)
|
10
|
+
exception.response_code = response_code
|
11
|
+
exception.response_text = response_text
|
12
|
+
raise exception
|
13
|
+
end
|
14
|
+
|
15
|
+
unless response["Transaction"] && response["Transaction"][expected_type.to_s]
|
16
|
+
raise HpsGatewayException
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Hps
|
2
|
+
class HpsSECCode
|
3
|
+
def self.ppd
|
4
|
+
'PPD'
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.ccd
|
8
|
+
'CCD'
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.pop
|
12
|
+
'POP'
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.web
|
16
|
+
'WEB'
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.tel
|
20
|
+
'TEL'
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.e_bronze
|
24
|
+
'eBronze'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module Hps
|
2
|
-
|
2
|
+
class HpsChargeService < HpsService
|
3
3
|
|
4
|
-
|
4
|
+
def get(transaction_id)
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
if transaction_id.nil? or transaction_id == 0
|
7
|
+
raise @exception_mapper.map_sdk_exception(SdkCodes.invalid_transaction_id)
|
8
|
+
end
|
9
9
|
|
10
10
|
xml = Builder::XmlMarkup.new
|
11
11
|
xml.hps :Transaction do
|
@@ -14,65 +14,65 @@ module Hps
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
response = doTransaction(xml.target!)
|
18
18
|
detail = response["Transaction"]["ReportTxnDetail"]
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
20
|
+
header = hydrate_transaction_header(response["Header"])
|
21
|
+
result = HpsReportTransactionDetails.new(header)
|
22
|
+
result.transaction_id = detail["GatewayTxnId"]
|
23
|
+
result.original_transaction_id = detail["OriginalGatewayTxnId"]
|
24
|
+
result.authorized_amount = detail["Data"]["AuthAmt"]
|
25
|
+
result.authorization_code = detail["Data"]["AuthCode"]
|
26
|
+
result.avs_result_code = detail["Data"]["AVSRsltCode"]
|
27
|
+
result.avs_result_text = detail["Data"]["AVSRsltText"]
|
28
|
+
result.card_type = detail["Data"]["CardType"]
|
29
|
+
result.masked_card_number = detail["Data"]["MaskedCardNbr"]
|
30
|
+
result.transaction_type = Hps.service_name_to_transaction_type(detail["ServiceName"])
|
31
|
+
result.transaction_date = detail["RspUtcDT"]
|
32
|
+
result.cpc_indicator = detail["Data"]["CPCInd"]
|
33
|
+
result.cvv_result_code = detail["Data"]["CVVRsltCode"]
|
34
|
+
result.cvv_result_text = detail["Data"]["CVVRsltText"]
|
35
35
|
result.reference_number = detail["Data"]["RefNbr"]
|
36
36
|
result.response_code = detail["Data"]["RspCode"]
|
37
37
|
result.response_text = detail["Data"]["RspText"]
|
38
38
|
|
39
|
-
|
39
|
+
tokenization_message = detail["Data"]["TokenizationMsg"]
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
unless tokenization_message.nil?
|
42
|
+
result.token_data = HpsTokenData.new(tokenization_message)
|
43
|
+
end
|
44
44
|
|
45
|
-
|
46
|
-
|
45
|
+
header_response_code = response["Header"]["GatewayRspCode"]
|
46
|
+
data_response_code = detail["Data"]["RspCode"]
|
47
47
|
|
48
|
-
|
48
|
+
if header_response_code != "0" or data_response_code != "0" or data_response_code != "00"
|
49
49
|
|
50
|
-
|
50
|
+
exceptions = HpsChargeExceptions.new()
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
52
|
+
if header_response_code != "0"
|
53
|
+
message = response["Header"]["GatewayRspMsg"]
|
54
|
+
exceptions.hps_exception = @exception_mapper.map_gateway_exception(result.transaction_id, header_response_code, message)
|
55
|
+
end
|
56
56
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
57
|
+
if data_response_code != "0" || data_response_code != "00"
|
58
|
+
message = detail["Data"]["RspText"]
|
59
|
+
exceptions.card_exception = @exception_mapper.map_issuer_exception(transaction_id, data_response_code, message)
|
60
|
+
end
|
61
61
|
|
62
|
-
|
62
|
+
result.exceptions = exceptions
|
63
63
|
|
64
|
-
|
64
|
+
end
|
65
65
|
|
66
|
-
|
66
|
+
result
|
67
67
|
|
68
|
-
|
68
|
+
end
|
69
69
|
|
70
|
-
|
70
|
+
def list(start_date, end_date, filter_by = nil)
|
71
71
|
|
72
72
|
if start_date > DateTime.now
|
73
|
-
|
73
|
+
raise @exception_mapper.map_sdk_exception(SdkCodes.invalid_start_date)
|
74
74
|
elsif end_date > DateTime.now
|
75
|
-
|
75
|
+
raise @exception_mapper.map_sdk_exception(SdkCodes.invalid_end_date)
|
76
76
|
end
|
77
77
|
|
78
78
|
xml = Builder::XmlMarkup.new
|
@@ -83,62 +83,62 @@ module Hps
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
-
|
86
|
+
response = doTransaction(xml.target!)
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
88
|
+
# Gateway exception
|
89
|
+
if response["Header"]["GatewayRspCode"] != "0"
|
90
|
+
transaction_id = response["Header"]["GatewayTxnId"]
|
91
|
+
response_code = response["Header"]["GatewayRspCode"]
|
92
|
+
response_message = response["Header"]["GatewayRspMsg"]
|
93
|
+
raise @exception_mapper.map_gateway_exception(transaction_id, response_code, response_message)
|
94
|
+
end
|
95
95
|
|
96
|
-
|
96
|
+
result = Array.new
|
97
97
|
|
98
98
|
if response["Transaction"]["ReportActivity"]["Header"]["TxnCnt"] == "0"
|
99
99
|
return result
|
100
100
|
end
|
101
101
|
|
102
|
-
|
102
|
+
response["Transaction"]["ReportActivity"]["Details"].each { |charge|
|
103
103
|
|
104
|
-
|
104
|
+
next if !filter_by.nil? and charge.serviceName != Hps.transaction_type_to_service_name(filter_by)
|
105
105
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
106
|
+
summary = HpsReportTransactionSummary.new()
|
107
|
+
summary.transaction_id = charge["GatewayTxnId"]
|
108
|
+
summary.original_transaction_id = charge["OriginalGatewayTxnId"]
|
109
|
+
summary.masked_card_number = charge["MaskedCardNbr"]
|
110
|
+
summary.response_code = charge["IssuerRspCode"]
|
111
|
+
summary.response_text = charge["IssuerRspText"]
|
112
|
+
summary.transaction_type = Hps.transaction_type_to_service_name(charge["ServiceName"]) if filter_by.nil? == false
|
113
113
|
|
114
|
-
|
115
|
-
|
114
|
+
gw_response_code = charge["GatewayRspCode"]
|
115
|
+
issuer_response_code = charge["IssuerRspCode"]
|
116
116
|
|
117
|
-
|
117
|
+
if gw_response_code != "0" or issuer_response_code != "0" or issuer_response_code != "00"
|
118
118
|
|
119
|
-
|
119
|
+
exceptions = HpsChargeExceptions.new()
|
120
120
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
121
|
+
if gw_response_code != "0"
|
122
|
+
message = charge["GatewayRspMsg"]
|
123
|
+
exceptions.hps_exception = @exception_mapper.map_gateway_exception(charge["GatewayTxnId"], gw_response_code, message)
|
124
|
+
end
|
125
125
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
126
|
+
if issuer_response_code != "0" || issuer_response_code != "00"
|
127
|
+
message = charge["IssuerRspText"]
|
128
|
+
exceptions.card_exception = @exception_mapper.map_issuer_exception(charge["GatewayTxnId"], issuer_response_code, message)
|
129
|
+
end
|
130
130
|
|
131
|
-
|
131
|
+
summary.exceptions = exceptions
|
132
132
|
|
133
|
-
|
133
|
+
end
|
134
134
|
|
135
|
-
|
136
|
-
|
135
|
+
result << summary
|
136
|
+
}
|
137
137
|
|
138
|
-
|
139
|
-
|
138
|
+
result
|
139
|
+
end
|
140
140
|
|
141
|
-
|
141
|
+
def charge(amount, currency, card, card_holder = nil, request_multi_use_token = false, details = nil, txn_descriptor = nil)
|
142
142
|
check_amount(amount)
|
143
143
|
check_currency(currency)
|
144
144
|
|
@@ -171,9 +171,9 @@ module Hps
|
|
171
171
|
end
|
172
172
|
|
173
173
|
submit_charge(xml.target!, amount, currency)
|
174
|
-
|
174
|
+
end
|
175
175
|
|
176
|
-
|
176
|
+
def charge_swipe(amount, currency, track_data, encryption_data = nil, gratuity = 0, allow_partial_auth = false, txn_descriptor = nil, request_multi_use_token = false, direct_market_data = nil)
|
177
177
|
check_amount(amount)
|
178
178
|
check_currency(currency)
|
179
179
|
|
@@ -197,7 +197,7 @@ module Hps
|
|
197
197
|
end
|
198
198
|
|
199
199
|
submit_charge(xml.target!, amount, currency)
|
200
|
-
|
200
|
+
end
|
201
201
|
|
202
202
|
def verify(card, card_holder = nil, request_multi_use_token = false, client_txn_id = nil)
|
203
203
|
|
@@ -435,16 +435,16 @@ module Hps
|
|
435
435
|
|
436
436
|
submit_void(xml.target!)
|
437
437
|
end
|
438
|
-
|
438
|
+
private
|
439
439
|
|
440
|
-
|
441
|
-
|
442
|
-
|
440
|
+
def check_amount(amount)
|
441
|
+
raise @exception_mapper.map_sdk_exception(SdkCodes.invalid_amount) if amount.nil? or amount <= 0
|
442
|
+
end
|
443
443
|
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
444
|
+
def check_currency(currency)
|
445
|
+
raise @exception_mapper.map_sdk_exception(SdkCodes.missing_currency) if currency.empty?
|
446
|
+
raise @exception_mapper.map_sdk_exception(SdkCodes.invalid_currency) unless currency.downcase.eql? "usd"
|
447
|
+
end
|
448
448
|
|
449
449
|
def hydrate_cardholder_data(card_holder)
|
450
450
|
xml = Builder::XmlMarkup.new
|
@@ -719,7 +719,7 @@ module Hps
|
|
719
719
|
exception.response_text = response_text
|
720
720
|
raise exception
|
721
721
|
|
722
|
-
elsif !response_code.eql? "00"
|
722
|
+
elsif !response_code.eql? "00" && !response_code.eql? "0"
|
723
723
|
|
724
724
|
exception = @exception_mapper.map_issuer_exception(transaction_id, response_code, response_text)
|
725
725
|
exception.response_code = response_code
|
@@ -730,6 +730,6 @@ module Hps
|
|
730
730
|
|
731
731
|
end
|
732
732
|
|
733
|
-
|
733
|
+
end
|
734
734
|
|
735
735
|
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module Hps
|
2
|
+
class HpsCheckService < HpsService
|
3
|
+
def sale(check, amount, client_txn_id = nil)
|
4
|
+
build_transaction('SALE', check, amount, client_txn_id)
|
5
|
+
end
|
6
|
+
|
7
|
+
def void(transaction_id = nil, client_txn_id = nil)
|
8
|
+
if (transaction_id == nil && client_txn_id == nil) ||
|
9
|
+
(transaction_id != nil && client_txn_id != nil)
|
10
|
+
raise Error, 'Please provide either a transaction ID or a client transaction ID'
|
11
|
+
end
|
12
|
+
|
13
|
+
xml = Builder::XmlMarkup.new
|
14
|
+
xml.hps :Transaction do
|
15
|
+
xml.hps :CheckVoid do
|
16
|
+
xml.hps :Block1 do
|
17
|
+
xml.hps :GatewayTxnId, transaction_id if transaction_id
|
18
|
+
xml.hps :ClientTxnId, client_txn_id if client_txn_id
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
submit_transaction(xml.target!, :CheckVoid)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def build_transaction(action, check, amount, client_txn_id)
|
29
|
+
amount = HpsInputValidation::check_amount(amount)
|
30
|
+
|
31
|
+
if check.sec_code == HpsSECCode.ccd &&
|
32
|
+
(check.check_holder == nil || check.check_holder.check_name == nil)
|
33
|
+
raise Error, 'For SEC code CCD, the check name is require', 'check_name'
|
34
|
+
end
|
35
|
+
|
36
|
+
xml = Builder::XmlMarkup.new
|
37
|
+
xml.hps :Transaction do
|
38
|
+
xml.hps :CheckSale do
|
39
|
+
xml.hps :Block1 do
|
40
|
+
xml.hps :Amt, amount
|
41
|
+
xml << hydrate_check_data(check)
|
42
|
+
xml.hps :CheckAction, action
|
43
|
+
xml.hps :SECCode, check.sec_code
|
44
|
+
xml.hps :CheckType, check.check_type if check.check_type
|
45
|
+
xml << hydrate_consumer_info(check.check_holder) if check.check_holder
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
submit_transaction(xml.target!, :CheckSale, client_txn_id)
|
51
|
+
end
|
52
|
+
|
53
|
+
def hydrate_check_data(check)
|
54
|
+
xml = Builder::XmlMarkup.new
|
55
|
+
xml.hps :AccountInfo do
|
56
|
+
xml.hps :AccountNumber, check.account_number if check.account_number
|
57
|
+
xml.hps :CheckNumber, check.check_number if check.check_number
|
58
|
+
xml.hps :MICRData, check.micr_number if check.micr_number
|
59
|
+
xml.hps :RoutingNumber, check.routing_number if check.routing_number
|
60
|
+
xml.hps :AccountType, check.account_type if check.account_type
|
61
|
+
end
|
62
|
+
xml.target!
|
63
|
+
end
|
64
|
+
|
65
|
+
def hydrate_consumer_info(check_holder)
|
66
|
+
xml = Builder::XmlMarkup.new
|
67
|
+
xml.hps :ConsumerInfo do
|
68
|
+
if check_holder.address
|
69
|
+
xml.hps :Address1, check_holder.address.address if check_holder.address.address
|
70
|
+
xml.hps :City, check_holder.address.city if check_holder.address.city
|
71
|
+
xml.hps :State, check_holder.address.state if check_holder.address.state
|
72
|
+
xml.hps :Zip, check_holder.address.zip if check_holder.address.zip
|
73
|
+
end
|
74
|
+
|
75
|
+
xml.hps :CheckName, check_holder.check_name if check_holder.check_name
|
76
|
+
xml.hps :CourtesyCard, check_holder.courtesy_card if check_holder.courtesy_card
|
77
|
+
xml.hps :DLNumber, check_holder.dl_number if check_holder.dl_number
|
78
|
+
xml.hps :DLState, check_holder.dl_state if check_holder.dl_state
|
79
|
+
xml.hps :EmailAddress, check_holder.email if check_holder.email_address
|
80
|
+
xml.hps :FirstName, check_holder.first_name if check_holder.first_name
|
81
|
+
xml.hps :LastName, check_holder.last_name if check_holder.last_name
|
82
|
+
xml.hps :PhoneNumber, check_holder.phone if check_holder.phone
|
83
|
+
|
84
|
+
if check_holder.ssl4 || check_holder.dob_year
|
85
|
+
xml.hps :IdentityInfo do
|
86
|
+
xml.hps :SSNL4, check_holder.ssl4 if check_holder.ssl4
|
87
|
+
xml.hps :DOBYear, check_holder.dob_year if check_holder.dob_year
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
xml.target!
|
93
|
+
end
|
94
|
+
|
95
|
+
def submit_transaction(xml, txn_type, client_txn_id = nil)
|
96
|
+
response = doTransaction(xml, client_txn_id)
|
97
|
+
HpsGatewayResponseValidation::check_response(response, txn_type)
|
98
|
+
response = HpsCheckResponse::from_hash(response, txn_type)
|
99
|
+
|
100
|
+
return response if response.response_code == '0'
|
101
|
+
|
102
|
+
raise HpsCheckException.new(
|
103
|
+
response.transaction_id,
|
104
|
+
response.details,
|
105
|
+
response.response_code,
|
106
|
+
response.response_text
|
107
|
+
)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -20,7 +20,7 @@ module Hps
|
|
20
20
|
|
21
21
|
#protected
|
22
22
|
|
23
|
-
def doTransaction(transaction)
|
23
|
+
def doTransaction(transaction, client_txn_id = nil)
|
24
24
|
|
25
25
|
if configuration_invalid
|
26
26
|
raise @exception_mapper.map_sdk_exception(SdkCodes.invalid_transaction_id)
|
@@ -48,6 +48,7 @@ module Hps
|
|
48
48
|
xml.hps :DeveloperID, self.developer_id if self.developer_id
|
49
49
|
xml.hps :VersionNbr, self.version_number if self.version_number
|
50
50
|
xml.hps :SiteTrace, self.site_trace if self.site_trace
|
51
|
+
xml.hps :ClientTxnId, client_txn_id if client_txn_id
|
51
52
|
end
|
52
53
|
|
53
54
|
xml << transaction
|
@@ -62,7 +63,15 @@ module Hps
|
|
62
63
|
uri = URI.parse(self.service_uri)
|
63
64
|
http = Net::HTTP.new uri.host, uri.port
|
64
65
|
http.use_ssl = true
|
65
|
-
|
66
|
+
|
67
|
+
# allow SSL verification as opt-in
|
68
|
+
if self.http_options && self.http_options.verify_mode
|
69
|
+
http.verify_mode = self.http_options.verify_mode
|
70
|
+
http.ca_file = self.http_options.ca_file if self.http_options.ca_file
|
71
|
+
else
|
72
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
73
|
+
end
|
74
|
+
|
66
75
|
data = xml.target!
|
67
76
|
|
68
77
|
response = http.post(uri.path, data, 'Content-type' => 'text/xml')
|
data/lib/hps/version.rb
CHANGED
@@ -0,0 +1,50 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), "test_helper.rb" )
|
2
|
+
|
3
|
+
describe "Check Tests" do
|
4
|
+
before(:each) do
|
5
|
+
Hps::TestHelper.configure_hps_module_secret_key_with_spaces
|
6
|
+
@service = Hps::HpsCheckService.new()
|
7
|
+
end
|
8
|
+
|
9
|
+
it "check should decline" do
|
10
|
+
expect {
|
11
|
+
@service.sale(Hps::TestCheck::decline, 5.00)
|
12
|
+
}.to raise_error(Hps::HpsCheckException) { |error|
|
13
|
+
expect(error.code).to eql("1")
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should throw check exception" do
|
18
|
+
expect {
|
19
|
+
@service.sale(Hps::TestCheck::invalid_check_holder, 5.00)
|
20
|
+
}.to raise_error(Hps::HpsCheckException) { |error|
|
21
|
+
expect(error.code).to eql("1")
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
it "check should sale" do
|
26
|
+
result = @service.sale(Hps::TestCheck::approve, 5.00)
|
27
|
+
expect(result).not_to eql(nil)
|
28
|
+
expect(result.response_code).to eql("0")
|
29
|
+
expect(result.response_text).to eql("Transaction Approved")
|
30
|
+
end
|
31
|
+
|
32
|
+
it "check should void" do
|
33
|
+
sale_result = @service.sale(Hps::TestCheck::approve, 5.00)
|
34
|
+
result = @service.void(sale_result.transaction_id)
|
35
|
+
expect(result).not_to eql(nil)
|
36
|
+
expect(result.response_code).to eql("0")
|
37
|
+
end
|
38
|
+
|
39
|
+
it "sale and void with client_txn_id" do
|
40
|
+
client_txn_id = 10244205
|
41
|
+
sale_result = @service.sale(Hps::TestCheck::approve, 5.00, client_txn_id)
|
42
|
+
expect(sale_result).not_to eql(nil)
|
43
|
+
expect(sale_result.response_code).to eql("0")
|
44
|
+
expect(sale_result.response_text).to eql("Transaction Approved")
|
45
|
+
|
46
|
+
void_result = @service.void(nil, client_txn_id)
|
47
|
+
expect(void_result).not_to eql(nil)
|
48
|
+
expect(void_result.response_code).to eql("0")
|
49
|
+
end
|
50
|
+
end
|
data/tests/test_check.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'hps'
|
2
|
+
|
3
|
+
module Hps
|
4
|
+
module TestCheck
|
5
|
+
def self.approve
|
6
|
+
check = HpsCheck.new()
|
7
|
+
check.account_number = '24413815'
|
8
|
+
check.routing_number = '490000018'
|
9
|
+
check.check_type = HpsCheckType.personal
|
10
|
+
check.account_type = HpsAccountType.checking
|
11
|
+
check.sec_code = HpsSECCode.ppd
|
12
|
+
|
13
|
+
check.check_holder = HpsCheckHolder.new()
|
14
|
+
check.check_holder.first_name = "Bill"
|
15
|
+
check.check_holder.last_name = "Johnson"
|
16
|
+
check.check_holder.address = HpsAddress.new
|
17
|
+
check.check_holder.address.address = "One Heartland Way"
|
18
|
+
check.check_holder.address.city = "Jeffersonville"
|
19
|
+
check.check_holder.address.state = "IN"
|
20
|
+
check.check_holder.address.zip = "47130"
|
21
|
+
check.check_holder.address.country = "United States"
|
22
|
+
check.check_holder.dl_number = '1234567'
|
23
|
+
check.check_holder.dl_state = 'TX'
|
24
|
+
check.check_holder.phone = '1234567890'
|
25
|
+
|
26
|
+
check
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.invalid_check_holder
|
30
|
+
check = HpsCheck.new()
|
31
|
+
check.account_number = '24413815'
|
32
|
+
check.routing_number = '490000018'
|
33
|
+
check.check_type = HpsCheckType.personal
|
34
|
+
check.account_type = HpsAccountType.checking
|
35
|
+
check.sec_code = HpsSECCode.ppd
|
36
|
+
|
37
|
+
check.check_holder = HpsCheckHolder.new()
|
38
|
+
check.check_holder.first_name = "Bill"
|
39
|
+
check.check_holder.last_name = "Johnson"
|
40
|
+
check.check_holder.address = HpsAddress.new
|
41
|
+
check.check_holder.address.address = "One Heartland Way"
|
42
|
+
check.check_holder.address.city = "Jeffersonville"
|
43
|
+
check.check_holder.address.state = "IN"
|
44
|
+
check.check_holder.address.zip = "47130"
|
45
|
+
check.check_holder.address.country = "United States"
|
46
|
+
check.check_holder.dl_number = ''
|
47
|
+
check.check_holder.dl_state = ''
|
48
|
+
check.check_holder.phone = '1234567890'
|
49
|
+
|
50
|
+
check
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.decline
|
54
|
+
check = HpsCheck.new()
|
55
|
+
check.account_number = '24413815'
|
56
|
+
check.routing_number = '490000034'
|
57
|
+
check.check_type = HpsCheckType.personal
|
58
|
+
check.account_type = HpsAccountType.checking
|
59
|
+
check.sec_code = HpsSECCode.ppd
|
60
|
+
|
61
|
+
check.check_holder = HpsCheckHolder.new()
|
62
|
+
check.check_holder.first_name = "Bill"
|
63
|
+
check.check_holder.last_name = "Johnson"
|
64
|
+
check.check_holder.address = HpsAddress.new
|
65
|
+
check.check_holder.address.address = "One Heartland Way"
|
66
|
+
check.check_holder.address.city = "Jeffersonville"
|
67
|
+
check.check_holder.address.state = "IN"
|
68
|
+
check.check_holder.address.zip = "47130"
|
69
|
+
check.check_holder.address.country = "United States"
|
70
|
+
check.check_holder.dl_number = '1234567'
|
71
|
+
check.check_holder.dl_state = 'TX'
|
72
|
+
check.check_holder.phone = '1234567890'
|
73
|
+
|
74
|
+
check
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/tests/test_helper.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require File.join( File.dirname(__FILE__), "test_data.rb" )
|
2
|
+
require File.join( File.dirname(__FILE__), "test_check.rb" )
|
2
3
|
require "hps"
|
3
4
|
require "rspec"
|
4
5
|
|
@@ -25,13 +26,13 @@ module Hps
|
|
25
26
|
config.secret_api_key = "skapi_uat_MXZOAAC7LmEFVeOYGlVHe_WhvRf_UzWzJq5VJ8A-jA"
|
26
27
|
end
|
27
28
|
end
|
28
|
-
|
29
|
+
|
29
30
|
def self.configure_hps_module_secret_key_with_spaces
|
30
31
|
Hps.configure do |config|
|
31
32
|
#config.service_uri = "https://cert.api2.heartlandportico.com/Hps.Exchange.PosGateway/PosGatewayService.asmx?wsdl"
|
32
33
|
config.secret_api_key = " skapi_cert_MYl2AQAowiQAbLp5JesGKh7QFkcizOP2jcX9BrEMqQ "
|
33
34
|
end
|
34
|
-
end
|
35
|
+
end
|
35
36
|
|
36
37
|
def self.configure_hps_module_for_certification
|
37
38
|
Hps.configure do |config|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hps
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1
|
4
|
+
version: 2.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Heartland Payment Systems
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -129,6 +129,10 @@ files:
|
|
129
129
|
- lib/hps/entities/hps_cardholder.rb
|
130
130
|
- lib/hps/entities/hps_charge.rb
|
131
131
|
- lib/hps/entities/hps_charge_exceptions.rb
|
132
|
+
- lib/hps/entities/hps_check.rb
|
133
|
+
- lib/hps/entities/hps_check_holder.rb
|
134
|
+
- lib/hps/entities/hps_check_response.rb
|
135
|
+
- lib/hps/entities/hps_check_response_details.rb
|
132
136
|
- lib/hps/entities/hps_credit_card.rb
|
133
137
|
- lib/hps/entities/hps_direct_market_data.rb
|
134
138
|
- lib/hps/entities/hps_encryption_data.rb
|
@@ -147,24 +151,34 @@ files:
|
|
147
151
|
- lib/hps/infrastructure/authentication_exception.rb
|
148
152
|
- lib/hps/infrastructure/card_exception.rb
|
149
153
|
- lib/hps/infrastructure/exceptions.json
|
154
|
+
- lib/hps/infrastructure/hps_account_type.rb
|
155
|
+
- lib/hps/infrastructure/hps_check_exception.rb
|
156
|
+
- lib/hps/infrastructure/hps_check_type.rb
|
157
|
+
- lib/hps/infrastructure/hps_data_entry_mode.rb
|
150
158
|
- lib/hps/infrastructure/hps_exception.rb
|
151
159
|
- lib/hps/infrastructure/hps_exception_mapper.rb
|
160
|
+
- lib/hps/infrastructure/hps_gateway_response_validation.rb
|
161
|
+
- lib/hps/infrastructure/hps_input_validation.rb
|
152
162
|
- lib/hps/infrastructure/hps_sdk_codes.rb
|
163
|
+
- lib/hps/infrastructure/hps_sec_code.rb
|
153
164
|
- lib/hps/infrastructure/hps_track_data_method.rb
|
154
165
|
- lib/hps/infrastructure/invalid_request_exception.rb
|
155
166
|
- lib/hps/services/hps_batch_service.rb
|
156
167
|
- lib/hps/services/hps_charge_service.rb
|
168
|
+
- lib/hps/services/hps_check_service.rb
|
157
169
|
- lib/hps/services/hps_service.rb
|
158
170
|
- lib/hps/version.rb
|
159
171
|
- tests/amex_tests.rb
|
160
172
|
- tests/cert_tests.rb
|
161
173
|
- tests/certification/card_present_spec.rb
|
174
|
+
- tests/check_tests.rb
|
162
175
|
- tests/discover_tests.rb
|
163
176
|
- tests/exception_mapper_tests.rb
|
164
177
|
- tests/general_tests.rb
|
165
178
|
- tests/hps_token_service.rb
|
166
179
|
- tests/mastercard_tests.rb
|
167
180
|
- tests/secret_key.rb
|
181
|
+
- tests/test_check.rb
|
168
182
|
- tests/test_data.rb
|
169
183
|
- tests/test_helper.rb
|
170
184
|
- tests/token_tests.rb
|
@@ -189,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
189
203
|
version: '0'
|
190
204
|
requirements: []
|
191
205
|
rubyforge_project:
|
192
|
-
rubygems_version: 2.
|
206
|
+
rubygems_version: 2.6.11
|
193
207
|
signing_key:
|
194
208
|
specification_version: 4
|
195
209
|
summary: Heartland Payment Systems - Portico Gateway SDK
|