activemerchant 1.11.0 → 1.12.0
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.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
|