authorizenet 1.8.1 → 1.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/lib/authorize_net.rb +5 -0
  3. data/lib/authorize_net.rb~ +95 -0
  4. data/lib/authorize_net/aim/response.rb~ +131 -0
  5. data/lib/authorize_net/arb/fields.rb +24 -0
  6. data/lib/authorize_net/arb/fields.rb~ +13 -0
  7. data/lib/authorize_net/arb/paging.rb +33 -0
  8. data/lib/authorize_net/arb/paging.rb~ +25 -0
  9. data/lib/authorize_net/arb/response.rb~ +68 -0
  10. data/lib/authorize_net/arb/sorting.rb +43 -0
  11. data/lib/authorize_net/arb/sorting.rb~ +43 -0
  12. data/lib/authorize_net/arb/subscription.rb +5 -5
  13. data/lib/authorize_net/arb/subscription_detail.rb +14 -0
  14. data/lib/authorize_net/arb/subscription_detail.rb~ +56 -0
  15. data/lib/authorize_net/arb/subscription_list_response.rb +43 -0
  16. data/lib/authorize_net/arb/subscription_list_response.rb~ +45 -0
  17. data/lib/authorize_net/arb/transaction.rb +35 -4
  18. data/lib/authorize_net/arb/transaction.rb~ +176 -0
  19. data/lib/authorize_net/fields.rb +21 -3
  20. data/lib/authorize_net/fields.rb~ +767 -0
  21. data/lib/authorize_net/key_value_transaction.rb +0 -2
  22. data/lib/authorize_net/payment_methods/credit_card.rb +20 -32
  23. data/lib/authorize_net/xml_response.rb~ +173 -0
  24. data/lib/authorize_net/xml_transaction.rb +5 -5
  25. data/lib/authorize_net/xml_transaction.rb~ +276 -0
  26. data/lib/generators/authorize_net/{direct_post_generator.rb → direct_post/direct_post_generator.rb} +4 -2
  27. data/lib/generators/authorize_net/direct_post/templates/README-AuthorizeNet +49 -0
  28. data/lib/generators/authorize_net/direct_post/templates/config.yml.erb +8 -0
  29. data/lib/generators/authorize_net/direct_post/templates/config.yml.rails3.erb +8 -0
  30. data/lib/generators/authorize_net/direct_post/templates/controller.rb.erb +31 -0
  31. data/lib/generators/authorize_net/direct_post/templates/initializer.rb +4 -0
  32. data/lib/generators/authorize_net/direct_post/templates/layout.erb +18 -0
  33. data/lib/generators/authorize_net/direct_post/templates/payment.erb +10 -0
  34. data/lib/generators/authorize_net/direct_post/templates/payment.rails3.erb +10 -0
  35. data/lib/generators/authorize_net/direct_post/templates/receipt.erb +1 -0
  36. data/lib/generators/authorize_net/direct_post/templates/relay_response.erb +1 -0
  37. data/lib/generators/authorize_net/{sim_generator.rb → sim/sim_generator.rb} +2 -2
  38. data/lib/generators/authorize_net/sim/templates/README-AuthorizeNet +52 -0
  39. data/lib/generators/authorize_net/sim/templates/config.yml.erb +8 -0
  40. data/lib/generators/authorize_net/sim/templates/config.yml.rails3.erb +8 -0
  41. data/lib/generators/authorize_net/sim/templates/controller.rb.erb +21 -0
  42. data/lib/generators/authorize_net/sim/templates/initializer.rb +4 -0
  43. data/lib/generators/authorize_net/sim/templates/layout.erb +18 -0
  44. data/lib/generators/authorize_net/sim/templates/payment.erb +6 -0
  45. data/lib/generators/authorize_net/sim/templates/payment.rails3.erb +6 -0
  46. data/lib/generators/authorize_net/sim/templates/thank_you.erb +1 -0
  47. data/lib/generators/generator_extensions.rb +75 -0
  48. metadata +41 -10
@@ -8,10 +8,8 @@ module AuthorizeNet
8
8
  module Gateway
9
9
  LIVE = 'https://secure.authorize.net/gateway/transact.dll'
10
10
  TEST = 'https://test.authorize.net/gateway/transact.dll'
