beanstreamy 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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