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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ef169211a337457fdd345d71363e83dd748525b0
4
- data.tar.gz: b40300100b4d8387fcb0cc2620126c0e5b394789
3
+ metadata.gz: fe094a2e028c26d7589d019cc4b65cddb785eaf9
4
+ data.tar.gz: e20c7eca17da26e189def2911b818e4483162f32
5
5
  SHA512:
6
- metadata.gz: daa2fab5fb3fd00b76a94fd2a2d5cb4ed012b010bda993bac41a859e956c9a7fb2a9cee48f209a95e61e20e01e0424a10982ce6092ecf7dbd67671e4f176ebf8
7
- data.tar.gz: 732560e30c0b5ebda581441bb5e37362be284fe9773170fbcefff2f702d674e24b676d083259bf4764dd05028eeae86371b3ed9ef75e7d1742a4399c61e55219
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
@@ -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,10 @@
1
+ module Hps
2
+ class HpsCheckHolder < HpsCardHolder
3
+ attr_accessor :check_name,
4
+ :dl_state,
5
+ :dl_number,
6
+ :ssl4,
7
+ :dob_year,
8
+ :courtesy_card
9
+ end
10
+ 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,9 @@
1
+ module Hps
2
+ class HpsCheckResponseDetails
3
+ attr_accessor :message_type,
4
+ :code,
5
+ :message,
6
+ :field_number,
7
+ :field_name
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Hps
2
+ class HpsAccountType
3
+ def self.checking
4
+ 'CHECKING'
5
+ end
6
+
7
+ def self.savings
8
+ 'SAVINGS'
9
+ end
10
+ end
11
+ 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,11 @@
1
+ module Hps
2
+ class HpsCheckType
3
+ def self.personal
4
+ 'PERSONAL'
5
+ end
6
+
7
+ def self.business
8
+ 'BUSINESS'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Hps
2
+ class HpsDataEntryMode
3
+ def self.manual
4
+ 'MANUAL'
5
+ end
6
+
7
+ def self.swipe
8
+ 'SWIPE'
9
+ end
10
+ end
11
+ 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,13 @@
1
+ module Hps
2
+ class HpsInputValidation
3
+ def self.check_amount(amount)
4
+ if amount < 0 || amount == nil
5
+ raise InvalidRequestException
6
+ end
7
+
8
+ return amount if amount.is_a? Float
9
+
10
+ amount.gsub(/[^0-9\.]/, '')
11
+ end
12
+ end
13
+ 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
- class HpsChargeService < HpsService
2
+ class HpsChargeService < HpsService
3
3
 
4
- def get(transaction_id)
4
+ def get(transaction_id)
5
5
 
6
- if transaction_id.nil? or transaction_id == 0
7
- raise @exception_mapper.map_sdk_exception(SdkCodes.invalid_transaction_id)
8
- end
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
- response = doTransaction(xml.target!)
17
+ response = doTransaction(xml.target!)
18
18
  detail = response["Transaction"]["ReportTxnDetail"]
19
19
 
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"]
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
- tokenization_message = detail["Data"]["TokenizationMsg"]
39
+ tokenization_message = detail["Data"]["TokenizationMsg"]
40
40
 
41
- unless tokenization_message.nil?
42
- result.token_data = HpsTokenData.new(tokenization_message)
43
- end
41
+ unless tokenization_message.nil?
42
+ result.token_data = HpsTokenData.new(tokenization_message)
43
+ end
44
44
 
45
- header_response_code = response["Header"]["GatewayRspCode"]
46
- data_response_code = detail["Data"]["RspCode"]
45
+ header_response_code = response["Header"]["GatewayRspCode"]
46
+ data_response_code = detail["Data"]["RspCode"]
47
47
 
48
- if header_response_code != "0" or data_response_code != "00"
48
+ if header_response_code != "0" or data_response_code != "0" or data_response_code != "00"
49
49
 
50
- exceptions = HpsChargeExceptions.new()
50
+ exceptions = HpsChargeExceptions.new()
51
51
 
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
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
- if data_response_code != "0"
58
- message = detail["Data"]["RspText"]
59
- exceptions.card_exception = @exception_mapper.map_issuer_exception(transaction_id, data_response_code, message)
60
- end
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
- result.exceptions = exceptions
62
+ result.exceptions = exceptions
63
63
 
64
- end
64
+ end
65
65
 
66
- result
66
+ result
67
67
 
68
- end
68
+ end
69
69
 
70
- def list(start_date, end_date, filter_by = nil)
70
+ def list(start_date, end_date, filter_by = nil)
71
71
 
72
72
  if start_date > DateTime.now
73
- raise @exception_mapper.map_sdk_exception(SdkCodes.invalid_start_date)
73
+ raise @exception_mapper.map_sdk_exception(SdkCodes.invalid_start_date)
74
74
  elsif end_date > DateTime.now
75
- raise @exception_mapper.map_sdk_exception(SdkCodes.invalid_end_date)
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
- response = doTransaction(xml.target!)
86
+ response = doTransaction(xml.target!)
87
87
 
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
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
- result = Array.new
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
- response["Transaction"]["ReportActivity"]["Details"].each { |charge|
102
+ response["Transaction"]["ReportActivity"]["Details"].each { |charge|
103
103
 
104
- next if !filter_by.nil? and charge.serviceName != Hps.transaction_type_to_service_name(filter_by)
104
+ next if !filter_by.nil? and charge.serviceName != Hps.transaction_type_to_service_name(filter_by)
105
105
 
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
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
- gw_response_code = charge["GatewayRspCode"]
115
- issuer_response_code = charge["IssuerRspCode"]
114
+ gw_response_code = charge["GatewayRspCode"]
115
+ issuer_response_code = charge["IssuerRspCode"]
116
116
 
117
- if gw_response_code != "0" or issuer_response_code != "00"
117
+ if gw_response_code != "0" or issuer_response_code != "0" or issuer_response_code != "00"
118
118
 
119
- exceptions = HpsChargeExceptions.new()
119
+ exceptions = HpsChargeExceptions.new()
120
120
 
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
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
- if issuer_response_code != "0"
127
- message = charge["IssuerRspText"]
128
- exceptions.card_exception = @exception_mapper.map_issuer_exception(charge["GatewayTxnId"], issuer_response_code, message)
129
- end
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
- summary.exceptions = exceptions
131
+ summary.exceptions = exceptions
132
132
 
133
- end
133
+ end
134
134
 
135
- result << summary
136
- }
135
+ result << summary
136
+ }
137
137
 
138
- result
139
- end
138
+ result
139
+ end
140
140
 
141
- def charge(amount, currency, card, card_holder = nil, request_multi_use_token = false, details = nil, txn_descriptor = nil)
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
- end
174
+ end
175
175
 
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)
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
- end
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
- private
438
+ private
439
439
 
440
- def check_amount(amount)
441
- raise @exception_mapper.map_sdk_exception(SdkCodes.invalid_amount) if amount.nil? or amount <= 0
442
- end
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
- 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
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
- end
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
- http.verify_mode = OpenSSL::SSL::VERIFY_NONE
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')
@@ -1,3 +1,3 @@
1
1
  module Hps
2
- VERSION = "2.1.2"
2
+ VERSION = "2.2.1"
3
3
  end
@@ -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
@@ -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
@@ -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.2
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: 2016-10-27 00:00:00.000000000 Z
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.5.1
206
+ rubygems_version: 2.6.11
193
207
  signing_key:
194
208
  specification_version: 4
195
209
  summary: Heartland Payment Systems - Portico Gateway SDK