11
- #TEST = 'https://qagreta1d.qa.intra/gateway/transact.dll'
12
11
  CARD_PRESENT_LIVE = 'https://cardpresent.authorize.net/gateway/transact.dll'
13
12
  CARD_PRESENT_TEST = 'https://test.authorize.net/gateway/transact.dll'
14
- #CARD_PRESENT_TEST = 'https://qagreta1d.qa.intra/gateway/transact.dll'
15
13
  end
16
14
 
17
15
  # Constants for both the various Authorize.Net payment transaction types are defined here.
@@ -1,41 +1,41 @@
1
1
  module AuthorizeNet
2
-
2
+
3
3
  # Defines constants for each payment method type.
4
4
  module PaymentMethodType
5
5
  CREDIT_CARD = 'CC'
6
6
  end
7
-
7
+
8
8
  # Models a credit card.
9
9
  class CreditCard
10
10
  PAYMENT_METHOD_CODE = AuthorizeNet::PaymentMethodType::CREDIT_CARD
11
-
11
+
12
12
  # The option defaults for the constructor.
13
13
  @@option_defaults = {
14
14
  :card_code => nil,
15
15
  :card_type => nil
16
16
  }
17
-
17
+
18
18
  attr_accessor :card_number, :expiration, :card_code, :card_type, :track_1, :track_2
19
-
19
+
20
20
  # Constructs a new credit card object. Takes a credit card number
21
21
  # and an expiration date. The CCV code can be passed as an option. So can
22
22
  # the data tracks (1 & 2). When passing in data tracks, please pass the
23
23
  # whole track. Sentinels and the LRC will be removed by the SDK. Track data
24
24
  # must be passed along as ASCII. The raw bit stream from the card is not acceptable.
25
- #
25
+ #
26
26
  # Field separators on
27
- #
27
+ #
28
28
  # +card_number+:: The credit card number as a string.
29
29
  # +expiration+:: The credit card expiration date as a string with format MMYY.
30
30
  # +options+:: A hash of options.
31
- #
31
+ #
32
32
  # Options
33
33
  # +card_code+:: Sets the CCV code for the credit card.
34
34
  # +card_type+:: Sets the type of card (Visa, MasterCard, Dinners Club, etc.)
35
35
  # +track_1+:: Sets the track 1 data. Either track 1 or track 2 data needs to be included for card present transactions (otherwise fee structure will change).
36
36
  # +track_2+:: Sets the track 2 data. Either track 1 or track 2 data needs to be included for card present transactions (otherwise fee structure will change).
37
37
  #
38
- #
38
+ #
39
39
  def initialize(card_number, expiration, options = {})
40
40
  @card_number = card_number
41
41
  @expiration = expiration
@@ -45,30 +45,18 @@ module AuthorizeNet
45
45
  @track_1 = options[:track_1]
46
46
  @track_2 = options[:track_2]
47
47
  end
48
-
48
+
49
49
  def to_hash
50
- hash = {
51
- :method => PAYMENT_METHOD_CODE,
52
- :card_num => @card_number,
53
- :exp_date => @expiration
54
- }
55
- hash[:card_code] = @card_code unless @card_code.nil?
56
- unless @track_1.nil?
57
- track_1 = @track_1
58
- if track_1[0..0] == '%'
59
- track_1 = track_1[1..(@track_1.rindex('?') - 1)]
60
- end
61
- hash[:track1] = track_1
62
- end
63
- unless @track_2.nil?
64
- track_2 = @track_2
65
- if track_2[0..0] == ';'
66
- track_2 = track_2[1..(@track_2.rindex('?') - 1)]
67
- end
68
- hash[:track2] = track_2
50
+ Hash.new.tap do |ch|
51
+ ch[:method] = PAYMENT_METHOD_CODE
52
+ ch[:card_num] = @card_number
53
+ ch[:exp_date] = @expiration
54
+ ch[:card_code] = @card_code if @card_code
55
+ ch[:track1] = @track_1.match(/(%|^)(.*?)(\?|$)/)[2] if @track_1
56
+ ch[:track2] = @track_2.match(/(;|^)(.*?)(\?|$)/)[2] if @track_2
57
+ #ch[:track1] = @track_1.match(/^%(?<fc>.)(?<p>[\d]{1,19}+)\^(?<n>.{2,26})\^(?<e>[\d]{0,4}|\^)(?<sc>[\d]{0,3}|\^)(?<dd>.*)\?\Z/) if @track_1
58
+ #ch[:track2] = @track_2.match(/\A;(?<pan>[\d]{1,19}+)=(?<expiration>[\d]{0,4}|=)(?<service_code>[\d]{0,3}|=)(?<discretionary_data>.*)\?\Z/) if @track_2
69
59
  end
70
- hash
71
60
  end
72
-
73
61
  end
74
- end
62
+ end
@@ -0,0 +1,173 @@
1
+ module AuthorizeNet
2
+
3
+ # The core, xml response class. You shouldn't instantiate this one.
4
+ # Instead you should use AuthorizeNet::ARB::Response.
5
+ class XmlResponse < AuthorizeNet::Response
6
+
7
+ # DO NOT USE. Instantiate AuthorizeNet::ARB::Response or AuthorizeNet::CIM::Response instead.
8
+ def initialize(raw_response, transaction)
9
+ @raw_response = raw_response
10
+ @transaction = transaction
11
+ unless connection_failure?
12
+ begin
13
+ xml = Nokogiri::XML(@raw_response.body) do |config|
14
+ # confirm noent is the right flag
15
+ config.recover.noent.nonet
16
+ end
17
+ @root = xml.children[0]
18
+ @result_code = node_content_unless_nil(@root.at_css('messages resultCode'))
19
+ @message_code = node_content_unless_nil(@root.at_css('messages message code'))
20
+ @message_text = node_content_unless_nil(@root.at_css('messages message text'))
21
+ @reference_id = node_content_unless_nil(@root.at_css('refId'))
22
+ rescue
23
+ @raw_response = $!
24
+ end
25
+ end
26
+ end
27
+
28
+ # Check to see if the response indicated success. Success is defined as a 200 OK response with a resultCode
29
+ # of 'Ok'.
30
+ def success?
31
+ puts "there"
32
+ !connection_failure? && @result_code == 'Ok'
33
+ end
34
+
35
+ # Returns true if we failed to open a connection to the gateway or got back a non-200 OK HTTP response.
36
+ def connection_failure?
37
+ !@raw_response.kind_of?(Net::HTTPOK)
38
+ end
39
+
40
+ # Returns the underlying Net::HTTPResponse object. This has the original response body along with
41
+ # headers and such. Note that if an exception is generated while making the request (which happens
42
+ # if there is no internet connection for example), you will get the exception object here instead of
43
+ # a Net::HTTPResponse object.
44
+ def raw
45
+ @raw_response
46
+ end
47
+
48
+ # Returns a deep-copy of the XML object received from the payment gateway. Or nil if there was no XML payload.
49
+ def xml
50
+ @root.dup unless @root.nil?
51
+ end
52
+
53
+ # Returns the resultCode from the XML response. resultCode will be either 'Ok' or 'Error'.
54
+ def result_code
55
+ @result_code
56
+ end
57
+
58
+ # Returns the messageCode from the XML response. This is a code indicating the details of an error
59
+ # or success.
60
+ def message_code
61
+ @message_code
62
+ end
63
+
64
+ # Returns the messageText from the XML response. This is a text description of the message_code.
65
+ def message_text
66
+ @message_text
67
+ end
68
+
69
+ # Alias for result_code.
70
+ def response_code
71
+ result_code
72
+ end
73
+
74
+ # Alias for message_code.
75
+ def response_reason_code
76
+ message_code
77
+ end
78
+
79
+ # Alias for message_text.
80
+ def response_reason_text
81
+ message_text
82
+ end
83
+
84
+ # Returns the refId from the response if there is one. Otherwise returns nil.
85
+ def reference_id
86
+ @reference_id
87
+ end
88
+
89
+ #:enddoc:
90
+ protected
91
+
92
+ def node_content_unless_nil(node)
93
+ if node.nil?
94
+ nil
95
+ else
96
+ node.content
97
+ end
98
+ end
99
+
100
+ def node_child_content_unless_nil(node)
101
+ if node.nil?
102
+ nil
103
+ else
104
+ if node.children.length > 0
105
+ node.children.collect(&:content)
106
+ else
107
+ nil
108
+ end
109
+ end
110
+ end
111
+
112
+ # Transforms a block of XML into a model Object defined by entity_desc.
113
+ def build_entity(xml, entity_desc)
114
+ args = {}
115
+ entity_desc.node_structure.each do |node_desc|
116
+ node_name = (node_desc.keys.reject {|k| k.to_s[0..0] == '_' }).first
117
+ args.merge!(handle_node_type(xml, node_desc, node_name, args, ''))
118
+ end
119
+
120
+ if args.length == 0
121
+ return nil
122
+ end
123
+
124
+ if entity_desc.arg_mapping.nil?
125
+ return entity_desc.entity_class.new(args)
126
+ else
127
+ args_list = []
128
+ entity_desc.arg_mapping.each do |arg|
129
+ args_list <<= args[arg]
130
+ args.delete(arg)
131
+ end
132
+ args_list <<= args
133
+ return entity_desc.entity_class.new(*args_list)
134
+ end
135
+ end
136
+
137
+ # Parses an XML fragment into an internal representation.
138
+ def handle_node_type(xml, node_desc, node_name, args, base_name)
139
+ case node_desc[node_name]
140
+ when Symbol
141
+ node = xml.at_css(base_name + node_name.to_s)
142
+ unless node.nil?
143
+ content = node.content
144
+ case node_desc[:_converter]
145
+ when Method, Proc
146
+ content = node_desc[:_converter].call(content)
147
+ when Symbol
148
+ content = self.send(node_desc[:_converter], content)
149
+ end
150
+ args[node_desc[node_name]] = content unless content.nil?
151
+ end
152
+ when AuthorizeNet::EntityDescription
153
+ unless node_desc[:_multivalue].nil?
154
+ xml.css(base_name + node_name.to_s).each do |node|
155
+ entity = build_entity(node, node_desc[node_name])
156
+ args[node_desc[:_multivalue]] = args[node_desc[:_multivalue]].to_a + entity.to_a unless entity.nil?
157
+ end
158
+ else
159
+ entity = build_entity(xml.css(base_name + node_name.to_s), node_desc[node_name])
160
+ args[node_desc[:_value]] = entity unless entity.nil?
161
+ end
162
+ when Array
163
+ node_desc[node_name].each do |inner_node|
164
+ inner_node_name = (inner_node.keys.reject {|k| k.to_s[0..0] == '_' }).first
165
+ args.merge!(handle_node_type(xml, inner_node, inner_node_name, args, node_name.to_s + ' '))
166
+ end
167
+ end
168
+ return args
169
+ end
170
+
171
+ end
172
+
173
+ end
@@ -10,7 +10,6 @@ module AuthorizeNet
10
10
  module Gateway
11
11
  LIVE = 'https://api.authorize.net/xml/v1/request.api'
12
12
  TEST = 'https://apitest.authorize.net/xml/v1/request.api'
13
- #TEST = 'https://qagrecp1d.vposdownload.qa.intra/xml/v1/request.api'
14
13
  end
15
14
 
16
15
  # Constants for both the various Authorize.Net transaction types are defined here.
@@ -19,6 +18,7 @@ module AuthorizeNet
19
18
  ARB_UPDATE = "ARBUpdateSubscriptionRequest"
20
19
  ARB_GET_STATUS = "ARBGetSubscriptionStatusRequest"
21
20
  ARB_CANCEL = "ARBCancelSubscriptionRequest"
21
+ ARB_GET_SUBSCRIPTION_LIST = "ARBGetSubscriptionListRequest"
22
22
  CIM_CREATE_PROFILE = "createCustomerProfileRequest"
23
23
  CIM_CREATE_PAYMENT = "createCustomerPaymentProfileRequest"
24
24
  CIM_CREATE_ADDRESS = "createCustomerShippingAddressRequest"
@@ -158,6 +158,7 @@ module AuthorizeNet
158
158
  multivalue = node[:_multivalue]
159
159
  conditional = node[:_conditional]
160
160
  value = node[nodeName]
161
+
161
162
  unless conditional.nil?
162
163
  value = self.send(conditional, nodeName)
