activemerchant 1.42.4 → 1.42.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NThjMjQ4YWE3M2Y3MGUyM2UzMDg2MWQ3ZjJjYjNiMzAyNzUxNTUyYw==
4
+ ZjExMzYzY2FiZmNmZDE1YWI2M2VhMTU5YzY4MGM2N2FkMGEwMDQzMQ==
5
5
  data.tar.gz: !binary |-
6
- ZTVkZDAwNWUyOGIwZGJmYzQxMmRmOWQ0YTdjODQ1Y2RkZTYxOGU3NA==
6
+ MDAyMGFkMTU4MmU1MmJhOWJkNjQxYjNkNTIxODFlZjA0NWZiZTBlYw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MjBkOGY2OTgzZTg3YzU5YmEwMzQwZjI3ODM2MTcwZDdmODBlYTExMjRiNTVi
10
- YzYyMDdlNThkYjBhNTBhMWFjZWM0ZTdkODVlYTI1NGVjNTdjMWU3ZTg1YmYx
11
- NTVjYjE5ZTA1ZDYyNDgzYTE2NDY1MDY2NDMyOGQ4ZDRmM2E5OWI=
9
+ ZDBiZmExZjY3ZGI2OTk4ZjAwNDI2ZDk0ZWUyZjA2NWY2ODQxNWRmMWVlYTA1
10
+ MzZhOTQ4YTJlYjlmNTRhOTRkNGM2OGM3MGJjNjI2ZWQwZmM5ODEzM2I3NjY1
11
+ NThlMTcxZjQ3OGNjMWRmNjIzMmVjYmVhYmFlNTcwZDhhYTJjMWU=
12
12
  data.tar.gz: !binary |-
13
- MmMwZDg4OGJmNzFlOTI4N2ZlNjczYWRkY2ZjM2ZiOGIzZTBmNGQ1M2VkZGRj
14
- MWZjOGU0YjEyMDRhMmZmYzBiMDBhMmFmMGNiM2JkMjQ1MDUxMGE4NTc5NDVm
15
- NWYyZGI1NWYzZmMzYzgyNTBjZDkyMDc2NTVhMzJmYWE2ZWYxZTY=
13
+ YzNmOGJiMDZmMjJlZjY3OWU0MWQ5NzM4M2M1NzI4ZmQ3OTNjNjI1ZmE0MzYz
14
+ ZjRjNjdlZGNkNTc3M2YxMjFjYWQyMmJhMzZlYWM0MzhkMWVkMTdkNWNkZDM0
15
+ YWIyYWJhNWQyYzE4YTVkNGVjN2ZlOTgxMzZiYWRlMmU1NTgzNWY=
Binary file
data.tar.gz.sig CHANGED
Binary file
data/CHANGELOG CHANGED
@@ -1,5 +1,10 @@
1
1
  = ActiveMerchant CHANGELOG
2
2
 
3
+ == Version 1.42.5 (February 7th, 2014)
4
+
5
+ * Add Doku Indonesia [bizla]
6
+ * Cardstream: Update gateway to use latest API [odorcicd]
7
+
3
8
  == Version 1.42.4 (January 8th, 2014)
4
9
 
5
10
  * DataCash: Set 'ecomm' as capturemethod [DavidGeukers]
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Active Merchant
2
- [![Build Status](https://secure.travis-ci.org/Shopify/active_merchant.png)](http://travis-ci.org/Shopify/active_merchant)
2
+ [![Build Status](https://travis-ci.org/Shopify/active_merchant.png?branch=master)](https://travis-ci.org/Shopify/active_merchant)
3
3
  [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/Shopify/active_merchant)
4
4
 
5
5
  Active Merchant is an extraction from the e-commerce system [Shopify](http://www.shopify.com).
@@ -201,6 +201,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
201
201
  * [DirecPay](http://www.timesofmoney.com/direcpay/jsp/home.jsp)
202
202
  * [Direct-eBanking / sofortueberweisung.de by Payment-Networks AG](https://www.payment-network.com/deb_com_en/merchantarea/home) - DE, AT, CH, BE, UK, NL
203
203
  * [Dotpay](http://dotpay.pl)
204
+ * [Doku](http://doku.com)
204
205
  * [Dwolla](https://www.dwolla.com/default.aspx)
205
206
  * [ePay](http://www.epay.dk/epay-payment-solutions/)
206
207
  * [First Data](https://firstdata.zendesk.com/entries/407522-first-data-global-gateway-e4sm-payment-pages-integration-manual)
@@ -62,7 +62,7 @@ module ActiveMerchant #:nodoc:
62
62
  include Utils
63
63
 
64
64
  DEBIT_CARDS = [ :switch, :solo ]
65
- CURRENCIES_WITHOUT_FRACTIONS = [ 'JPY', 'HUF', 'TWD', 'ISK' ]
65
+ CURRENCIES_WITHOUT_FRACTIONS = [ 'BIF', 'BYR', 'CLP', 'CVE', 'DJF', 'GNF', 'HUF', 'ISK', 'JPY', 'KMF', 'KRW', 'PYG', 'RWF', 'TWD', 'UGX', 'VND', 'VUV', 'XAF', 'XOF', 'XPF' ]
66
66
  CREDIT_DEPRECATION_MESSAGE = "Support for using credit to refund existing transactions is deprecated and will be removed from a future release of ActiveMerchant. Please use the refund method instead."
67
67
 
68
68
  cattr_reader :implementations
@@ -1,55 +1,29 @@
1
1
  module ActiveMerchant #:nodoc:
2
2
  module Billing #:nodoc:
3
- #
4
- # CardStream supports the following credit cards, which are auto-detected by
5
- # the gateway based on the card number used:
6
- # * AM American Express
7
- # * Diners Club
8
- # * Electron
9
- # * JCB
10
- # * UK Maestro
11
- # * Maestro International
12
- # * Mastercard
13
- # * Solo
14
- # * Style
15
- # * Switch
16
- # * Visa Credit
17
- # * Visa Debit
18
- # * Visa Purchasing
19
- #
20
3
  class CardStreamGateway < Gateway
21
- self.live_url = self.test_url = 'https://gateway.cardstream.com/process.ashx'
22
-
4
+ self.test_url = self.live_url = 'https://gateway.cardstream.com/direct/'
23
5
  self.money_format = :cents
24
6
  self.default_currency = 'GBP'
25
- self.supported_countries = ['GB']
7
+ self.supported_countries = ['GB', 'USD', 'EUR', 'CHF', 'SEK', 'SGD', 'NOK', 'JPY', 'ICK', 'HKD', 'DKK', 'CZK', 'CAD', 'AUD']
26
8
  self.supported_cardtypes = [:visa, :master, :american_express, :diners_club, :discover, :jcb, :maestro, :solo, :switch]
27
9
  self.homepage_url = 'http://www.cardstream.com/'
28
10
  self.display_name = 'CardStream'
29
11
 
30
- APPROVED = '00'
31
-
32
12
  CURRENCY_CODES = {
33
- "AUD"=> '036',
34
- "CAD"=> '124',
35
- "CZK"=> '203',
36
- "DKK"=> '208',
37
- "HKD"=> '344',
38
- "ICK"=> '352',
39
- "JPY"=> '392',
40
- "NOK"=> '578',
41
- "SGD"=> '702',
42
- "SEK"=> '752',
43
- "CHF"=> '756',
44
- "GBP"=> '826',
45
- "USD"=> '840',
46
- "EUR"=> '978'
47
- }
48
-
49
- TRANSACTIONS = {
50
- :purchase => 'ESALE_KEYED',
51
- :refund => 'EREFUND_KEYED',
52
- :authorization => 'ESALE_KEYED'
13
+ "AUD" => '036',
14
+ "CAD" => '124',
15
+ "CZK" => '203',
16
+ "DKK" => '208',
17
+ "HKD" => '344',
18
+ "ICK" => '352',
19
+ "JPY" => '392',
20
+ "NOK" => '578',
21
+ "SGD" => '702',
22
+ "SEK" => '752',
23
+ "CHF" => '756',
24
+ "GBP" => '826',
25
+ "USD" => '840',
26
+ "EUR" => '978'
53
27
  }
54
28
 
55
29
  CVV_CODE = {
@@ -86,136 +60,158 @@ module ActiveMerchant #:nodoc:
86
60
  }
87
61
 
88
62
  def initialize(options = {})
89
- requires!(options, :login, :password)
63
+ requires!(options, :login, :shared_secret)
64
+ if (options[:threeDSRequired])
65
+ @threeDSRequired = options[:threeDSRequired]
66
+ else
67
+ @threeDSRequired = 'N'
68
+ end
90
69
  super
91
70
  end
92
71
 
93
- def purchase(money, credit_card, options = {})
94
- requires!(options, :order_id)
95
-
72
+ def authorize(money, creditcard, options = {})
96
73
  post = {}
74
+ add_amount(post, money, options)
75
+ add_invoice(post, creditcard, money, options)
76
+ add_creditcard(post, creditcard)
77
+ add_address(post, creditcard, options)
78
+ add_customer_data(post, options)
79
+ commit('PREAUTH', post)
80
+ end
97
81
 
82
+ def purchase(money, creditcard, options = {})
83
+ post = {}
98
84
  add_amount(post, money, options)
99
- add_invoice(post, money, credit_card, options)
100
- add_credit_card(post, credit_card)
101
- add_address(post, options)
85
+ add_invoice(post, creditcard, money, options)
86
+ add_creditcard(post, creditcard)
87
+ add_address(post, creditcard, options)
102
88
  add_customer_data(post, options)
89
+ commit('SALE', post)
90
+ end
103
91
 
104
- commit(:purchase, post)
92
+ def capture(money, authorization, options = {})
93
+ post = {}
94
+ add_pair(post, :xref, authorization)
95
+ add_amount(post, money, options)
96
+ commit('SALE', post)
97
+ end
98
+
99
+ def refund(money, authorization, options = {})
100
+ post = {}
101
+ add_pair(post, :xref, authorization)
102
+ add_amount(post, money, options)
103
+ commit('REFUND', post)
104
+ end
105
+
106
+ def void(authorization, options = {})
107
+ post = {}
108
+ add_pair(post, :xref, authorization)
109
+ commit('REFUND', post)
105
110
  end
106
111
 
107
112
  private
108
113
 
109
114
  def add_amount(post, money, options)
110
- add_pair(post, :Amount, amount(money), :required => true)
111
- add_pair(post, :CurrencyCode, currency_code(options[:currency] || currency(money)), :required => true)
115
+ add_pair(post, :amount, amount(money), :required => true)
116
+ add_pair(post, :currencyCode, currency_code(options[:currency] || currency(money)) || currency_code(self.default_currency))
112
117
  end
113
118
 
114
119
  def add_customer_data(post, options)
115
- add_pair(post, :BillingEmail, options[:email])
116
- add_pair(post, :BillingPhoneNumber, options[:phone])
120
+ address = options[:billing_address] || options[:address]
121
+ add_pair(post, :customerPostCode, address[:zip])
122
+ add_pair(post, :customerEmail, options[:email])
123
+ add_pair(post, :customerPhone, options[:phone])
117
124
  end
118
125
 
119
- def add_address(post, options)
126
+ def add_address(post, creditcard, options)
120
127
  address = options[:billing_address] || options[:address]
121
128
 
122
129
  return if address.nil?
123
130
 
124
- add_pair(post, :BillingStreet, address[:address1])
125
- add_pair(post, :BillingHouseNumber, address[:address2])
126
- add_pair(post, :BillingCity, address[:city])
127
- add_pair(post, :BillingState, address[:state])
128
- add_pair(post, :BillingPostCode, address[:zip])
131
+ add_pair(post, :customerAddress, address[:address1] + " " + (address[:address2].nil? ? "" : address[:address2]))
132
+ add_pair(post, :customerPostCode, address[:zip])
129
133
  end
130
134
 
131
- def add_invoice(post, money, credit_card, options)
132
- add_pair(post, :TransactionUnique, options[:order_id], :required => true)
133
- add_pair(post, :OrderDesc, options[:description] || options[:order_id], :required => true)
134
-
135
- if [ 'american_express', 'diners_club' ].include?(card_brand(credit_card).to_s)
136
- add_pair(post, :AEIT1Quantity, 1)
137
- add_pair(post, :AEIT1Description, (options[:description] || options[:order_id]).slice(0, 15))
138
- add_pair(post, :AEIT1GrossValue, amount(money))
135
+ def add_invoice(post, credit_card, money, options)
136
+ add_pair(post, :transactionUnique, options[:order_id], :required => true)
137
+ add_pair(post, :orderRef, options[:description] || options[:order_id], :required => true)
138
+ if ['american_express', 'diners_club'].include?(card_brand(credit_card).to_s)
139
+ add_pair(post, :item1Quantity, 1)
140
+ add_pair(post, :item1Description, (options[:description] || options[:order_id]).slice(0, 15))
141
+ add_pair(post, :item1GrossValue, amount(money))
139
142
  end
140
143
  end
141
144
 
142
- def add_credit_card(post, credit_card)
143
- add_pair(post, :CardName, credit_card.name, :required => true)
144
- add_pair(post, :CardNumber, credit_card.number, :required => true)
145
+ def add_creditcard(post, credit_card)
146
+ add_pair(post, :customerName, credit_card.name, :required => true)
147
+ add_pair(post, :cardNumber, credit_card.number, :required => true)
145
148
 
146
- add_pair(post, :ExpiryDateMM, format(credit_card.month, :two_digits), :required => true)
147
- add_pair(post, :ExpiryDateYY, format(credit_card.year, :two_digits), :required => true)
149
+ add_pair(post, :cardExpiryMonth, format(credit_card.month, :two_digits), :required => true)
150
+ add_pair(post, :cardExpiryYear, format(credit_card.year, :two_digits), :required => true)
148
151
 
149
152
  if requires_start_date_or_issue_number?(credit_card)
150
- add_pair(post, :StartDateMM, format(credit_card.start_month, :two_digits))
151
- add_pair(post, :StartDateYY, format(credit_card.start_year, :two_digits))
153
+ add_pair(post, :cardStartMonth, format(credit_card.start_month, :two_digits))
154
+ add_pair(post, :cardStartYear, format(credit_card.start_year, :two_digits))
152
155
 
153
- add_pair(post, :IssueNumber, credit_card.issue_number)
156
+ add_pair(post, :cardIssueNumber, credit_card.issue_number)
154
157
  end
155
158
 
156
- add_pair(post, :CV2, credit_card.verification_value)
159
+ add_pair(post, :cardCVV, credit_card.verification_value)
157
160
  end
158
161
 
159
- def commit(action, parameters)
160
- response = parse( ssl_post(self.live_url, post_data(action, parameters)) )
161
-
162
- Response.new(response[:response_code] == APPROVED, message_from(response), response,
163
- :test => test?,
164
- :authorization => response[:cross_reference],
165
- :cvv_result => CVV_CODE[ response[:avscv2_response_code].to_s[0, 1] ],
166
- :avs_result => {
167
- :street_match => AVS_STREET_MATCH[ response[:avscv2_response_code].to_s[2, 1] ],
168
- :postal_match => AVS_POSTAL_MATCH[ response[:avscv2_response_code].to_s[1, 1] ]
169
- }
170
- )
171
- end
162
+ def add_hmac(post)
163
+ result = post.sort.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
164
+ result = Digest::SHA512.hexdigest("#{result}#{@options[:shared_secret]}")
172
165
 
173
- def message_from(results)
174
- results[:response_code] == APPROVED ? "APPROVED" : results[:message]
166
+ add_pair(post, :signature, result)
175
167
  end
176
168
 
177
- def post_data(action, parameters = {})
178
- parameters.update(
179
- :MerchantPassword => @options[:password],
180
- :MerchantID => @options[:login],
181
- :MessageType => TRANSACTIONS[action],
182
- :CallBack => "disable",
183
- :DuplicateDelay => "0",
184
- :EchoCardType => "YES",
185
- :EchoAmount => "YES",
186
- :EchoAVSCV2ResponseCode => "YES",
187
- :ReturnAVSCV2Message => "YES",
188
- :CountryCode => '826' # 826 for UK based merchant
189
- )
190
-
191
- add_pair(parameters, :Dispatch, action == :authorization ? "LATER" : "NOW")
192
-
193
- parameters.collect { |key, value| "VP#{key}=#{CGI.escape(value.to_s)}" }.join("&")
194
- end
195
-
196
- # VPCrossReference
197
- # The value in VPCrossReference on a success transaction will contain
198
- # a unique reference that you may use to run future transactions.
199
- # Please note that cross reference transactions must come a static IP
200
- # addressed that has been pre-registered with Cardstream. To
201
- # register an IP address please send it to support@cardstream.com
202
- # with your Cardstream issued merchant ID and it will be added to
203
- # your account.
204
169
  def parse(body)
205
170
  result = {}
206
171
  pairs = body.split("&")
207
172
  pairs.each do |pair|
208
173
  a = pair.split("=")
209
- result[a[0].gsub(/^VP/,'').underscore.to_sym] = a[1]
174
+ # because some values pairs dont have a value
175
+ result[a[0].to_sym] = a[1] == nil ? '' : CGI.unescape(a[1])
210
176
  end
211
-
212
177
  result
213
178
  end
214
179
 
180
+ def commit(action, parameters)
181
+
182
+ parameters.update(
183
+ :merchantID => @options[:login],
184
+ :action => action,
185
+ :type => '1', #Ecommerce
186
+ :countryCode => self.supported_countries[0],
187
+ :threeDSRequired => @threeDSRequired #Disable 3d secure by default
188
+ )
189
+ # adds a signature to the post hash/array
190
+ add_hmac(parameters)
191
+
192
+ response = parse(ssl_post(self.live_url, post_data(action, parameters)))
193
+
194
+ Response.new(response[:responseCode] == "0",
195
+ response[:responseCode] == "0" ? "APPROVED" : response[:responseMessage],
196
+ response,
197
+ :test => test?,
198
+ :authorization => response[:xref],
199
+ :cvv_result => CVV_CODE[response[:avscv2ResponseCode].to_s[0, 1]],
200
+ :avs_result => {
201
+ :postal_match => AVS_POSTAL_MATCH[response[:avscv2ResponseCode].to_s[1, 1]],
202
+ :street_match => AVS_STREET_MATCH[response[:avscv2ResponseCode].to_s[2, 1]]
203
+ }
204
+ )
205
+ end
206
+
215
207
  def currency_code(currency)
216
208
  CURRENCY_CODES[currency]
217
209
  end
218
210
 
211
+ def post_data(action, parameters = {})
212
+ parameters.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
213
+ end
214
+
219
215
  def add_pair(post, key, value, options = {})
220
216
  post[key] = value if !value.blank? || options[:required]
221
217
  end
@@ -201,7 +201,7 @@ module ActiveMerchant #:nodoc:
201
201
  raise unless options[:order_timestamp]
202
202
  amount = @fields['x_amount']
203
203
  data = "#{@fields['x_login']}^#{@fields['x_fp_sequence']}^#{options[:order_timestamp].to_i}^#{amount}^#{@fields['x_currency_code']}"
204
- hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('md5'), options[:transaction_key], data)
204
+ hmac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('md5'), options[:transaction_key], data)
205
205
  add_field 'x_fp_hash', hmac
206
206
  add_field 'x_fp_timestamp', options[:order_timestamp].to_i
207
207
  end
@@ -42,7 +42,7 @@ module ActiveMerchant
42
42
  end
43
43
 
44
44
  def self.checksum(secret_key, payload_items )
45
- digest = OpenSSL::Digest::Digest.new('sha1')
45
+ digest = OpenSSL::Digest.new('sha1')
46
46
  OpenSSL::HMAC.hexdigest(digest, secret_key, payload_items)
47
47
  end
48
48
  end
@@ -0,0 +1,24 @@
1
+ require File.dirname(__FILE__) + '/doku/helper.rb'
2
+ require File.dirname(__FILE__) + '/doku/notification.rb'
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ module Integrations #:nodoc:
7
+ module Doku
8
+
9
+ def self.service_url
10
+ 'https://apps.myshortcart.com/payment/request-payment/'
11
+ end
12
+
13
+ def self.notification(post, options = {})
14
+ Notification.new(post, options)
15
+ end
16
+
17
+ def self.return(post, options = {})
18
+ Return.new(post, options)
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,102 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module Integrations #:nodoc:
4
+ module Doku
5
+
6
+ # # Example.
7
+ #
8
+ # payment_service_for('ORDER_ID', 'DOKU_STORE_ID', :service => :doku, :amount => 155_000, :shared_key => 'DOKU_SHARED_KEY') do |service|
9
+ #
10
+ # service.customer :name => 'Ismail Danuarta',
11
+ # :email => 'ismail.danuarta@gmail.com',
12
+ # :mobile_phone => '085779280093',
13
+ # :working_phone => '0215150555',
14
+ # :home_phone => '0215150555',
15
+ # :birth_date => '1991-09-11'
16
+ #
17
+ # service.billing_address :city => 'Jakarta Selatan',
18
+ # :address => 'Jl. Jendral Sudirman kav 59, Plaza Asia Office Park Unit 3',
19
+ # :state => 'DKI Jakarta',
20
+ # :zip => '12190',
21
+ # :country => 'ID'
22
+
23
+ # service.shipping_address :city => 'Jakarta',
24
+ # :address => 'Jl. Jendral Sudirman kav 59, Plaza Asia Office Park Unit 3',
25
+ # :state => 'DKI Jakarta',
26
+ # :zip => '12190',
27
+ # :country => 'ID'
28
+ #
29
+ # service.url 'http://yourstore.com'
30
+ #
31
+ # end
32
+ #
33
+
34
+ class Helper < ActiveMerchant::Billing::Integrations::Helper
35
+ def initialize(order, account, options = {})
36
+ @shared_key = options.delete(:credential2)
37
+ @transidmerchant = order
38
+ super
39
+ end
40
+
41
+ def form_fields
42
+ add_field 'WORDS', words
43
+ add_field 'BASKET', basket
44
+ add_field 'TRANSIDMERCHANT', @transidmerchant
45
+ @fields
46
+ end
47
+
48
+ def customer(params = {})
49
+ add_field mappings[:customer][:name], "#{params[:first_name]} #{params[:last_name]}"
50
+ add_field mappings[:customer][:email], params[:email]
51
+ add_field mappings[:customer][:phone], params[:phone]
52
+ add_field mappings[:customer][:mobile_phone], params[:mobile_phone]
53
+ add_field mappings[:customer][:working_phone], params[:working_phone]
54
+ add_field mappings[:customer][:birth_date], params[:birth_date]
55
+ end
56
+
57
+ mapping :account, 'STOREID'
58
+ mapping :amount, 'AMOUNT'
59
+ mapping :cancel_return_url, 'URL'
60
+
61
+
62
+ mapping :customer, :name => 'CNAME',
63
+ :email => 'CEMAIL',
64
+ :phone => 'CHPHONE',
65
+ :mobile_phone => 'CMPHONE',
66
+ :working_phone => 'CWPHONE',
67
+ :birth_date => 'BIRTHDATE'
68
+
69
+ mapping :billing_address, :city => 'CCITY',
70
+ :address1 => 'CADDRESS',
71
+ :state => 'CSTATE',
72
+ :zip => 'CZIPCODE',
73
+ :country => 'CCOUNTRY'
74
+
75
+ mapping :shipping_address, :city => 'SCITY',
76
+ :address1 => 'SADDRESS',
77
+ :state => 'SSTATE',
78
+ :zip => 'SZIPCODE',
79
+ :country => 'SCOUNTRY'
80
+ private
81
+
82
+ def basket
83
+ "Checkout #{@transidmerchant},#{@fields['AMOUNT']},1,#{@fields['AMOUNT']}"
84
+ end
85
+
86
+ def words
87
+ @words ||= Digest::SHA1.hexdigest("#{ @fields['AMOUNT'] }#{ @shared_key }#{ @transidmerchant }")
88
+ end
89
+
90
+ def add_address(key, params)
91
+ return if mappings[key].nil?
92
+
93
+ code = lookup_country_code(params.delete(:country), :numeric)
94
+ add_field(mappings[key][:country], code)
95
+ add_fields(key, params)
96
+ end
97
+
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end