activemerchant 1.11.0 → 1.12.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +3 -1
- data/CHANGELOG +17 -0
- data/CONTRIBUTORS +16 -0
- data/README.rdoc +5 -0
- data/lib/active_merchant.rb +0 -1
- data/lib/active_merchant/billing/gateway.rb +1 -1
- data/lib/active_merchant/billing/gateways/authorize_net.rb +5 -2
- data/lib/active_merchant/billing/gateways/federated_canada.rb +169 -0
- data/lib/active_merchant/billing/gateways/garanti.rb +13 -1
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +4 -4
- data/lib/active_merchant/billing/gateways/nmi.rb +13 -0
- data/lib/active_merchant/billing/gateways/pay_junction.rb +8 -8
- data/lib/active_merchant/billing/gateways/paybox_direct.rb +3 -4
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +2 -2
- data/lib/active_merchant/billing/gateways/paypal_express.rb +37 -5
- data/lib/active_merchant/billing/gateways/qbms.rb +290 -0
- data/lib/active_merchant/billing/integrations/direc_pay/helper.rb +25 -21
- data/lib/active_merchant/billing/integrations/moneybookers.rb +23 -0
- data/lib/active_merchant/billing/integrations/moneybookers/helper.rb +33 -0
- data/lib/active_merchant/billing/integrations/moneybookers/notification.rb +101 -0
- data/lib/active_merchant/billing/integrations/valitor/helper.rb +5 -1
- data/lib/active_merchant/billing/integrations/world_pay.rb +34 -0
- data/lib/active_merchant/billing/integrations/world_pay/helper.rb +100 -0
- data/lib/active_merchant/billing/integrations/world_pay/notification.rb +160 -0
- data/lib/active_merchant/version.rb +1 -1
- metadata +13 -4
- metadata.gz.sig +0 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
module Integrations #:nodoc:
|
4
|
+
module Moneybookers
|
5
|
+
|
6
|
+
autoload :Notification, File.dirname(__FILE__) + '/moneybookers/notification.rb'
|
7
|
+
autoload :Helper, File.dirname(__FILE__) + '/moneybookers/helper.rb'
|
8
|
+
|
9
|
+
mattr_accessor :production_url
|
10
|
+
self.production_url = 'https://www.moneybookers.com/app/payment.pl'
|
11
|
+
|
12
|
+
def self.service_url
|
13
|
+
self.production_url
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.notification(post)
|
17
|
+
Notification.new(post)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
module Integrations #:nodoc:
|
4
|
+
module Moneybookers
|
5
|
+
class Helper < ActiveMerchant::Billing::Integrations::Helper
|
6
|
+
mapping :account, 'pay_to_email'
|
7
|
+
mapping :order, 'transaction_id'
|
8
|
+
mapping :amount, 'amount'
|
9
|
+
mapping :currency, 'currency'
|
10
|
+
|
11
|
+
mapping :customer,
|
12
|
+
:first_name => 'firstname',
|
13
|
+
:last_name => 'lastname',
|
14
|
+
:email => 'pay_from_email',
|
15
|
+
:phone => 'phone_number'
|
16
|
+
|
17
|
+
mapping :billing_address,
|
18
|
+
:city => 'city',
|
19
|
+
:address1 => 'address',
|
20
|
+
:address2 => 'address2',
|
21
|
+
:state => 'state',
|
22
|
+
:zip => 'postal_code',
|
23
|
+
:country => 'country'
|
24
|
+
|
25
|
+
mapping :notify_url, 'status_url'
|
26
|
+
mapping :return_url, 'return_url'
|
27
|
+
mapping :cancel_return_url, 'cancel_url'
|
28
|
+
mapping :description, 'detail1_text'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'digest/md5'
|
3
|
+
|
4
|
+
module ActiveMerchant #:nodoc:
|
5
|
+
module Billing #:nodoc:
|
6
|
+
module Integrations #:nodoc:
|
7
|
+
module Moneybookers
|
8
|
+
class Notification < ActiveMerchant::Billing::Integrations::Notification
|
9
|
+
include PostsData
|
10
|
+
|
11
|
+
# was the transaction comlete?
|
12
|
+
def complete?
|
13
|
+
status == "2"
|
14
|
+
end
|
15
|
+
|
16
|
+
def status
|
17
|
+
params['status']
|
18
|
+
end
|
19
|
+
|
20
|
+
def item_id
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def transaction_id
|
25
|
+
if params.has_key?("transaction_id")
|
26
|
+
params['transaction_id']
|
27
|
+
else
|
28
|
+
params['mb_transaction_id']
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# When was this payment received by the client.
|
33
|
+
def received_at
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def payer_email
|
38
|
+
params['pay_from_email']
|
39
|
+
end
|
40
|
+
|
41
|
+
def receiver_email
|
42
|
+
params['pay_to_email']
|
43
|
+
end
|
44
|
+
|
45
|
+
def md5sig
|
46
|
+
params['md5sig']
|
47
|
+
end
|
48
|
+
|
49
|
+
#Unique ID from the merchant's Moneybookers.com account, needed for calculatinon of md5 sig
|
50
|
+
def merchant_id
|
51
|
+
params['merchant_id']
|
52
|
+
end
|
53
|
+
|
54
|
+
# currency of mb_amount, will always be the same as the currency of the beneficiary's account at Moneybookers.com
|
55
|
+
def currency
|
56
|
+
params['mb_currency']
|
57
|
+
end
|
58
|
+
|
59
|
+
# total amount of the payment in Merchants currency (ex 25.46/25.4/25)
|
60
|
+
def gross
|
61
|
+
params['mb_amount']
|
62
|
+
end
|
63
|
+
|
64
|
+
# currency of the payment as posted by the merchant on the entry form
|
65
|
+
def posted_currency
|
66
|
+
params['currency']
|
67
|
+
end
|
68
|
+
|
69
|
+
# amount of the payment as posted by the merchant on the entry form (ex. 39.60/39.6/39)
|
70
|
+
def posted_amount
|
71
|
+
params['amount']
|
72
|
+
end
|
73
|
+
|
74
|
+
# Was this a test transaction?
|
75
|
+
def test?
|
76
|
+
false
|
77
|
+
end
|
78
|
+
|
79
|
+
# Acknowledge the transaction to MoneyBooker. This method has to be called after a new
|
80
|
+
# apc arrives. It will verify that all the information we received is correct and will return a
|
81
|
+
# ok or a fail.
|
82
|
+
#
|
83
|
+
# Example:
|
84
|
+
#
|
85
|
+
# def ipn
|
86
|
+
# notify = Moneybookers::Notification.new(request.raw_post)
|
87
|
+
#
|
88
|
+
# if notify.acknowledge('secretpass')
|
89
|
+
# ... process order ... if notify.complete?
|
90
|
+
# else
|
91
|
+
# ... log possible hacking attempt ...
|
92
|
+
# end
|
93
|
+
def acknowledge(secret = '')
|
94
|
+
fields = [merchant_id, transaction_id, Digest::MD5.hexdigest(secret).upcase, gross, currency, status].join
|
95
|
+
md5sig == Digest::MD5.hexdigest(fields).upcase
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -50,7 +50,7 @@ module ActiveMerchant #:nodoc:
|
|
50
50
|
requires!(options, :amount, :description)
|
51
51
|
options.assert_valid_keys([:description, :quantity, :amount, :discount])
|
52
52
|
|
53
|
-
add_field("Vara_#{id}_Verd", options[:amount])
|
53
|
+
add_field("Vara_#{id}_Verd", format_amount(options[:amount]))
|
54
54
|
add_field("Vara_#{id}_Fjoldi", options[:quantity] || "1")
|
55
55
|
|
56
56
|
add_field("Vara_#{id}_Lysing", options[:description]) if options[:description]
|
@@ -75,6 +75,10 @@ module ActiveMerchant #:nodoc:
|
|
75
75
|
@fields[mappings[:success_text]] ||= DEFAULT_SUCCESS_TEXT
|
76
76
|
@fields.merge('RafraenUndirskrift' => signature)
|
77
77
|
end
|
78
|
+
|
79
|
+
def format_amount(amount)
|
80
|
+
amount.to_f.round
|
81
|
+
end
|
78
82
|
end
|
79
83
|
end
|
80
84
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/world_pay/helper.rb'
|
2
|
+
require File.dirname(__FILE__) + '/world_pay/notification.rb'
|
3
|
+
|
4
|
+
module ActiveMerchant #:nodoc:
|
5
|
+
module Billing #:nodoc:
|
6
|
+
module Integrations #:nodoc:
|
7
|
+
module WorldPay
|
8
|
+
|
9
|
+
mattr_accessor :service_url
|
10
|
+
self.service_url = 'https://select.worldpay.com/wcc/purchase'
|
11
|
+
|
12
|
+
mattr_accessor :test_url
|
13
|
+
self.test_url = 'https://select-test.worldpay.com/wcc/purchase'
|
14
|
+
|
15
|
+
|
16
|
+
def self.service_url
|
17
|
+
mode = ActiveMerchant::Billing::Base.integration_mode
|
18
|
+
case mode
|
19
|
+
when :production
|
20
|
+
production_url
|
21
|
+
when :test
|
22
|
+
test_url
|
23
|
+
else
|
24
|
+
raise StandardError, "Integration mode set to an invalid value: #{mode}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.notification(post)
|
29
|
+
Notification.new(post)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
module Integrations #:nodoc:
|
4
|
+
module WorldPay
|
5
|
+
class Helper < ActiveMerchant::Billing::Integrations::Helper
|
6
|
+
mapping :account, 'instId'
|
7
|
+
mapping :amount, 'amount'
|
8
|
+
mapping :order, 'cartId'
|
9
|
+
mapping :currency, 'currency'
|
10
|
+
|
11
|
+
mapping :customer, :email => 'email',
|
12
|
+
:phone => 'tel'
|
13
|
+
|
14
|
+
mapping :billing_address, :zip => 'postcode',
|
15
|
+
:country => 'country'
|
16
|
+
|
17
|
+
mapping :description, 'desc'
|
18
|
+
mapping :notify_url, 'MC_callback'
|
19
|
+
|
20
|
+
|
21
|
+
# WorldPay supports two different test modes - :always_succeed and :always_fail
|
22
|
+
def initialize(order, account, options = {})
|
23
|
+
super
|
24
|
+
|
25
|
+
if ActiveMerchant::Billing::Base.integration_mode == :test || options[:test]
|
26
|
+
test_mode = case options[:test]
|
27
|
+
when :always_fail
|
28
|
+
101
|
29
|
+
when false
|
30
|
+
0
|
31
|
+
else
|
32
|
+
100
|
33
|
+
end
|
34
|
+
add_field('testMode', test_mode.to_s)
|
35
|
+
elsif ActiveMerchant::Billing::Base.integration_mode == :always_succeed
|
36
|
+
add_field('testMode', '100')
|
37
|
+
elsif ActiveMerchant::Billing::Base.integration_mode == :always_fail
|
38
|
+
add_field('testMode', '101')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# WorldPay only supports a single address field so we
|
43
|
+
# have to concat together - lines are separated using
|
44
|
+
def billing_address(params={})
|
45
|
+
add_field(mappings[:billing_address][:zip], params[:zip])
|
46
|
+
add_field(mappings[:billing_address][:country], lookup_country_code(params[:country]))
|
47
|
+
|
48
|
+
address = [params[:address1], params[:address2], params[:city], params[:state]].compact
|
49
|
+
add_field('address', address.join(' '))
|
50
|
+
end
|
51
|
+
|
52
|
+
# WorldPay only supports a single name field so we have to concat
|
53
|
+
def customer(params={})
|
54
|
+
add_field(mappings[:customer][:email], params[:email])
|
55
|
+
add_field(mappings[:customer][:phone], params[:phone])
|
56
|
+
add_field('name', "#{params[:first_name]} #{params[:last_name]}")
|
57
|
+
end
|
58
|
+
|
59
|
+
# Support for a MD5 hash of selected fields to prevent tampering
|
60
|
+
# For futher information read the tech note at the address below:
|
61
|
+
# http://support.worldpay.com/kb/integration_guides/junior/integration/help/tech_notes/sjig_tn_009.html
|
62
|
+
def encrypt(secret, fields = [:amount, :currency, :account, :order])
|
63
|
+
signature_fields = fields.collect{ |field| mappings[field] }
|
64
|
+
add_field('signatureFields', signature_fields.join(':'))
|
65
|
+
|
66
|
+
field_values = fields.collect{ |field| form_fields[mappings[field]] }
|
67
|
+
signature = "#{secret}:#{field_values.join(':')}"
|
68
|
+
add_field('signature', Digest::MD5.hexdigest(signature))
|
69
|
+
end
|
70
|
+
|
71
|
+
# Add a time window for which the payment can be completed. Read the link below for how they work
|
72
|
+
# http://support.worldpay.com/kb/integration_guides/junior/integration/help/appendicies/sjig_10100.html
|
73
|
+
def valid_from(from_time)
|
74
|
+
add_field('authValidFrom', from_time.to_i.to_s + '000')
|
75
|
+
end
|
76
|
+
|
77
|
+
def valid_to(to_time)
|
78
|
+
add_field('authValidTo', to_time.to_i.to_s + '000')
|
79
|
+
end
|
80
|
+
|
81
|
+
# WorldPay supports the passing of custom parameters prefixed with the following:
|
82
|
+
# C_ : These parameters can be used in the response pages hosted on WorldPay's site
|
83
|
+
# M_ : These parameters are passed through to the callback script (if enabled)
|
84
|
+
# MC_ or CM_ : These parameters are availble both in the response and callback contexts
|
85
|
+
def response_params(params={})
|
86
|
+
params.each{|k,v| add_field("C_#{k}",v)}
|
87
|
+
end
|
88
|
+
|
89
|
+
def callback_params(params={})
|
90
|
+
params.each{|k,v| add_field("M_#{k}",v)}
|
91
|
+
end
|
92
|
+
|
93
|
+
def combined_params(params={})
|
94
|
+
params.each{|k,v| add_field("MC_#{k}",v)}
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
module Integrations #:nodoc:
|
4
|
+
module WorldPay
|
5
|
+
class Notification < ActiveMerchant::Billing::Integrations::Notification
|
6
|
+
def complete?
|
7
|
+
status == 'Completed'
|
8
|
+
end
|
9
|
+
|
10
|
+
def account
|
11
|
+
params['instId']
|
12
|
+
end
|
13
|
+
|
14
|
+
def item_id
|
15
|
+
params['cartId']
|
16
|
+
end
|
17
|
+
|
18
|
+
def transaction_id
|
19
|
+
params['transId']
|
20
|
+
end
|
21
|
+
|
22
|
+
# Time this payment was received by the client in UTC time.
|
23
|
+
def received_at
|
24
|
+
Time.at(params['transTime'].to_i / 1000).utc
|
25
|
+
end
|
26
|
+
|
27
|
+
# Callback password set in the WorldPay CMS
|
28
|
+
def security_key
|
29
|
+
params['callbackPW']
|
30
|
+
end
|
31
|
+
|
32
|
+
# the money amount we received in X.2 decimal.
|
33
|
+
def gross
|
34
|
+
params['authAmount']
|
35
|
+
end
|
36
|
+
|
37
|
+
def currency
|
38
|
+
params['authCurrency']
|
39
|
+
end
|
40
|
+
|
41
|
+
# Was this a test transaction?
|
42
|
+
def test?
|
43
|
+
params.key?('testMode') && params['testMode'] != '0'
|
44
|
+
end
|
45
|
+
|
46
|
+
def status
|
47
|
+
params['transStatus'] == 'Y' ? 'Completed' : 'Cancelled'
|
48
|
+
end
|
49
|
+
|
50
|
+
def name
|
51
|
+
params['name']
|
52
|
+
end
|
53
|
+
|
54
|
+
def address
|
55
|
+
params['address']
|
56
|
+
end
|
57
|
+
|
58
|
+
def postcode
|
59
|
+
params['postcode']
|
60
|
+
end
|
61
|
+
|
62
|
+
def country
|
63
|
+
params['country']
|
64
|
+
end
|
65
|
+
|
66
|
+
def phone_number
|
67
|
+
params['tel']
|
68
|
+
end
|
69
|
+
|
70
|
+
def fax_number
|
71
|
+
params['fax']
|
72
|
+
end
|
73
|
+
|
74
|
+
def email_address
|
75
|
+
params['email']
|
76
|
+
end
|
77
|
+
|
78
|
+
def card_type
|
79
|
+
params['cardType']
|
80
|
+
end
|
81
|
+
|
82
|
+
# WorldPay extended fraud checks returned as a 4 character string
|
83
|
+
# 1st char: Credit card CVV check
|
84
|
+
# 2nd char: Postcode AVS check
|
85
|
+
# 3rd char: Address AVS check
|
86
|
+
# 4th char: Country comparison check
|
87
|
+
# Possible values are:
|
88
|
+
# :not_supported - 0
|
89
|
+
# :not_checked - 1
|
90
|
+
# :matched - 2
|
91
|
+
# :not_matched - 4
|
92
|
+
# :partial_match - 8
|
93
|
+
def cvv_status
|
94
|
+
return avs_value_to_symbol(params['AVS'][0].chr)
|
95
|
+
end
|
96
|
+
|
97
|
+
def postcode_status
|
98
|
+
return avs_value_to_symbol(params['AVS'][1].chr)
|
99
|
+
end
|
100
|
+
|
101
|
+
def address_status
|
102
|
+
return avs_value_to_symbol(params['AVS'][2].chr)
|
103
|
+
end
|
104
|
+
|
105
|
+
def country_status
|
106
|
+
return avs_value_to_symbol(params['AVS'][3].chr)
|
107
|
+
end
|
108
|
+
|
109
|
+
def acknowledge
|
110
|
+
return true
|
111
|
+
end
|
112
|
+
|
113
|
+
# WorldPay supports the passing of custom parameters through to the callback script
|
114
|
+
def custom_params
|
115
|
+
return @custom_params ||= read_custom_params
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
# Take the posted data and move the relevant data into a hash
|
122
|
+
def parse(post)
|
123
|
+
@raw = post
|
124
|
+
for line in post.split('&')
|
125
|
+
key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
|
126
|
+
params[key] = value
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Read the custom params into a hash
|
131
|
+
def read_custom_params
|
132
|
+
custom = {}
|
133
|
+
params.each do |key, value|
|
134
|
+
if /\A(M_|MC_|CM_)/ === key
|
135
|
+
custom[key.gsub(/\A(M_|MC_|CM_)/, '').to_sym] = value
|
136
|
+
end
|
137
|
+
end
|
138
|
+
custom
|
139
|
+
end
|
140
|
+
|
141
|
+
# Convert a AVS value to a symbol - see above for more about AVS
|
142
|
+
def avs_value_to_symbol(value)
|
143
|
+
case value.to_s
|
144
|
+
when '8'
|
145
|
+
:partial_match
|
146
|
+
when '4'
|
147
|
+
:no_match
|
148
|
+
when '2'
|
149
|
+
:matched
|
150
|
+
when '1'
|
151
|
+
:not_checked
|
152
|
+
else
|
153
|
+
:not_supported
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|