163
164
  end
@@ -239,7 +240,7 @@ module AuthorizeNet
239
240
  end
240
241
 
241
242
  fields = @fields
242
-
243
+
243
244
  builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |x|
244
245
  x.send(@type.to_sym, :xmlns => XML_NAMESPACE) {
245
246
  x.merchantAuthentication {
@@ -249,8 +250,7 @@ module AuthorizeNet
249
250
  build_nodes(x, self.class.const_get(:FIELDS)[@type], fields)
250
251
  }
251
252
  end
252
- @xml = builder.to_xml
253
-
253
+ @xml = builder.to_xml
254
254
  url = URI.parse(@gateway)
255
255
 
256
256
  request = Net::HTTP::Post.new(url.path)
@@ -273,4 +273,4 @@ module AuthorizeNet
273
273
  end
274
274
 
275
275
  end
276
- end
276
+ end
@@ -0,0 +1,276 @@
1
+ module AuthorizeNet
2
+
3
+ # The ARB transaction class.
4
+ class XmlTransaction < AuthorizeNet::Transaction
5
+
6
+ # The XML namespace used by the ARB API.
7
+ XML_NAMESPACE = 'AnetApi/xml/v1/schema/AnetApiSchema.xsd'
8
+
9
+ # Constants for both the various Authorize.Net subscription gateways are defined here.
10
+ module Gateway
11
+ LIVE = 'https://api.authorize.net/xml/v1/request.api'
12
+ TEST = 'https://apitest.authorize.net/xml/v1/request.api'
13
+ end
14
+
15
+ # Constants for both the various Authorize.Net transaction types are defined here.
16
+ module Type
17
+ ARB_CREATE = "ARBCreateSubscriptionRequest"
18
+ ARB_UPDATE = "ARBUpdateSubscriptionRequest"
19
+ ARB_GET_STATUS = "ARBGetSubscriptionStatusRequest"
20
+ ARB_CANCEL = "ARBCancelSubscriptionRequest"
21
+ ARB_GET_SUBSCRIPTION_LIST = "ARBGetSubscriptionListRequest"
22
+ CIM_CREATE_PROFILE = "createCustomerProfileRequest"
23
+ CIM_CREATE_PAYMENT = "createCustomerPaymentProfileRequest"
24
+ CIM_CREATE_ADDRESS = "createCustomerShippingAddressRequest"
25
+ CIM_CREATE_TRANSACTION = "createCustomerProfileTransactionRequest"
26
+ CIM_DELETE_PROFILE = "deleteCustomerProfileRequest"
27
+ CIM_DELETE_PAYMENT = "deleteCustomerPaymentProfileRequest"
28
+ CIM_DELETE_ADDRESS = "deleteCustomerShippingAddressRequest"
29
+ CIM_GET_PROFILE_IDS = "getCustomerProfileIdsRequest"
30
+ CIM_GET_PROFILE = "getCustomerProfileRequest"
31
+ CIM_GET_PAYMENT = "getCustomerPaymentProfileRequest"
32
+ CIM_GET_ADDRESS = "getCustomerShippingAddressRequest"
33
+ CIM_UPDATE_PROFILE = "updateCustomerProfileRequest"
34
+ CIM_UPDATE_PAYMENT = "updateCustomerPaymentProfileRequest"
35
+ CIM_UPDATE_ADDRESS = "updateCustomerShippingAddressRequest"
36
+ CIM_UPDATE_SPLIT = "updateSplitTenderGroupRequest"
37
+ CIM_VALIDATE_PAYMENT = "validateCustomerPaymentProfileRequest"
38
+ REPORT_GET_BATCH_LIST = "getSettledBatchListRequest"
39
+ REPORT_GET_TRANSACTION_LIST = "getTransactionListRequest"
40
+ REPORT_GET_TRANSACTION_DETAILS = "getTransactionDetailsRequest"
41
+ end
42
+
43
+ # Fields to convert to/from booleans.
44
+ @@boolean_fields = []
45
+
46
+ # Fields to convert to/from BigDecimal.
47
+ @@decimal_fields = []
48
+
49
+ # Fields to convert to/from Date.
50
+ @@date_fields = []
51
+
52
+ # Fields to convert to/from DateTime.
53
+ @@datetime_fields = []
54
+
55
+ # The class to wrap our response in.
56
+ @response_class = AuthorizeNet::XmlResponse
57
+
58
+ # The default options for the constructor.
59
+ @@option_defaults = {
60
+ :gateway => :production,
61
+ :verify_ssl => false,
62
+ :reference_id => nil
63
+ }
64
+
65
+ # DO NOT USE. Instantiate AuthorizeNet::ARB::Transaction or AuthorizeNet::CIM::Transaction instead.
66
+ def initialize(api_login_id, api_transaction_key, options = {})
67
+ super()
68
+ @api_login_id = api_login_id
69
+ @api_transaction_key = api_transaction_key
70
+
71
+ @response ||= nil
72
+ @type ||= nil
73
+
74
+ options = @@option_defaults.merge(options)
75
+ @verify_ssl = options[:verify_ssl]
76
+ @reference_id = options[:reference_id]
77
+ case options[:gateway]
78
+ when :sandbox, :test
79
+ @gateway = Gateway::TEST
80
+ when :production, :live
81
+ @gateway = Gateway::LIVE
82
+ else
83
+ @gateway = options[:gateway]
84
+ end
85
+ end
86
+
87
+ # Checks if the transaction has been configured for the sandbox or not. Return FALSE if the
88
+ # transaction is running against the production, TRUE otherwise.
89
+ def test?
90
+ @gateway != Gateway::LIVE
91
+ end
92
+
93
+ # Checks to see if the transaction has a response (meaning it has been submitted to the gateway).
94
+ # Returns TRUE if a response is present, FALSE otherwise.
95
+ def has_response?
96
+ !@response.nil?
97
+ end
98
+
99
+ # Retrieve the response object (or Nil if transaction hasn't been sent to the gateway).
100
+ def response
101
+ @response
102
+ end
103
+
104
+ # Submits the transaction to the gateway for processing. Returns a response object. If the transaction
105
+ # has already been run, it will return nil.
106
+ def run
107
+ make_request
108
+ end
109
+
110
+ # Returns a deep-copy of the XML object sent to the payment gateway. Or nil if there was no XML payload.
111
+ def xml
112
+ @xml
113
+ end
114
+
115
+ #:enddoc:
116
+ protected
117
+
118
+ # Takes a list of nodes (a Hash is a node, and Array is a list) and returns True if any nodes
119
+ # would be built by build_nodes. False if no new nodes would be generated.
120
+ def has_content(nodeList, data)
121
+ nodeList.each do |node|
122
+ nodeName = (node.keys.reject {|k| nodeName.to_s[0..0] == '_' }).first
123
+ multivalue = node[:_multivalue]
124
+ conditional = node[:_conditional]
125
+ value = node[nodeName]
126
+ unless conditional.nil?
127
+ value = self.send(conditional, nodeName)
128
+ end
129
+ case value
130
+ when Array
131
+ if multivalue.nil?
132
+ if has_content(value, data)
133
+ return true
134
+ end
135
+ else
136
+ data[multivalue].each do |v|
137
+ if has_content(value, v)
138
+ return true
139
+ end
140
+ end
141
+ end
142
+ when Symbol
143
+ converted = convert_field(value, data[value])
144
+ return true unless converted.nil?
145
+ else
146
+ return true
147
+ end
148
+ end
149
+ false
150
+ end
151
+
152
+ # Takes a list of nodes (a Hash is a node, and Array is a list) and recursively builds the XML by pulling
153
+ # values as needed from data.
154
+ def build_nodes(builder, nodeList, data)
155
+ nodeList.each do |node|
156
+ # TODO - ADD COMMENTS HERE
157
+ nodeName = (node.keys.reject {|k| k.to_s[0..0] == '_' }).first
158
+ multivalue = node[:_multivalue]
159
+ conditional = node[:_conditional]
160
+ value = node[nodeName]
161
+
162
+ unless conditional.nil?
163
+ value = self.send(conditional, nodeName)
164
+ end
165
+ case value
166
+ when Array # node containing other nodes
167
+ if multivalue.nil?
168
+ proc = Proc.new { build_nodes(builder, value, data) }
169
+ builder.send(nodeName, &proc) if has_content(value, data)
170
+ else
171
+ data[multivalue].to_a.each do |v|
172
+ proc = Proc.new { build_nodes(builder, value, v) }
173
+ builder.send(nodeName, &proc) if has_content(value, v)
174
+ end
175
+ end
176
+ when Symbol # node containing actual data
177
+ if data[value].kind_of?(Array)
178
+ data[value].each do |v|
179
+ converted = convert_field(value, v)
180
+ builder.send(nodeName, converted) unless converted.nil?
181
+ end
182
+ else
183
+ converted = convert_field(value, data[value])
184
+ builder.send(nodeName, converted) unless converted.nil?
185
+ end
186
+ else
187
+ builder.send(nodeName, value)
188
+ end
189
+ end
190
+ end
191
+
192
+ def convert_field(field, value)
193
+ if @@boolean_fields.include?(field) and !value.nil?
194
+ return boolean_to_value(value)
195
+ elsif @@decimal_fields.include?(field) and !value.nil?
196
+ return decimal_to_value(value)
197
+ elsif @@date_fields.include?(field) and !value.nil?
198
+ return date_to_value(value)
199
+ elsif @@datetime_fields.include?(field) and !value.nil?
200
+ return datetime_to_value(value)
201
+ elsif field == :extra_options
202
+ # handle converting extra options
203
+ options = []
204
+ unless value.nil?
205
+ value.each_pair{|k,v| options <<= self.to_param(k, v)}
206
+ end
207
+ unless @custom_fields.nil?
208
+ # special sort to maintain compatibility with AIM custom field ordering
209
+ # FIXME - This should be DRY'd up.
210
+ custom_field_keys = @custom_fields.keys.collect(&:to_s).sort.collect(&:to_sym)
211
+ for key in custom_field_keys
212
+ options <<= self.to_param(key, @custom_fields[key.to_sym], '')
213
+ end
214
+ end
215
+
216
+ if options.length > 0
217
+ return options.join('&')
218
+ else
219
+ return nil
220
+ end
221
+ elsif field == :exp_date
222
+ # convert MMYY expiration dates into the XML equivalent
223
+ unless value.nil?
224
+ begin
225
+ return value.to_s.downcase == 'xxxx' ? 'XXXX' : Date.strptime(value.to_s, '%m%y').strftime('%Y-%m')
226
+ rescue
227
+ # If we didn't get the exp_date in MMYY format, try our best to convert it
228
+ return Date.parse(value.to_s).strftime('%Y-%m')
229
+ end
230
+ end
231
+ end
232
+
233
+ value
234
+ end
235
+
236
+ # An internal method that builds the POST body, submits it to the gateway, and constructs a Response object with the response.
237
+ def make_request
238
+ if has_response?
239
+ return nil
240
+ end
241
+
242
+ fields = @fields
243
+
244
+ builder = Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |x|
245
+ x.send(@type.to_sym, :xmlns => XML_NAMESPACE) {
246
+ x.merchantAuthentication {
247
+ x.name @api_login_id
248
+ x.transactionKey @api_transaction_key
249
+ }
250
+ build_nodes(x, self.class.const_get(:FIELDS)[@type], fields)
251
+ }
252
+ end
253
+ @xml = builder.to_xml
254
+ url = URI.parse(@gateway)
255
+
256
+ request = Net::HTTP::Post.new(url.path)
257
+ request.content_type = 'text/xml'
258
+ request.body = @xml
259
+ connection = Net::HTTP.new(url.host, url.port)
260
+ connection.use_ssl = true
261
+ if @verify_ssl
262
+ connection.verify_mode = OpenSSL::SSL::VERIFY_PEER
263
+ else
264
+ connection.verify_mode = OpenSSL::SSL::VERIFY_NONE
265
+ end
266
+
267
+ # Use our Class's @response_class variable to find the Response class we are supposed to use.
268
+ begin
269
+ @response = self.class.instance_variable_get(:@response_class).new((connection.start {|http| http.request(request)}), self)
270
+ rescue
271
+ @response = self.class.instance_variable_get(:@response_class).new($!, self)
272
+ end
273
+ end
274
+
275
+ end
276
+ end