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) someon

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:



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

def initialize rack_payment
  @rack_payment = rack_payment
end

Instance Attribute Details

#amountObject

Returns the value of attribute amount.



31
32
33
# File 'lib/rack-payment/helper.rb', line 31

def amount
  @amount
end

#billing_addressObject

Returns the value of attribute billing_address.



31
32
33
# File 'lib/rack-payment/helper.rb', line 31

def billing_address
  @billing_address
end

#credit_cardObject

Returns the value of attribute credit_card.



31
32
33
# File 'lib/rack-payment/helper.rb', line 31

def credit_card
  @credit_card
end

#errorsObject

Returns the value of attribute errors.



31
32
33
# File 'lib/rack-payment/helper.rb', line 31

def errors
  @errors
end

#on_errorObject

Specifies what page to render if payment fails (for this specific request). To set this option globally, see Rack::Payment#on_error.



35
36
37
# File 'lib/rack-payment/helper.rb', line 35

def on_error
  @on_error
end

#on_successObject

Specifies what page to render if payment succeeds (for this specific request). To set this option globally, see Rack::Payment#on_success.



39
40
41
# File 'lib/rack-payment/helper.rb', line 39

def on_success
  @on_success
end

#rack_paymentObject

Returns the value of attribute rack_payment.



31
32
33
# File 'lib/rack-payment/helper.rb', line 31

def rack_payment
  @rack_payment
end

#responseObject

Returns the value of attribute response.



31
32
33
# File 'lib/rack-payment/helper.rb', line 31

def response
  @response
end

#use_expressObject

Returns the value of attribute use_express.



31
32
33
# File 'lib/rack-payment/helper.rb', line 31

def use_express
  @use_express
end

Instance Method Details

#amount_in_centsObject



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

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

#billing_address_valuesObject



246
247
248
249
250
251
# File 'lib/rack-payment/helper.rb', line 246

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)


91
92
93
# File 'lib/rack-payment/helper.rb', line 91

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

#ccObject



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

def cc
  credit_card
end

#credit_card_valuesObject



239
240
241
242
243
244
# File 'lib/rack-payment/helper.rb', line 239

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



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/rack-payment/helper.rb', line 254

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



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/rack-payment/helper.rb', line 191

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



299
300
301
302
303
304
305
# File 'lib/rack-payment/helper.rb', line 299

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



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

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



118
119
120
# File 'lib/rack-payment/helper.rb', line 118

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



122
123
124
# File 'lib/rack-payment/helper.rb', line 122

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



126
127
128
# File 'lib/rack-payment/helper.rb', line 126

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



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

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?



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

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



227
228
229
230
231
232
233
234
235
236
237
# File 'lib/rack-payment/helper.rb', line 227

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



207
208
209
210
211
212
213
214
215
# File 'lib/rack-payment/helper.rb', line 207

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



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

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



63
64
65
# File 'lib/rack-payment/helper.rb', line 63

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)


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
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/rack-payment/helper.rb', line 134

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.



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

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



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/rack-payment/helper.rb', line 281

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



58
59
60
# File 'lib/rack-payment/helper.rb', line 58

def use_express!
  self.use_express = true 
end

#use_express?Boolean

Returns:

  • (Boolean)


54
55
56
# File 'lib/rack-payment/helper.rb', line 54

def use_express?
  self.use_express == true
end