authorize_net 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: af027737f355d0be9ecdf632b089872b67c055ba
4
+ data.tar.gz: af7373a60654eb83262507dd8b5b3475bf0018f1
5
+ SHA512:
6
+ metadata.gz: 67c4b05bbea66632978c76b3d7e35ce210746fba8cdd7bd1cf1479a5499d863d3df2da4cc55396d049524a92d52076ac5a091a231424fa085bc67a0eef1d5f50
7
+ data.tar.gz: 3045de76b817e9e898478829c768c7165be7db6ffb0b96f13065fe13be8e89f4a1800aaf2df6704d729d32b5d03fc35f212b3efc4f85c6c9cb252852ef24f067
@@ -0,0 +1,22 @@
1
+ require 'authorize_net/data_object'
2
+
3
+ class AuthorizeNet::Address < AuthorizeNet::DataObject
4
+
5
+ ATTRIBUTES = {
6
+ :first_name => {:key => "firstName"},
7
+ :last_name => {:key => "lastName"},
8
+ :company => nil,
9
+ :address => nil,
10
+ :city => nil,
11
+ :state => nil,
12
+ :zip => nil,
13
+ :country => nil,
14
+ :phone => nil,
15
+ :fax => nil,
16
+ }
17
+
18
+ self::ATTRIBUTES.keys.each do |attr|
19
+ attr_accessor attr
20
+ end
21
+
22
+ end
@@ -0,0 +1,325 @@
1
+ require 'nokogiri'
2
+
3
+ # ===============================================================
4
+ # This class uses the AuthroizeRequest object to interact with
5
+ # the Authorize.Net API
6
+ #
7
+ # Add any new Authroize.Net API endpoints here
8
+ # ===============================================================
9
+ class AuthorizeNet::Api
10
+
11
+ def initialize(api_login_id, api_transaction_key, is_test_api)
12
+ @api_login_id = api_login_id
13
+ @api_transaction_key = api_transaction_key
14
+ @is_test_api = is_test_api
15
+ @logger = nil
16
+ @log_full_request = false
17
+ end
18
+
19
+ def setLogger(logger)
20
+ @logger = logger
21
+ end
22
+
23
+ def setLogFullRequest(log_full_request)
24
+ @log_full_request = log_full_request
25
+ end
26
+
27
+ # ===============================================================
28
+ # Charges the given credit card
29
+ # @param Number amount
30
+ # @param AuthorizeNet::CreditCard credit_card
31
+ # @param AuthorizeNet::Address billing_address
32
+ # @return {transaction_id}
33
+ # ===============================================================
34
+ def chargeCard(amount, credit_card, billing_address=nil)
35
+ xml_obj = getXmlAuth
36
+ xml_obj["transactionRequest"] = {
37
+ "transactionType" => "authCaptureTransaction",
38
+ "amount" => amount,
39
+ "payment" => {
40
+ "creditCard" => credit_card.to_h,
41
+ },
42
+ }
43
+ if !billing_address.nil?
44
+ xml_obj["transactionRequest"]["billTo"] = billing_address.to_h
45
+ end
46
+
47
+ response = sendRequest("createTransactionRequest", xml_obj)
48
+ if !response.nil?
49
+ return AuthorizeNet::Transaction.parse(response)
50
+ end
51
+ end
52
+
53
+ # ===============================================================
54
+ # Creates the CustomerProfile and charges the first listed
55
+ # PaymentProfile on AuthorizeNet
56
+ # @param Number amount
57
+ # @param AuthorizeNet::CustomerProfile customer_profile
58
+ # @return {customer_profile_id, payment_profile_id}
59
+ # ===============================================================
60
+ def chargeAndCreateProfile(amount, customer_profile)
61
+ if customer_profile.payment_profiles.empty?
62
+ raise "[AuthorizeNet] CustomerProfile in Api.chargeAndCreateProfile requires a PaymentProfile"
63
+ end
64
+
65
+ payment_profile = customer_profile.payment_profiles.first
66
+ xml_obj = getXmlAuth
67
+ xml_obj["transactionRequest"] = {
68
+ "transactionType" => "authCaptureTransaction",
69
+ "amount" => amount,
70
+ "payment" => {
71
+ "creditCard" => payment_profile.credit_card.to_h,
72
+ },
73
+ "profile" => {
74
+ "createProfile" => true,
75
+ },
76
+ "customer" => {
77
+ "id" => customer_profile.merchant_id,
78
+ "email" => customer_profile.email,
79
+ "description" => customer_profile.description,
80
+ "billTo" => payment_profile.billing_address.to_h,
81
+ },
82
+ }
83
+
84
+ response = sendRequest("createTransactionRequest", xml_obj)
85
+
86
+ if !response.nil?
87
+ return {
88
+ :transaction => AuthorizeNet::Transaction.parse(response),
89
+ :customer_profile_id => AuthorizeNet::Util.getXmlValue(
90
+ response, "customerProfileId"),
91
+ :payment_profile_id => AuthorizeNet::Util.getXmlValue(
92
+ response, "customerPaymentProfileIdList numericString"),
93
+ }
94
+ end
95
+ end
96
+
97
+ # ===============================================================
98
+ # Charges the given profile and payment profile on Authorize.net
99
+ # @param Number amount
100
+ # @param String/Number customer_profile_id
101
+ # @param String/Number payment_profile_id
102
+ # @return transaction_id
103
+ # ===============================================================
104
+ def chargeProfile(amount, profile_id, payment_profile_id)
105
+ xml_obj = getXmlAuth
106
+ xml_obj["transactionRequest"] = {
107
+ "transactionType" => "authCaptureTransaction",
108
+ "amount" => amount,
109
+ "profile" => {
110
+ "customerProfileId" => profile_id,
111
+ "paymentProfile" => {
112
+ "paymentProfileId" => payment_profile_id,
113
+ },
114
+ },
115
+ }
116
+
117
+ response = sendRequest("createTransactionRequest", xml_obj)
118
+ if !response.nil?
119
+ return AuthorizeNet::Transaction.parse(response)
120
+ end
121
+ end
122
+
123
+ # ===============================================================
124
+ # Creates the given customer profile on Authorize.net
125
+ # @param AuthorizeNet::CustomerProfile customer_profile
126
+ # @param Number amount
127
+ # @param AuthorizeNet::ValidationMode validation_mode (optional)
128
+ # @return transaction_id
129
+ # ===============================================================
130
+ def createCustomerProfile(customer_profile, validation_mode=nil)
131
+ xml_obj = getXmlAuth
132
+ xml_obj["profile"] = customer_profile.to_h
133
+
134
+ addValidationMode!(xml_obj, validation_mode)
135
+ response = sendRequest("createCustomerProfileRequest", xml_obj)
136
+
137
+ if !response.nil?
138
+ return {
139
+ :customer_profile_id => AuthorizeNet::Util.getXmlValue(
140
+ response, "customerProfileId"),
141
+ :payment_profile_id => AuthorizeNet::Util.getXmlValue(
142
+ response, "customerPaymentProfileIdList numericString"),
143
+ }
144
+ end
145
+ end
146
+
147
+ # ===============================================================
148
+ # Create Customer Payment Profile
149
+ # @param String/Number customer_profile_id
150
+ # @param AuthorizeNet::PaymentProfile payment_profile
151
+ # @param AuthorizeNet::ValidationMode validation_mode (optional)
152
+ # @return {customer_profile_id, payment_profile_id}
153
+ # ===============================================================
154
+ def createPaymentProfile(customer_profile_id, payment_profile, validation_mode=nil)
155
+ xml_obj = getXmlAuth
156
+ xml_obj["customerProfileId"] = customer_profile_id
157
+ xml_obj["paymentProfile"] = payment_profile.to_h
158
+
159
+ addValidationMode!(xml_obj, validation_mode)
160
+ response = sendRequest("createCustomerPaymentProfileRequest", xml_obj)
161
+
162
+ if !response.nil?
163
+ return {
164
+ :customer_profile_id => AuthorizeNet::Util.getXmlValue(
165
+ response, "customerProfileId"),
166
+ :payment_profile_id => AuthorizeNet::Util.getXmlValue(
167
+ response, "customerPaymentProfileId"),
168
+ }
169
+ end
170
+ end
171
+
172
+ # ===============================================================
173
+ # Delete Customer Payment Profile
174
+ # @param String/Number customer_profile_id
175
+ # @param String/Number payment_profile_id
176
+ # @return boolean is delete successful?
177
+ # ===============================================================
178
+ def deletePaymentProfile(customer_profile_id, payment_profile_id)
179
+ xml_obj = getXmlAuth
180
+ xml_obj["customerProfileId"] = customer_profile_id
181
+ xml_obj["customerPaymentProfileId"] = payment_profile_id
182
+
183
+ response = sendRequest("deleteCustomerPaymentProfileRequest", xml_obj)
184
+ return !response.nil?
185
+ end
186
+
187
+ # ===============================================================
188
+ # Validate Customer Payment Profile
189
+ # @param String/Number customer_profile_id
190
+ # @param String/Number payment_profile_id
191
+ # @param AuthorizeNet::ValidationMode::(String) validation_mode
192
+ # @return boolean is update successful?
193
+ # ===============================================================
194
+ def validatePaymentProfile(customer_profile_id, payment_profile_id, validation_mode)
195
+ xml_obj = getXmlAuth
196
+ xml_obj["customerProfileId"] = customer_profile_id
197
+ xml_obj["customerPaymentProfileId"] = payment_profile_id
198
+ xml_obj["validationMode"] = validation_mode
199
+
200
+ response = sendRequest("validateCustomerPaymentProfileRequest", xml_obj)
201
+ return !response.nil?
202
+ end
203
+
204
+ # ===============================================================
205
+ # Get customer profile information
206
+ # @param String/Number customer_profile_id
207
+ # @param String/Number customer_profile_id
208
+ # @return AuthorizeNet::CustomerProfile
209
+ # ===============================================================
210
+ def getCustomerProfile(customer_profile_id)
211
+ xml_obj = getXmlAuth
212
+ xml_obj["customerProfileId"] = customer_profile_id
213
+
214
+ response = sendRequest("getCustomerProfileRequest", xml_obj)
215
+ if response
216
+ return AuthorizeNet::CustomerProfile.parse(response)
217
+ end
218
+ end
219
+
220
+ # ===============================================================
221
+ # Gets transaction information
222
+ # @param String/Number customer_profile_id
223
+ # @param String/Number transaction_id
224
+ # @return AuthorizeNet::Transaction
225
+ # ===============================================================
226
+ def getTransactionInfo(transaction_id)
227
+ xml_obj = getXmlAuth
228
+ xml_obj["transId"] = transaction_id
229
+
230
+ response = sendRequest("getTransactionDetailsRequest", xml_obj)
231
+ if response
232
+ return AuthorizeNet::Transaction.parse(response)
233
+ end
234
+ end
235
+
236
+
237
+
238
+ private
239
+
240
+ def getXmlAuth
241
+ return {
242
+ "merchantAuthentication" => {
243
+ "name" => @api_login_id,
244
+ "transactionKey" => @api_transaction_key,
245
+ }
246
+ }
247
+ end
248
+
249
+ def addValidationMode!(xml_obj, validation_mode)
250
+ if validation_mode
251
+ xml_obj["validationMode"] = validation_mode
252
+ end
253
+ end
254
+
255
+ # =============================================
256
+ # Looks for potential errors in the response
257
+ # and raises an error if it finds any
258
+ # Passes through OK responses
259
+ # @throws AuthorizeNet::Exception
260
+ # =============================================
261
+ def handleResponse(raw_response)
262
+ logHttpResponse(raw_response)
263
+
264
+ response = AuthorizeNet::Response.parseXml(raw_response.read_body)
265
+ if response.result == AuthorizeNet::RESULT_OK && response.errors.nil?
266
+ return response.parsed_xml
267
+ else
268
+ logErrorResponse(response)
269
+ AuthorizeNet::ErrorHandler.handle(response)
270
+ end
271
+ end
272
+
273
+ # =============================================
274
+ # Send HTTP request to Authorize Net
275
+ # @param Net::HTTPResponse
276
+ # @return response
277
+ # =============================================
278
+ def sendRequest(type, xml_obj)
279
+ uri = @is_test_api ? AuthorizeNet::TEST_URI : AuthorizeNet::URI
280
+ request = AuthorizeNet::Request.new(type, xml_obj, uri)
281
+
282
+ if @logger.respond_to? :info
283
+ @logger.info(request.toLog(@log_full_request))
284
+ end
285
+
286
+ return handleResponse(request.postRequest)
287
+ end
288
+
289
+ # =============================================
290
+ # Log HTTP response from Authorize Net
291
+ # @param Net::HTTPResponse
292
+ # @return String log
293
+ # =============================================
294
+ def logHttpResponse(response)
295
+ if @logger.respond_to? :logHttpResponse
296
+ @logger.logHttpResponse(response)
297
+ elsif @logger.respond_to? :info
298
+ @logger.info("[AuthorizeNet] HTTP Response code=#{response.code} message=#{response.message}")
299
+ end
300
+ end
301
+
302
+ # =============================================
303
+ # Returns a log string with http response data
304
+ # @param Net::HTTPResponse
305
+ # @throws RuntimeError
306
+ # =============================================
307
+ def logErrorResponse(response)
308
+ if @logger.respond_to? :info
309
+ @logger.info("[AuthorizeNet] Responded with resultCode=\"#{response.result}\"")
310
+ end
311
+
312
+ if !response.messages.nil? and @logger.respond_to? :info
313
+ response.messages.each do |msg|
314
+ @logger.info("[AuthorizeNet] Message code=\"#{msg[:code]}\" text=\"#{msg[:text]}\"")
315
+ end
316
+ end
317
+
318
+ if !response.errors.nil? and @logger.respond_to? :error
319
+ response.errors.each do |error|
320
+ @logger.error("[AuthorizeNet] Error code=\"#{error[:code]}\" text=\"#{error[:text]}\"")
321
+ end
322
+ end
323
+ end
324
+
325
+ end
@@ -0,0 +1,16 @@
1
+ require 'authorize_net/data_object'
2
+
3
+ class AuthorizeNet::CreditCard < AuthorizeNet::DataObject
4
+
5
+ ATTRIBUTES = {
6
+ :card_num => {:key => "cardNumber"},
7
+ :expiration => {:key => "expirationDate"},
8
+ :security_code => {:key => "cardCode"},
9
+ :card_type => {:key => "cardType"},
10
+ }
11
+
12
+ self::ATTRIBUTES.keys.each do |attr|
13
+ attr_accessor attr
14
+ end
15
+
16
+ end
@@ -0,0 +1,26 @@
1
+ require 'authorize_net/data_object'
2
+ require 'authorize_net/payment_profile'
3
+
4
+ class AuthorizeNet::CustomerProfile < AuthorizeNet::DataObject
5
+
6
+ ATTRIBUTES = {
7
+ :id => {:key => "customerProfileId"},
8
+ :merchant_id => {:key => "merchantCustomerId"},
9
+ :email => nil,
10
+ :description => nil,
11
+ :payment_profiles => {
12
+ :key => "paymentProfiles",
13
+ :type => AuthorizeNet::DataObject::TYPE_OBJECT_ARRAY,
14
+ :class => AuthorizeNet::PaymentProfile,
15
+ },
16
+ }
17
+
18
+ self::ATTRIBUTES.keys.each do |attr|
19
+ attr_accessor attr
20
+ end
21
+
22
+ def initialize
23
+ @payment_profiles = []
24
+ end
25
+
26
+ end
@@ -0,0 +1,123 @@
1
+ # *** NOTE ***
2
+ # Data objects must have a static ATTRIBUTES hash followed by these lines
3
+ #
4
+ # self::ATTRIBUTES.keys.each do |attr|
5
+ # attr_accessor attr
6
+ # end
7
+ #
8
+ class AuthorizeNet::DataObject
9
+
10
+ TYPE_ARRAY = :type_array
11
+ TYPE_OBJECT = :type_object
12
+ TYPE_OBJECT_ARRAY = :type_object_array
13
+
14
+ # =======================================================
15
+ # Parses XML from the values in the ATTRIBUTES hash in
16
+ # to the attributes of this object.
17
+ # =======================================================
18
+ def parse(xml)
19
+ if xml.nil? || !xml.respond_to?(:at_css)
20
+ return
21
+ end
22
+
23
+ self.class::ATTRIBUTES.keys.each do |attr|
24
+ spec = self.class::ATTRIBUTES[attr].to_h
25
+ xml_key = spec[:key] || attr.to_s
26
+ type = spec[:type]
27
+ type_class = spec[:class]
28
+
29
+ if (type == TYPE_OBJECT or type == TYPE_OBJECT_ARRAY) and type_class.nil?
30
+ raise "DataObject=#{self.class} Attribute=#{attr} of type #{type} must specify a class"
31
+ end
32
+
33
+ if type == TYPE_OBJECT
34
+ obj_xml = xml.at_css(xml_key)
35
+ send("#{attr}=", type_class.parse(obj_xml))
36
+
37
+ elsif type == TYPE_OBJECT_ARRAY
38
+ array_xml = xml.css(xml_key)
39
+ send("#{attr}=", array_xml.map{ |x| type_class.parse(x) })
40
+
41
+ elsif type == TYPE_ARRAY
42
+ array_xml = xml.css(xml_key)
43
+ send("#{attr}=", array_xml.map{ |x| x.inner_text })
44
+
45
+ else
46
+ send("#{attr}=", AuthorizeNet::Util.getXmlValue(xml, xml_key))
47
+ end
48
+ end
49
+ end
50
+
51
+ # =======================================================
52
+ # Turns this object into a hash using the keys specified
53
+ # as the values in ATTRIBUTES
54
+ #
55
+ # If the value in ATTRIBUTES is nil, use the String
56
+ # version of the attribute itself
57
+ # =======================================================
58
+ def to_h(include_blanks=false)
59
+ hash = {}
60
+ self.class::ATTRIBUTES.keys.each do |attr|
61
+ spec = self.class::ATTRIBUTES[attr].to_h
62
+ key = spec[:key] || attr.to_s
63
+ type = spec[:type]
64
+ value = send(attr)
65
+
66
+ if value.nil?
67
+ if include_blanks
68
+ hash[key] = nil
69
+ end
70
+ elsif type == TYPE_OBJECT
71
+ hash[key] = value.to_h
72
+ elsif type == TYPE_OBJECT_ARRAY
73
+ hash[key] = value.map{ |e| e.to_h }
74
+ else
75
+ hash[key] = value
76
+ end
77
+ end
78
+
79
+ return hash
80
+ end
81
+
82
+ # =======================================================
83
+ # Turns this object into a hash using the keys specified
84
+ # as the keys in ATTRIBUTES
85
+ # =======================================================
86
+ def serialize
87
+ hash = {}
88
+ self.class::ATTRIBUTES.keys.each do |attr|
89
+ spec = self.class::ATTRIBUTES[attr].to_h
90
+ type = spec[:type]
91
+ value = send(attr)
92
+
93
+ if value.nil?
94
+ hash[attr] = nil
95
+ elsif type == TYPE_OBJECT
96
+ hash[attr] = value.serialize
97
+ elsif type == TYPE_OBJECT_ARRAY
98
+ hash[attr] = value.map{ |e| e.serialize }
99
+ else
100
+ hash[attr] = value
101
+ end
102
+ end
103
+
104
+ return hash
105
+ end
106
+
107
+
108
+ class << self
109
+ # =============================================
110
+ # Parses xml into a new instance of this class
111
+ # =============================================
112
+ def parse(xml)
113
+ if xml.nil? || !xml.respond_to?(:at_css)
114
+ return
115
+ end
116
+
117
+ object = new
118
+ object.parse(xml)
119
+ return object
120
+ end
121
+ end
122
+
123
+ end
@@ -0,0 +1,137 @@
1
+
2
+ class AuthorizeNet::ErrorHandler
3
+ class << self
4
+ ERROR_FIELD_REGEXES = [
5
+ /'AnetApi\/xml\/v1\/schema\/AnetApiSchema\.xsd:([a-zA-Z]*)'/,
6
+ /The element '([a-zA-Z]*)' in namespace 'AnetApi\/xml\/v1\/schema\/AnetApiSchema.xsd'/
7
+ ]
8
+
9
+ MESSAGE_CODES = {
10
+ "E00003" => :invalid_field,
11
+ "E00015" => :invalid_field_length,
12
+ "E00027" => :missing_required_field,
13
+ "E00039" => :duplicate_record_exists,
14
+ "E00041" => :customer_profile_info_required,
15
+ }
16
+
17
+ ERROR_CODES = {
18
+ "210" => :transaction_declined,
19
+ "6" => :invalid_card_number,
20
+ "7" => :invalid_expiration_date,
21
+ "8" => :expired_credit_card,
22
+ }
23
+
24
+ ERROR_FIELDS = {
25
+ :invalid_card_number => :card_number,
26
+ :invalid_expiration_date => :card_expiration,
27
+ :expired_credit_card => :card_expiration,
28
+
29
+ "cardNumber" => :card_number,
30
+ "expirationDate" => :card_expiration,
31
+ "cardCode" => :card_security_code,
32
+ }
33
+
34
+ # =============================================
35
+ # Creates an exception, populates it as well
36
+ # as possible, and then raises it
37
+ # @param AuthorizeNet::Response
38
+ # @throws AuthorizeNet::Exception
39
+ # =============================================
40
+ def handle(response)
41
+ exception = AuthorizeNet::Exception.new
42
+
43
+ if !response.errors.nil?
44
+ first_error = response.errors.first
45
+ exception.message = first_error[:text]
46
+
47
+ # Add errors to exception
48
+ response.errors.each do |error|
49
+ exception.errors << buildError(error)
50
+ end
51
+
52
+ raise exception
53
+
54
+ # If there are no errors, then the "messages" are probably errors... *sigh*
55
+ elsif !response.messages.nil? and response.result == AuthorizeNet::RESULT_ERROR
56
+ first_msg = response.messages.first
57
+ exception.message = first_msg[:text]
58
+
59
+ # Add messages (that are sometimes actually errors) to exception
60
+ response.messages.each do |msg|
61
+ exception.errors << buildError(msg)
62
+ end
63
+
64
+ raise exception
65
+ end
66
+
67
+ end
68
+
69
+ # =============================================
70
+ # Attempts to determine the error type and field
71
+ # for an error hash
72
+ # @param Hash error
73
+ # @return Hash error
74
+ # =============================================
75
+ def buildError(error)
76
+ code = error[:code]
77
+ text = error[:text]
78
+ type = getTypeFromCode(code)
79
+ field = nil
80
+
81
+ if !type.nil? and ERROR_FIELDS.has_key? type
82
+ field = ERROR_FIELDS[type]
83
+ else
84
+ field = getFieldFromText(text)
85
+ end
86
+
87
+ return {
88
+ :code => code,
89
+ :text => text,
90
+ :type => type,
91
+ :field => field,
92
+ }
93
+ end
94
+
95
+ # =============================================
96
+ # Attempts to determine the error type given
97
+ # an error code
98
+ # @param String code
99
+ # @return Symbol|nil type
100
+ # =============================================
101
+ def getTypeFromCode(code)
102
+ if ERROR_CODES.has_key? code
103
+ return ERROR_CODES[code]
104
+ elsif MESSAGE_CODES.has_key? code
105
+ return MESSAGE_CODES[code]
106
+ end
107
+ return nil
108
+ end
109
+
110
+ # =============================================
111
+ # Attempts to determine the error field given
112
+ # an error message
113
+ # @param String text
114
+ # @return Symbol|nil field
115
+ # =============================================
116
+ def getFieldFromText(text)
117
+ if text.nil?
118
+ return nil
119
+ end
120
+
121
+ ERROR_FIELD_REGEXES.each do |regex|
122
+ field_match = text.match(regex)
123
+ if !field_match.nil?
124
+ field = field_match[1]
125
+
126
+ if ERROR_FIELDS.keys.include? field
127
+ return ERROR_FIELDS[field]
128
+ end
129
+ return field
130
+ end
131
+ end
132
+
133
+ return nil
134
+ end
135
+
136
+ end
137
+ end
@@ -0,0 +1,13 @@
1
+ class AuthorizeNet::Exception < Exception
2
+
3
+ GENERIC_ERROR_MESSAGE = "[AuthorizeNet] The Authorize.Net API returned an error"
4
+
5
+ attr_accessor :message
6
+ attr_accessor :errors
7
+
8
+ def initialize
9
+ @message = GENERIC_ERROR_MESSAGE
10
+ @errors = []
11
+ end
12
+
13
+ end
@@ -0,0 +1,39 @@
1
+ require 'authorize_net/data_object'
2
+ require 'authorize_net/credit_card'
3
+ require 'authorize_net/address'
4
+
5
+ class AuthorizeNet::PaymentProfile < AuthorizeNet::DataObject
6
+
7
+ ATTRIBUTES = {
8
+ :id => {:key => "customerPaymentProfileId"},
9
+ :credit_card => {
10
+ :key => "creditCard",
11
+ :type => AuthorizeNet::DataObject::TYPE_OBJECT,
12
+ :class => AuthorizeNet::CreditCard,
13
+ },
14
+ :billing_address => {
15
+ :key => "billTo",
16
+ :type => AuthorizeNet::DataObject::TYPE_OBJECT,
17
+ :class => AuthorizeNet::Address,
18
+ },
19
+ }
20
+
21
+ self::ATTRIBUTES.keys.each do |attr|
22
+ attr_accessor attr
23
+ end
24
+
25
+ # Override
26
+ def to_h
27
+ hash = super
28
+
29
+ hash.delete('creditCard')
30
+ if !@credit_card.nil?
31
+ hash['payment'] = {
32
+ 'creditCard' => @credit_card.to_h
33
+ }
34
+ end
35
+
36
+ return hash
37
+ end
38
+
39
+ end
@@ -0,0 +1,93 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+
4
+ # ===============================================================
5
+ # This class represents a request to the Authorize.Net API
6
+ #
7
+ # Add any logic that applies to ALL requests here
8
+ # ===============================================================
9
+ class AuthorizeNet::Request
10
+
11
+ attr_accessor :response
12
+
13
+ def initialize(type, data, uri)
14
+ @xml_data = data
15
+ @request_type = type
16
+ @uri = URI(uri)
17
+ @response = nil
18
+ end
19
+
20
+ # =============================================
21
+ # Uses the given data to make a POST request
22
+ # =============================================
23
+ def postRequest
24
+ assertRequestData
25
+ assertRequestType
26
+ req = Net::HTTP::Post.new(@uri.request_uri)
27
+ req.add_field('Content-Type', 'text/xml')
28
+ req.body = buildXmlRequest
29
+ @response = sendRequest(req)
30
+ return @response
31
+ end
32
+
33
+ # =============================================
34
+ # Uses the given data to make a GET request
35
+ # =============================================
36
+ def getRequest
37
+ assertRequestType
38
+ req = Net::HTTP::Get.new(@uri.request_uri)
39
+ req.add_field('Content-Type', 'text/xml')
40
+ req.body = buildXmlRequest
41
+ end
42
+
43
+ # =============================================
44
+ # Make a log string for this request
45
+ # =============================================
46
+ def toLog(log_body)
47
+ log = "[AuthorizeNet] HTTP Request type=#{@request_type} uri=#{@uri}"
48
+
49
+ if log_body
50
+ log += " body=\"#{buildXmlRequest}\""
51
+ end
52
+
53
+ return log
54
+ end
55
+
56
+
57
+ private
58
+
59
+ def assertRequestData
60
+ if @xml_data.nil?
61
+ raise "AuthorizeRequest has no xml data"
62
+ end
63
+ end
64
+
65
+ def assertRequestType
66
+ if @request_type.nil?
67
+ raise "AuthorizeRequest has no request type"
68
+ end
69
+ end
70
+
71
+ # =============================================
72
+ # Builds the full XML request using request
73
+ # type and the xml data object
74
+ # =============================================
75
+ def buildXmlRequest
76
+ xml_string = AuthorizeNet::XML_HEADER
77
+ xml_string += "<#{@request_type} xmlns=\"#{AuthorizeNet::XML_SCHEMA}\">"
78
+ xml_string += AuthorizeNet::Util.buildXmlFromObject(@xml_data)
79
+ xml_string += "</#{@request_type}>"
80
+ return xml_string
81
+ end
82
+
83
+ # =============================================
84
+ # Sends the input request to Authorize.Net
85
+ # =============================================
86
+ def sendRequest(req)
87
+ http = Net::HTTP.start(@uri.host, @uri.port, :use_ssl => @uri.scheme == 'https')
88
+ @response = http.request(req)
89
+ return @response
90
+ end
91
+
92
+
93
+ end
@@ -0,0 +1,50 @@
1
+ require 'nokogiri'
2
+
3
+ class AuthorizeNet::Response
4
+
5
+ attr_accessor :result
6
+ attr_accessor :errors
7
+ attr_accessor :messages
8
+ attr_accessor :raw_xml
9
+ attr_accessor :parsed_xml
10
+
11
+ class << self
12
+
13
+ # =============================================
14
+ # Returns a populated response object
15
+ # @param String xml
16
+ # @return AuthorizeNet::Response
17
+ # =============================================
18
+ def parseXml(xml)
19
+ response = new
20
+ response.raw_xml = xml
21
+ response.parsed_xml = Nokogiri::XML.parse(xml)
22
+ response.result = AuthorizeNet::Util.getXmlValue(response.parsed_xml, "resultCode")
23
+
24
+ errors = response.parsed_xml.at_css("errors")
25
+ if !errors.nil?
26
+ response.errors = []
27
+ errors.css("error").each do |xml_error|
28
+ response.errors << {
29
+ :code => AuthorizeNet::Util.getXmlValue(xml_error, "errorCode"),
30
+ :text => AuthorizeNet::Util.getXmlValue(xml_error, "errorText"),
31
+ }
32
+ end
33
+ end
34
+
35
+ messages = response.parsed_xml.at_css("messages")
36
+ if !messages.nil?
37
+ response.messages = []
38
+ messages.css("message").each do |xml_msg|
39
+ response.messages << {
40
+ :code => AuthorizeNet::Util.getXmlValue(xml_msg, "code"),
41
+ :text => AuthorizeNet::Util.getXmlValue(xml_msg, "text"),
42
+ }
43
+ end
44
+ end
45
+
46
+ return response
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,45 @@
1
+ require 'authorize_net/data_object'
2
+ require 'authorize_net/address'
3
+ require 'authorize_net/customer_profile'
4
+ require 'authorize_net/credit_card'
5
+ require 'authorize_net/util'
6
+
7
+ class AuthorizeNet::Transaction < AuthorizeNet::DataObject
8
+
9
+ ATTRIBUTES = {
10
+ :id => {:key => "transId"},
11
+ :timestamp_local => {:key => "submitTimeLocal"},
12
+ :timestamp_utc => {:key => "submitTimeUTC"},
13
+ :type => {:key => "transactionType"},
14
+ :status => {:key => "transactionStatus"},
15
+ :account_num => {:key => "accountNumber"},
16
+ :account_type => {:key => "accountType"},
17
+ :auth_code => {:key => "authCode"},
18
+ :credit_card => {
19
+ :key => "creditCard",
20
+ :type => AuthorizeNet::DataObject::TYPE_OBJECT,
21
+ :class => AuthorizeNet::CreditCard,
22
+ },
23
+ :customer_profile => {
24
+ :key => "customer",
25
+ :type => AuthorizeNet::DataObject::TYPE_OBJECT,
26
+ :class => AuthorizeNet::CustomerProfile,
27
+ },
28
+ :billing_address => {
29
+ :key => "billTo",
30
+ :type => AuthorizeNet::DataObject::TYPE_OBJECT,
31
+ :class => AuthorizeNet::Address,
32
+ },
33
+ }
34
+
35
+ self::ATTRIBUTES.keys.each do |attr|
36
+ attr_accessor attr
37
+ end
38
+
39
+ def parse(xml)
40
+ super
41
+
42
+ @customer_profile.merchant_id = AuthorizeNet::Util.getXmlValue(xml, 'customer id')
43
+ end
44
+
45
+ end
@@ -0,0 +1,55 @@
1
+ class AuthorizeNet::Util
2
+
3
+ class << self
4
+ # ==============================================
5
+ # A wrapper for safely getting the inner value
6
+ # of an XML attribute only if it exists
7
+ #
8
+ # If multiple instances exist, return the first one
9
+ # ==============================================
10
+ def getXmlValue(xml, attr_string)
11
+ if !xml.respond_to? :at_css || attr_string.nil?
12
+ return nil
13
+ end
14
+
15
+ attr = xml.at_css(attr_string)
16
+ if !attr.nil?
17
+ return attr.inner_text
18
+ end
19
+ end
20
+
21
+ # ==============================================
22
+ # Builds XML from Ruby Hashes/Arrays/Primitives
23
+ # ==============================================
24
+ def buildXmlFromObject(obj, parent_tag=nil)
25
+ xml = ""
26
+ has_parent = !parent_tag.nil?
27
+
28
+ # Arrays are formatted with the parent tag
29
+ # wrapping each of the array elements for some
30
+ # reason
31
+ if obj.is_a? Array
32
+ obj.each do |e|
33
+ xml += has_parent ? "<#{parent_tag}>" : ""
34
+ xml += buildXmlFromObject(e)
35
+ xml += has_parent ? "</#{parent_tag}>" : ""
36
+ end
37
+
38
+ elsif obj.is_a? Hash
39
+ xml += has_parent ? "<#{parent_tag}>" : ""
40
+ obj.keys.each do |key|
41
+ xml += buildXmlFromObject(obj[key], key.to_s)
42
+ end
43
+ xml += has_parent ? "</#{parent_tag}>" : ""
44
+
45
+ elsif !obj.nil?
46
+ xml += has_parent ? "<#{parent_tag}>" : ""
47
+ xml += obj.to_s
48
+ xml += has_parent ? "</#{parent_tag}>" : ""
49
+ end
50
+
51
+ return xml
52
+ end
53
+ end
54
+
55
+ end
@@ -0,0 +1,30 @@
1
+ module AuthorizeNet
2
+ URI = "https://api.authorize.net/xml/v1/request.api"
3
+ TEST_URI = "https://apitest.authorize.net/xml/v1/request.api"
4
+ XML_SCHEMA = "AnetApi/xml/v1/schema/AnetApiSchema.xsd"
5
+ XML_HEADER = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
6
+ RESULT_OK = "Ok"
7
+ RESULT_ERROR = "Error"
8
+
9
+ # ===============================================================
10
+ # Constants for types of authorize net credit card validation
11
+ #
12
+ # Live Mode - Executes a test charge on the credit card for $0.01
13
+ # that is immediately voided
14
+ # Test Mode - Does basic mathematical checks on card validity
15
+ # None - No validation, could be useful for integration tests?
16
+ # ===============================================================
17
+ module ValidationMode
18
+ LIVE = "liveMode"
19
+ TEST = "testMode"
20
+ NONE = "None"
21
+ end
22
+ end
23
+
24
+ # require all authorize-net files
25
+ Dir['lib/authorize_net/**/*.rb'].each do |filename|
26
+ match = filename.match(/lib\/(authorize_net\/.*).rb/)
27
+ if !match.nil?
28
+ require match[1]
29
+ end
30
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: authorize_net
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Avenir Interactive LLC
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.6.7.2
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.6.7.2
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - '='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.6.7.2
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.6.7.2
33
+ description: A RubyGem that interfaces with the Authorize.net payment gateway
34
+ email:
35
+ - info@avenirhq.com
36
+ executables: []
37
+ extensions: []
38
+ extra_rdoc_files: []
39
+ files:
40
+ - lib/authorize_net.rb
41
+ - lib/authorize_net/address.rb
42
+ - lib/authorize_net/api.rb
43
+ - lib/authorize_net/credit_card.rb
44
+ - lib/authorize_net/customer_profile.rb
45
+ - lib/authorize_net/data_object.rb
46
+ - lib/authorize_net/error_handler.rb
47
+ - lib/authorize_net/exception.rb
48
+ - lib/authorize_net/payment_profile.rb
49
+ - lib/authorize_net/request.rb
50
+ - lib/authorize_net/response.rb
51
+ - lib/authorize_net/transaction.rb
52
+ - lib/authorize_net/util.rb
53
+ homepage: https://github.com/AvenirHQ/authorize_net
54
+ licenses:
55
+ - MIT
56
+ metadata: {}
57
+ post_install_message:
58
+ rdoc_options: []
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ requirements: []
72
+ rubyforge_project:
73
+ rubygems_version: 2.5.2
74
+ signing_key:
75
+ specification_version: 4
76
+ summary: API interface for Authorize.net payment gateway
77
+ test_files: []
78
+ has_rdoc: