beanstreamy 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.1
1
+ 0.2.2
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{beanstreamy}
8
- s.version = "0.2.1"
8
+ s.version = "0.2.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jeff Siegel"]
12
- s.date = %q{2010-07-09}
12
+ s.date = %q{2010-07-12}
13
13
  s.description = %q{Adds activemerchant gateway support for hash validation, querying transactions, and submitting payment via hosted forms}
14
14
  s.email = %q{jeff@stage2.ca}
15
15
  s.extra_rdoc_files = [
@@ -29,6 +29,18 @@ module Beanstreamy
29
29
 
30
30
  private
31
31
 
32
+ def parse(body)
33
+ results = super
34
+
35
+ if results[:errorMessage]
36
+ results[:errorMessage].gsub!(/<LI>/, "")
37
+ results[:errorMessage].gsub!(/(\.)?<br>/, ". ")
38
+ results[:errorMessage].strip!
39
+ end
40
+
41
+ results
42
+ end
43
+
32
44
  def add_transaction_type(post, action)
33
45
  post[:trnType] = EXTRA_TRANSACTIONS[action] || super
34
46
  end
@@ -4,21 +4,86 @@ module Beanstreamy
4
4
  mattr_accessor :config
5
5
  @@config = Beanstreamy.config
6
6
 
7
- def beanstream_hosted_payment_form(options = {}, &block)
7
+ # Generate a form that will submit payment information to Beanstream's payment gateway
8
+ # using the http POST method.
9
+ #
10
+ # === Hash Validation
11
+ #
12
+ # It's highly recommended you enable hash validation. Otherwise end-users will be able
13
+ # to modify any information submitted to Beanstream, including the amount to be charged.
14
+ # You can specify the hash key with the +:hash_key+ option.
15
+ #
16
+ # (*Note*: Currently only SHA1 hashing is supported.)
17
+ #
18
+ # The +amount+ argument is expected to be an +Integer+ in cents, just like in ActiveMerchant.
19
+ #
20
+ # === Options
21
+ #
22
+ # [:merchant_id]
23
+ # The merchant id of your Beanstream account. This is required. You can specify this in
24
+ # the beanstreamy initializer file
25
+ # [:hash_key]
26
+ # The key used for SHA1 hash validation. You can specify this in the beanstreamy initializer file
27
+ # [:skip_hash]
28
+ # If +true+, turn off hash validation. Default is +false+.
29
+ # [:approved_url]
30
+ # The url that beanstream will redirect to for approved transactions
31
+ # [:declined_url]
32
+ # The url that beanstream will redirect to for declined transactions
33
+ # [:error_url]
34
+ # The url that beanstream will redirect to when there's validation errors with any of the submitted fields
35
+ # [:options]
36
+ # A hash of extra gateway parameters such as billing address and subtotals. Uses the same
37
+ # format as gateway options in ActiveMerchant. You'll most likely want to specify the +:order_id+ option
38
+ # at a minimum.
39
+ #
40
+ # === Example
41
+ #
42
+ # <%= beanstream_hosted_payment_form 3456, :merchant_id => 454353534, :hash_key => "FK49Clk34Jd",
43
+ # :options => {
44
+ # :order_id => "R5564396848",
45
+ # :email => "customer@example.com",
46
+ # :billing_address => {
47
+ # :name => "Reginald DeBillings",
48
+ # :address1 => "15 Over There Rd",
49
+ # :city => "Somecity",
50
+ # :province => "AB",
51
+ # :country => "CA",
52
+ # :postal_code => "T6G1K7"
53
+ # }
54
+ # } %>
55
+ # # Render fields needed for CC info
56
+ # <% end -%>
57
+ #
58
+ # In this example, it is assumed the billing information has been captured in a previous step. If you wanted to
59
+ # capture both billing information along with the CC info in one step, you would exclude it from the +:options+
60
+ # and render the appropriate fields.
61
+ #
62
+ # === TODO
63
+ #
64
+ # For rendered inputs, you need to specify the exact parameter names that Beanstream
65
+ # expects (e.g. +trnCardNumber+). There should be some extra helper methods that abstracts these to be
66
+ # similar to the +options+ hash.
67
+ def beanstream_hosted_payment_form(amount, options = {}, &block)
68
+ amount = Util.amount(amount) # convert from cents to dollars
8
69
 
9
- order_id = options.delete(:order_id) or raise("Missing order id")
10
- amount = options.delete(:amount) or raise("Missing amount")
11
70
  merchant_id = options.delete(:merchant_id) || config.merchant_id
12
71
  hash_key = options.delete(:hash_key) || config.hash_key
72
+ skip_hash = options.delete(:skip_hash)
73
+
13
74
  approved_url = options.delete(:approved_url) || config.approved_url
14
75
  declined_url = options.delete(:declined_url) || config.declined_url
15
76
  error_url = options.delete(:error_url)
16
77
 
17
- skip_hash = options.delete(:skip_hash)
78
+ gateway_options = options.delete(:options) || {}
79
+ gateway_params = {}
80
+ Util.add_address(gateway_params, gateway_options)
81
+ Util.add_invoice(gateway_params, gateway_options)
82
+
18
83
  extra_params = options.delete(:params)
19
84
 
85
+ # construct the parameter list
20
86
  hashed_params = [["merchant_id", merchant_id],
21
- ["trnOrderNumber", order_id],
22
87
  ["trnAmount", amount]]
23
88
  hashed_params << ["approvedPage", approved_url] if approved_url.present?
24
89
  hashed_params << ["declinedPage", declined_url] if declined_url.present?
@@ -28,18 +93,19 @@ module Beanstreamy
28
93
  hashed_params << ["hashExpiry", Util.hash_expiry(expire_at)]
29
94
  end
30
95
 
96
+ hashed_params += Array(gateway_params)
31
97
  hashed_params += Array(extra_params)
32
98
 
33
99
  form = content_tag(:form, options.merge(:action => config.payment_url, :method => "post")) do
34
100
  hashed_params.each do |key, value|
35
- concat hidden_field_tag(key, value)
101
+ concat hidden_field_tag(key, value) if value
36
102
  end
37
103
 
38
104
  hash_value = nil
39
105
  if hash_key.present? && !skip_hash
40
106
  # Beansream's hosted page uses hash validation to prevent price modification. This hash is computed from
41
107
  # the url encoded string of the above inputs
42
- query_string = hashed_params.reject { |k,v| v.blank? }.map { |k,v| v.to_query(k) }.join('&')
108
+ query_string = hashed_params.reject { |k,v| !v }.map { |k,v| v.to_query(k) }.join('&')
43
109
  hash_value = Util.hash_value(hash_key, query_string)
44
110
 
45
111
  concat hidden_field_tag("hashValue", hash_value)
@@ -1,13 +1,67 @@
1
1
  module Beanstreamy
2
2
  module Util
3
+
3
4
  def self.hash_value(key, message)
4
5
  Digest::SHA1.hexdigest(message + key)
5
6
  end
6
7
 
8
+ def self.amount(cents)
9
+ sprintf("%.2f", cents.to_f / 100)
10
+ end
11
+
7
12
  def self.hash_expiry(expire_at)
8
13
  # Beanstream uses PST/PDT for all their timestamps. Time stamps only have minute resolution,
9
14
  # so the seconds need chopping off.
10
15
  expire_at.in_time_zone("Pacific Time (US & Canada)").to_s(:number)[0..-3]
11
16
  end
17
+
18
+ def self.add_address(params, options)
19
+ prepare_address_for_non_american_countries(options)
20
+
21
+ if billing_address = options[:billing_address] || options[:address]
22
+ params[:ordName] = billing_address[:name]
23
+ params[:ordEmailAddress] = options[:email]
24
+ params[:ordPhoneNumber] = billing_address[:phone]
25
+ params[:ordAddress1] = billing_address[:address1]
26
+ params[:ordAddress2] = billing_address[:address2]
27
+ params[:ordCity] = billing_address[:city]
28
+ params[:ordProvince] = billing_address[:province] || billing_address[:state]
29
+ params[:ordPostalCode] = billing_address[:postal_code] || billing_address[:zip]
30
+ params[:ordCountry] = billing_address[:country]
31
+ end
32
+
33
+ if shipping_address = options[:shipping_address]
34
+ params[:shipName] = shipping_address[:name]
35
+ params[:shipEmailAddress] = options[:email]
36
+ params[:shipPhoneNumber] = shipping_address[:phone]
37
+ params[:shipAddress1] = shipping_address[:address1]
38
+ params[:shipAddress2] = shipping_address[:address2]
39
+ params[:shipCity] = shipping_address[:city]
40
+ params[:shipProvince] = shipping_address[:province] || shipping_address[:state]
41
+ params[:shipPostalCode] = shipping_address[:postal_code] || shipping_address[:zip]
42
+ params[:shipCountry] = shipping_address[:country]
43
+ params[:shippingMethod] = shipping_address[:shipping_method]
44
+ params[:deliveryEstimate] = shipping_address[:delivery_estimate]
45
+ end
46
+ end
47
+
48
+ def self.prepare_address_for_non_american_countries(options)
49
+ [ options[:billing_address], options[:shipping_address] ].compact.each do |address|
50
+ unless ['US', 'CA'].include?(address[:country])
51
+ address[:province] = '--'
52
+ address[:postal_code] = '000000' unless address[:postal_code] || address[:zip]
53
+ end
54
+ end
55
+ end
56
+
57
+ def self.add_invoice(params, options)
58
+ params[:trnOrderNumber] = options[:order_id]
59
+ params[:trnComments] = options[:description]
60
+ params[:ordItemPrice] = amount(options[:subtotal])
61
+ params[:ordShippingPrice] = amount(options[:shipping])
62
+ params[:ordTax1Price] = amount(options[:tax1] || options[:tax])
63
+ params[:ordTax2Price] = amount(options[:tax2])
64
+ params[:ref1] = options[:custom]
65
+ end
12
66
  end
13
67
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 2
8
- - 1
9
- version: 0.2.1
8
+ - 2
9
+ version: 0.2.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Jeff Siegel
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-07-09 00:00:00 -06:00
17
+ date: 2010-07-12 00:00:00 -06:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency