authorize_net 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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: