Completed
Pull Request — master (#156)
by
unknown
02:20
created

KeyValueTransaction.handle_transaction_argument()   A

Complexity

Conditions 3

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 7.608

Importance

Changes 0
Metric Value
cc 3
dl 0
loc 10
ccs 1
cts 5
cp 0.2
crap 7.608
rs 9.4285
c 0
b 0
f 0
1 1
module AuthorizeNet
2
  # The core, key/value transaction class. You shouldn't instantiate this one.
3
  # Instead you should use AuthorizeNet::AIM::Transaction or AuthorizeNet::SIM::Transaction.
4 1
  class KeyValueTransaction < AuthorizeNet::Transaction
5
    # Constants for both the various Authorize.Net payment gateways are defined here.
6 1
    module Gateway
7 1
      LIVE = 'https://secure2.authorize.net/gateway/transact.dll'.freeze
8 1
      TEST = 'https://test.authorize.net/gateway/transact.dll'.freeze
9 1
      CARD_PRESENT_LIVE = 'https://cardpresent.authorize.net/gateway/transact.dll'.freeze
10 1
      CARD_PRESENT_TEST = 'https://test.authorize.net/gateway/transact.dll'.freeze
11
    end
12
13
    # Constants for both the various Authorize.Net payment transaction types are defined here.
14 1
    module Type
15 1
      AUTHORIZE_AND_CAPTURE = "AUTH_CAPTURE".freeze
16 1
      AUTHORIZE_ONLY = "AUTH_ONLY".freeze
17 1
      CAPTURE_ONLY = "CAPTURE_ONLY".freeze
18 1
      CREDIT = "CREDIT".freeze
19 1
      PRIOR_AUTHORIZATION_AND_CAPTURE = "PRIOR_AUTH_CAPTURE".freeze
20 1
      VOID = "VOID".freeze
21
    end
22
23
    # Constants for the various device types used in card present transactions.
24 1
    module DeviceType
25 1
      UNKNOWN = 1
26 1
      UNATTENDED = 2
27 1
      SELF_SERVICE = 3
28 1
      CASH_REGISTER = 4
29 1
      PC_TERMINAL = 5
30 1
      AIRPAY = 6
31 1
      WIRELESS_POS = 7
32 1
      WEBSITE_TERMINAL = 8
33 1
      DIAL_TERMINAL = 9
34 1
      VIRTUAL_TERMINAL = 10
35
    end
36
37
    # Constants for the various market types used in card present transactions.
38 1
    module MarketType
39 1
      RETAIL = 2
40
    end
41
42
    # The default options for purchase.
43 1
    @@purchase_option_defaults = {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using a class variable like @@purchase_option_defaults is generally not recommended; did you consider
using an class instance variable instead?
Loading history...
44
      cardholder_auth_value: nil,
45
      cardholder_auth_indicator: nil
46
    }
47
48
    # The default options for authorize.
49 1
    @@authorize_option_defaults = {
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using a class variable like @@authorize_option_defaults is generally not recommended; did you consider
using an class instance variable instead?
Loading history...
50
      cardholder_auth_value: nil,
51
      cardholder_auth_indicator: nil
52
    }
53
54
    # Fields to convert to/from booleans.
55 1
    @@boolean_fields = []
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using a class variable like @@boolean_fields is generally not recommended; did you consider
using an class instance variable instead?
Loading history...
56
57
    # Fields to convert to/from BigDecimal.
58 1
    @@decimal_fields = []
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using a class variable like @@decimal_fields is generally not recommended; did you consider
using an class instance variable instead?
Loading history...
59
60
    # DO NOT USE. Instantiate AuthorizeNet::AIM::Transaction or AuthorizeNet::SIM::Transaction instead.
61 1
    def initialize
62 1
      super
63 1
      @custom_fields ||= {}
64 1
      @test_mode ||= false
65 1
      @version = '3.1'
66
    end
67
68
    # Checks if the transaction has been configured for test mode or not. Return TRUE if the
69
    # transaction is a test transaction, FALSE otherwise. All transactions run against the sandbox
70
    # are considered test transactions.
71 1
    def test?
72
      !!@test_mode
73
    end
74
75
    # Returns the current API version that we are adhering to
76 1
    attr_reader :version
77
78
    # Sets arbitrary custom fields, overwriting existing values if they exist. Takes a hash of key/value pairs,
79
    # where the keys are the field names. You can set a field to Nil to unset it.
80 1
    def set_custom_fields(fields = {})
81
      @custom_fields.merge!(fields)
82
    end
83
84
    # Returns the current hash of custom fields.
85 1
    attr_reader :custom_fields
86
87
    # Convenience method for adding line items to a transaction.
88 1
    def add_line_item(id = nil, name = nil, description = nil, quantity = nil, price = nil, taxable = nil)
89
      line_item = "#{id}<|>#{name}<|>#{description}<|>#{quantity}<|>#{price}<|>#{taxable}"
90
      if @fields.key?(:line_item)
91
        @fields[:line_item] = @fields[:line_item].to_a << line_item
92
      else
93
        @fields[:line_item] = [line_item]
94
      end
95
    end
96
97
    # Takes an instance of AuthorizeNet::EmailReceipt and adds it to the transaction.
98 1
    def set_email_receipt(email)
99
      @fields.merge!(email.to_hash)
100
    end
101
102
    # Returns the type of transaction.
103 1
    attr_reader :type
104
105
    # Sets the type of transaction.
106 1
    def type=(type)
107 1
      case type
108
      when :authorize, :auth_only
109
        @type = Type::AUTHORIZE_ONLY
110
      when :purchase, :auth_and_capture
111
        @type = Type::AUTHORIZE_AND_CAPTURE
112
      when :refund, :credit
113
        @type = Type::CREDIT
114
      when :void
115
        @type = Type::VOID
116
      when :capture, :capture_only
117
        @type = Type::CAPTURE_ONLY
118
      when :prior_auth_capture
119
        @type = Type::PRIOR_AUTHORIZATION_AND_CAPTURE
120
      else
121 1
        @type = type
122
      end
123
    end
124
125
    # Sets up and submits a standard purchase (AUTHORIZE_AND_CAPTURE) transaction. Returns a response object. If the transaction
126
    # has already been run, it will return nil.
127
    #
128
    # +amount+:: The amount to charge. Accepts a string in the format "%0.2f", a Float or a BigDecimal.
129
    # +credit_card+:: The credit card or eCheck to charge. Accepts an instance of AuthorizeNet::CreditCard, AuthorizeNet::ECheck, or a string of digits (in which case the expiration should be added using set_fields).
130
    # +options+:: A hash with any of following keys: cardholder_auth_indicator, cardholder_auth_value. These are for CAVV and can be ignored in most cases.
131
    #
132
    #
133
    # Typical usage:
134
    #
135
    #   credit_card = AuthorizeNet::CreditCard.new('4111111111111111', '1120')
136
    #   response = transaction.purchase(10.0, credit_card)
137
    #
138 1 View Code Duplication
    def purchase(amount, credit_card, options = {})
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
139 1
      handle_payment_argument(credit_card)
140 1
      options = @@purchase_option_defaults.merge(options)
141 1
      handle_cavv_options(options)
142 1
      set_fields(amount: amount)
143 1
      self.type = Type::AUTHORIZE_AND_CAPTURE
144 1
      run
145
    end
146
147
    # Sets up and submits a refund (CREDIT) transaction. Returns a response object. If the transaction
148
    # has already been run, it will return nil.
149
    #
150
    # +amount+:: The amount to refund. Accepts a string in the format "%0.2f", a Float or a BigDecimal.
151
    # +transaction+:: The transaction ID to apply the refund to. Accepts a string of the transaction ID, an instance of AuthorizeNet::Transaction or AuthorizeNet::Response.
152
    # +credit_card+:: The credit card or eCheck to charge. Accepts an instance of AuthorizeNet::CreditCard, AuthorizeNet::ECheck, or a string of digits. In many cases you only need the last 4 digits of the credit card here.
153
    #
154
    #
155
    # Typical usage:
156
    #
157
    #   response = transaction.refund(10.0, '123456789', '1212')
158
    #
159 1 View Code Duplication
    def refund(amount, transaction, credit_card)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
160
      handle_payment_argument(credit_card)
161
      handle_transaction_argument(transaction)
162
      set_fields(amount: amount)
163
      self.type = Type::CREDIT
164
      run
165
    end
166
167
    # Sets up and submits a refund (CREDIT) transaction for a transaction that was not originally
168
    # submitted via the payment gateway. Note that this is a special feature which requires your
169
    # account to support ECC (expanded credits capability) transactions.
170
    #
171
    # +amount+:: The amount to refund. Accepts a string in the format "%0.2f", a Float or a BigDecimal.
172
    # +credit_card+:: The credit card or eCheck to charge. Accepts an instance of AuthorizeNet::CreditCard, AuthorizeNet::ECheck, or a string of digits.
173
    #
174
    # Typical usage:
175
    #
176
    #   response = transaction.unlinked_credit(10.0, '4111111111111111')
177
    #
178 1 View Code Duplication
    def unlinked_credit(amount, credit_card)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
179
      handle_payment_argument(credit_card)
180
      set_fields(amount: amount)
181
      self.type = Type::CREDIT
182
      run
183
    end
184
185
    # Sets up and submits a void (VOID) transaction. Returns a response object. If the transaction
186
    # has already been run, it will return nil. Note that you can only void unsettled transactions.
187
    #
188
    # +transaction+:: The transaction ID of the transaction to void. Accepts a string of the transaction ID, an instance of AuthorizeNet::Transaction or AuthorizeNet::Response.
189
    #
190
    #
191
    # Typical usage:
192
    #
193
    #   response = transaction.void('123456789')
194
    #
195 1
    def void(transaction)
196
      handle_transaction_argument(transaction)
197
      self.type = Type::VOID
198
      run
199
    end
200
201
    # Sets up and submits an authorize (AUTH_ONLY) transaction. Returns a response object. If the transaction
202
    # has already been run, it will return nil. Use this to put a hold on funds, but don't actually charge
203
    # the card yet.
204
    #
205
    # +amount+:: The amount to authorize. Accepts a string in the format "%0.2f", a Float or a BigDecimal.
206
    # +credit_card+:: The credit card or eCheck to charge. Accepts an instance of AuthorizeNet::CreditCard, AuthorizeNet::ECheck, or a string of digits (in which case the expiration should be added using set_fields).
207
    # +options+:: A hash with any of following keys: cardholder_auth_indicator, cardholder_auth_value. These are for CAVV and can be ignored in most cases.
208
    #
209
    #
210
    # Typical usage:
211
    #
212
    #   credit_card = AuthorizeNet::CreditCard.new('4111111111111111', '1120')
213
    #   response = transaction.authorize(10.0, credit_card)
214
    #
215 1 View Code Duplication
    def authorize(amount, credit_card, options = {})
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
216
      handle_payment_argument(credit_card)
217
      options = @@authorize_option_defaults.merge(options)
218
      handle_cavv_options(options)
219
      set_fields(amount: amount)
220
      self.type = Type::AUTHORIZE_ONLY
221
      run
222
    end
223
224
    # Sets up and submits a capture (CAPTURE_ONLY) transaction. Returns a response object. If the transaction
225
    # has already been run, it will return nil. Note that you can not capture a transaction that was made
226
    # though the AIM API using this method. Use prior_auth_capture instead.
227
    #
228
    # +amount+:: The amount to capture. Accepts a string in the format "%0.2f", a Float or a BigDecimal.
229
    # +authorization_code+:: The authorization code of the transaction to capture. Accepts a string.
230
    #
231
    #
232
    # Typical usage:
233
    #
234
    #   response = transaction.capture(10.0, '123FAKE')
235
    #
236 1
    def capture(amount, authorization_code)
237
      set_fields(amount: amount, auth_code: authorization_code)
238
      self.type = Type::CAPTURE_ONLY
239
      run
240
    end
241
242
    # Sets up and submits a capture (PRIOR_AUTH_CAPTURE) transaction. Returns a response object. Use this method
243
    # to actually charge a card that you previously put a hold on (using authorize).
244
    #
245
    # +transaction+:: The transaction ID to capture. Accepts a string of the transaction ID, an instance of AuthorizeNet::Transaction or AuthorizeNet::Response.
246
    # +amount+:: The amount to capture (only if less than the amount originally authorized, otherwise leave as Nil). Accepts a string in the format "%0.2f", a Float, a BigDecimal or Nil.
247
    #
248
    #
249
    # Typical usage:
250
    #
251
    #   response = transaction.prior_auth_capture('123456789')
252
    #
253 1
    def prior_auth_capture(transaction, amount = nil)
254
      handle_transaction_argument(transaction)
255
      set_fields(amount: amount)
256
      self.type = Type::PRIOR_AUTHORIZATION_AND_CAPTURE
257
      run
258
    end
259
260
    #:enddoc:
261 1
    protected
262
263
    # Internal method to handle multiple types of transaction arguments.
264 1
    def handle_transaction_argument(transaction)
265
      case transaction
266
      when Transaction
267
        set_fields(trans_id: transaction.response.transaction_id)
268
      when Response
269
        set_fields(trans_id: transaction.transaction_id)
270
      else
271
        set_fields(trans_id: transaction)
272
      end
273
    end
274
275
    # Internal method to handle CAVV options.
276 1
    def handle_cavv_options(options)
277 1
      set_fields(authentication_indicator: options[:cardholder_auth_indicator]) unless options[:cardholder_auth_indicator].nil?
278 1
      set_fields(cardholder_authentication_value: options[:cardholder_auth_value]) unless options[:cardholder_auth_value].nil?
279
    end
280
  end
281
end
282