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:



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

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

#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



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

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

#billing_address_valuesObject



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

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)


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

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

#ccObject



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

def cc
  credit_card
end

#credit_card_valuesObject



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

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



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/rack-payment/helper.rb', line 246

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



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/rack-payment/helper.rb', line 183

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



291
292
293
294
295
296
297
# File 'lib/rack-payment/helper.rb', line 291

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



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

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



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

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



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

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



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

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



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

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?



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

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



219
220
221
222
223
224
225
226
227
228
229
# File 'lib/rack-payment/helper.rb', line 219

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



199
200
201
202
203
204
205
206
207
# File 'lib/rack-payment/helper.rb', line 199

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



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

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



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

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)


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
172
173
174
175
176
# File 'lib/rack-payment/helper.rb', line 126

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.



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

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



273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/rack-payment/helper.rb', line 273

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



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

def use_express!
  self.use_express = true 
end

#use_express?Boolean

Returns:

  • (Boolean)


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

def use_express?
  self.use_express == true
end