Class: Rack::Payment::Helper

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/rack-payment/helper.rb

Overview

When you include Methods into your application, you get a #payment method/object which gives you an instance of Helper

Helper is the main API for working with Rack::Payment. You use it to:

* Set the {#amount} you want to charge someone
* Spit out the HTML for a credit card / billing information {#form} into your own application
* Set the {#credit_card} and {#billing_address} to be used when processing the payment
* Get {#errors} if something didn't work
* Get the {#response} from your billing gateway after charging (or attempting to charge) someone
* Get the URL to the image for a {#paypal_express_button}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(rack_payment) ⇒ Helper

Returns a new instance of Helper.

Parameters:



29
30
31
# File 'lib/rack-payment/helper.rb', line 29

def initialize rack_payment
  @rack_payment = rack_payment
end

Instance Attribute Details

#amountObject

Returns the value of attribute amount.



26
27
28
# File 'lib/rack-payment/helper.rb', line 26

def amount
  @amount
end

#billing_addressObject

Returns the value of attribute billing_address.



26
27
28
# File 'lib/rack-payment/helper.rb', line 26

def billing_address
  @billing_address
end

#credit_cardObject

Returns the value of attribute credit_card.



26
27
28
# File 'lib/rack-payment/helper.rb', line 26

def credit_card
  @credit_card
end

#errorsObject

Returns the value of attribute errors.



26
27
28
# File 'lib/rack-payment/helper.rb', line 26

def errors
  @errors
end

#rack_paymentObject

Returns the value of attribute rack_payment.



26
27
28
# File 'lib/rack-payment/helper.rb', line 26

def rack_payment
  @rack_payment
end

#responseObject

Returns the value of attribute response.



26
27
28
# File 'lib/rack-payment/helper.rb', line 26

def response
  @response
end

#use_expressObject

Returns the value of attribute use_express.



26
27
28
# File 'lib/rack-payment/helper.rb', line 26

def use_express
  @use_express
end

Instance Method Details

#amount_in_centsObject



74
75
76
# File 'lib/rack-payment/helper.rb', line 74

def amount_in_cents
  (amount * 100).to_i if amount
end

#billing_address_valuesObject



233
234
235
236
237
238
# File 'lib/rack-payment/helper.rb', line 233

def billing_address_values
  %w( name address1 city state zip country ).inject({}) do |all, attribute|
    all[attribute.to_sym] = billing_address[attribute.to_sym]
    all
  end
end

#card_or_address_partially_filled_out?Boolean

Returns:

  • (Boolean)


78
79
80
# File 'lib/rack-payment/helper.rb', line 78

def card_or_address_partially_filled_out?
  credit_card.partially_filled_out? or billing_address.partially_filled_out?
end

#ccObject



33
34
35
# File 'lib/rack-payment/helper.rb', line 33

def cc
  credit_card
end

#credit_card_valuesObject



226
227
228
229
230
231
# File 'lib/rack-payment/helper.rb', line 226

def credit_card_values
  %w( first_name last_name number cvv type expiration_month expiration_year ).inject({}) do |all, attribute|
    all[attribute.to_sym] = credit_card[attribute.to_sym]
    all
  end
end

#fields(values = nil) ⇒ Object

Returns Hash of HTML fields with their values set.

Returns:

  • Hash of HTML fields with their values set



241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/rack-payment/helper.rb', line 241

def fields values = nil
  values ||= {}
  values[:credit_card]     = credit_card_values.merge(     values[:credit_card]     || {} )
  values[:billing_address] = billing_address_values.merge( values[:billing_address] || {} )

  CallableHash.new({
    :credit_card => CallableHash.new({
      :first_name       => input_tag(  :credit_card, :first_name,       values[:credit_card][:first_name],  :autofocus => true),
      :last_name        => input_tag(  :credit_card, :last_name,        values[:credit_card][:last_name]),
      :number           => input_tag(  :credit_card, :number,           values[:credit_card][:number],      :autocomplete => 'off'),
      :cvv              => input_tag(  :credit_card, :cvv,              values[:credit_card][:cvv],         :autocomplete => 'off'),
      :type             => select_tag( :credit_card, :type,             values[:credit_card][:type]),
      :expiration_month => select_tag( :credit_card, :expiration_month, values[:credit_card][:expiration_month]),
      :expiration_year  => select_tag( :credit_card, :expiration_year,  values[:credit_card][:expiration_year])
    }),

    :billing_address => CallableHash.new({
      :name     => input_tag(:billing_address, :name,     values[:billing_address][:name]),
      :address1 => input_tag(:billing_address, :address1, values[:billing_address][:address1]),
      :city     => input_tag(:billing_address, :city,     values[:billing_address][:city]),
      :state    => input_tag(:billing_address, :state,    values[:billing_address][:state]),
      :zip      => input_tag(:billing_address, :zip,      values[:billing_address][:zip]),
      :country  => input_tag(:billing_address, :country,  values[:billing_address][:country])
    })
  })
end

#form(options = nil) ⇒ Object

Returns the HTML for the built in form

By default, the form will POST to the current URL (action=”)

You can pass a different URL for the form action



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/rack-payment/helper.rb', line 178

def form options = nil
  options ||= {}
  post_to    = (options[:post_to] ||= '') # the url/path to post to
  auth_token = options[:auth_token]       # if not nil, we include the authenticity_token in the form

  view = ::File.dirname(__FILE__) + '/views/credit-card-and-billing-info-form.html.erb'
  erb  = ::File.read view
  html = ''

  if options and options[:inline_css]
    html << "<style type='text/css'>\n#{ options[:inline_css] }\n</style>"
  end

  html << ERB.new(erb).result(binding)
end

#input_tag(object, property, value = nil, options = nil) ⇒ Object

Returns the HTML for an <input /> element

Returns:

  • String



286
287
288
289
290
291
292
# File 'lib/rack-payment/helper.rb', line 286

def input_tag object, property, value = nil, options = nil
  attributes = { :type => 'text', :id => "#{object}_#{property}", :name => "#{object}[#{property}]" }
  attributes[:value] = value if value.present?
  attributes.merge!(options) if options

  "<input #{ attributes.map {|name, value| "#{name}='#{value}'" }.join(' ') } />"
end

#log_authorize_successful(transaction_id, options) ⇒ Object



101
102
103
# File 'lib/rack-payment/helper.rb', line 101

def log_authorize_successful transaction_id, options
  logger.debug { "[#{transaction_id}] #authorize(#{amount_in_cents.inspect}, <CreditCard for #{ credit_card.full_name.inspect }>, :ip => #{ options[:ip].inspect }) was successful" } if logger
end

#log_authorize_unsuccessful(transaction_id, options) ⇒ Object



105
106
107
# File 'lib/rack-payment/helper.rb', line 105

def log_authorize_unsuccessful transaction_id, options
  logger.debug { "[#{transaction_id}] #authorize(#{amount_in_cents.inspect}, <CreditCard for #{ credit_card.full_name.inspect }>, :ip => #{ options[:ip].inspect }) was unsuccessful: #{ errors.inspect }" } if logger
end

#log_capture_successful(transaction_id) ⇒ Object



109
110
111
# File 'lib/rack-payment/helper.rb', line 109

def log_capture_successful transaction_id
    logger.debug { "[#{transaction_id}] #capture(#{amount_in_cents}, #{raw_authorize_response.authorization.inspect}) was successful" } if logger
end

#log_capture_unsuccessful(transaction_id) ⇒ Object



113
114
115
# File 'lib/rack-payment/helper.rb', line 113

def log_capture_unsuccessful transaction_id
    logger.debug { "[#{transaction_id}] #capture(#{amount_in_cents}, #{raw_authorize_response.authorization.inspect}) was unsuccessful: #{ errors.inspect }" } if logger
end

#log_invalid_credit_card(transaction_id) ⇒ Object



97
98
99
# File 'lib/rack-payment/helper.rb', line 97

def log_invalid_credit_card transaction_id
  logger.warn { "[#{transaction_id}] invalid credit card: #{ errors.inspect }" } if logger
end

#log_purchase_start(transaction_id, options) ⇒ Object

Move these out into a module or something?



93
94
95
# File 'lib/rack-payment/helper.rb', line 93

def log_purchase_start transaction_id, options
  logger.debug { "[#{transaction_id}] #purchase(#{options.inspect}) for amount_in_cents: #{ amount_in_cents.inspect }" } if logger
end

#options_for_credit_card_type(selected = nil) ⇒ Object



214
215
216
217
218
219
220
221
222
223
224
# File 'lib/rack-payment/helper.rb', line 214

def options_for_credit_card_type selected = nil
  [ ['visa', 'Visa'], ['master', 'MasterCard'], ['american_express', 'American Express'], 
    ['discover', 'Discover'] ].map { |value, name|
  
    if selected and selected.to_s == value.to_s
      "<option value='#{ value }' selected='selected'>#{ name }</option>"
    else
      "<option value='#{ value }'>#{ name }</option>"
    end
  }.join
end

#options_for_expiration_month(selected = nil) ⇒ Object



194
195
196
197
198
199
200
201
202
# File 'lib/rack-payment/helper.rb', line 194

def options_for_expiration_month selected = nil
  %w( 01 02 03 04 05 06 07 08 09 10 11 12 ).map { |month|
    if selected and selected.to_s == month.to_s
      "<option selected='selected'>#{ month }</option>"
    else
      "<option>#{ month }</option>"
    end
  }.join
end

#options_for_expiration_year(selected = nil) ⇒ Object



204
205
206
207
208
209
210
211
212
# File 'lib/rack-payment/helper.rb', line 204

def options_for_expiration_year selected = nil
  (Date.today.year..(Date.today.year + 15)).map { |year|
    if selected and selected.to_s == year.to_s
      "<option selected='selected'>#{ year }</option>"
    else
      "<option>#{ year }</option>"
    end
  }.join
end

#paypal_express_buttonObject

helper for getting the src of the express checkout image



50
51
52
# File 'lib/rack-payment/helper.rb', line 50

def paypal_express_button
  'https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif'
end

#purchase(options) ⇒ Object

Fires off a purchase!

This resets #errors and #response

Raises:

  • (ArgumentError)


121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/rack-payment/helper.rb', line 121

def purchase options
  transaction_id = DateTime.now.strftime('%Y-%m-%d %H:%M:%S %L') # %L to include milliseconds
  log_purchase_start(transaction_id, options)

  raise "#amount_in_cents must be greater than 0" unless amount_in_cents.to_i > 0
  raise ArgumentError, "The :ip option is required when calling #purchase" unless options and options[:ip]

  # Check for Credit Card errors
  self.response = Response.new
  self.errors   = credit_card.errors # start off with any errors from the credit_card

  # Try to #authorize (if no errors so far)
  if errors.empty?
    begin
      # TODO should pass :billing_address, if the billing address isn't empty.
      #      fields: name, address1, city, state, country, zip.
      #      Some gateways (eg. PayPal Pro) require a billing_address!
      self.raw_authorize_response = gateway.authorize amount_in_cents, credit_card.active_merchant_card, :ip => options[:ip], :billing_address => billing_address.active_merchant_hash
      unless raw_authorize_response.success?
        errors << raw_authorize_response.message
        log_authorize_unsuccessful(transaction_id, options)
      end
    rescue ActiveMerchant::Billing::Error => error
      self.raw_authorize_response = OpenStruct.new :success? => false, :message => error.message, :authorization => nil
      errors << error.message
      log_authorize_unsuccessful(transaction_id, options)
    end
  else
    log_invalid_credit_card(transaction_id)
  end

  # Try to #capture (if no errors so far)
  if errors.empty?
    log_authorize_successful(transaction_id, options)
    begin
      self.raw_capture_response = gateway.capture amount_in_cents, raw_authorize_response.authorization
      unless raw_capture_response.success?
        errors << raw_capture_response.message
        log_capture_unsuccessful(transaction_id)
      end
    rescue ActiveMerchant::Billing::Error => error
      self.raw_capture_response = OpenStruct.new :success? => false, :message => error.message
      errors << raw_capture_response.message
      log_capture_unsuccessful(transaction_id)
    end
  end

  log_capture_successful(transaction_id) if errors.empty?

  return errors.empty?
end

#purchase!(options) ⇒ Object

The same as #purchase but it raises an exception on error.



83
84
85
86
87
88
89
# File 'lib/rack-payment/helper.rb', line 83

def purchase! options
  if response = purchase(options)
    true
  else
    raise "Purchase failed.  #{ errors.join(', ') }"
  end
end

#select_tag(object, property, value = nil, options = nil) ⇒ Object



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/rack-payment/helper.rb', line 268

def select_tag object, property, value = nil, options = nil
  attributes = { :type => 'text', :id => "#{object}_#{property}", :name => "#{object}[#{property}]" }
  attributes.merge!(options) if options

  case property
  when :type
    options = options_for_credit_card_type(value)
  when :expiration_month
    options = options_for_expiration_month(value)
  when :expiration_year
    options = options_for_expiration_year(value)
  end

  "<select #{ attributes.map {|name, value| "#{name}='#{value}'" }.join(' ') }>#{ options }</select>"
end

#use_express!Object



45
46
47
# File 'lib/rack-payment/helper.rb', line 45

def use_express!
  self.use_express = true 
end

#use_express?Boolean

Returns:

  • (Boolean)


41
42
43
# File 'lib/rack-payment/helper.rb', line 41

def use_express?
  self.use_express == true
end