activemerchant 1.49.0 → 1.50.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.
- checksums.yaml +4 -4
- data/CHANGELOG +47 -0
- data/CONTRIBUTORS +4 -0
- data/README.md +5 -1
- data/lib/active_merchant/billing/credit_card.rb +9 -0
- data/lib/active_merchant/billing/gateways/allied_wallet.rb +203 -0
- data/lib/active_merchant/billing/gateways/authorize_net.rb +17 -6
- data/lib/active_merchant/billing/gateways/beanstream.rb +4 -0
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +0 -4
- data/lib/active_merchant/billing/gateways/beanstream_interac.rb +4 -0
- data/lib/active_merchant/billing/gateways/bpoint.rb +277 -0
- data/lib/active_merchant/billing/gateways/cashnet.rb +19 -8
- data/lib/active_merchant/billing/gateways/cenpos.rb +15 -29
- data/lib/active_merchant/billing/gateways/conekta.rb +3 -2
- data/lib/active_merchant/billing/gateways/dibs.rb +206 -0
- data/lib/active_merchant/billing/gateways/fat_zebra.rb +19 -12
- data/lib/active_merchant/billing/gateways/merchant_partners.rb +245 -0
- data/lib/active_merchant/billing/gateways/netbilling.rb +1 -0
- data/lib/active_merchant/billing/gateways/omise.rb +319 -0
- data/lib/active_merchant/billing/gateways/optimal_payment.rb +5 -4
- data/lib/active_merchant/billing/gateways/orbital.rb +7 -0
- data/lib/active_merchant/billing/gateways/payu_in.rb +243 -0
- data/lib/active_merchant/billing/gateways/quickpay.rb +11 -357
- data/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb +188 -0
- data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +240 -0
- data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +227 -0
- data/lib/active_merchant/billing/gateways/s5.rb +226 -0
- data/lib/active_merchant/billing/gateways/sage_pay.rb +7 -1
- data/lib/active_merchant/billing/gateways/secure_net.rb +1 -1
- data/lib/active_merchant/billing/gateways/stripe.rb +8 -5
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +2 -2
- data/lib/active_merchant/billing/gateways/vanco.rb +280 -0
- data/lib/active_merchant/connection.rb +3 -0
- data/lib/active_merchant/version.rb +1 -1
- metadata +15 -27
- checksums.yaml.gz.sig +0 -2
- data.tar.gz.sig +0 -0
- data/lib/active_merchant/billing/gateways/adyen.rb +0 -209
- metadata.gz.sig +0 -1
@@ -269,17 +269,19 @@ module ActiveMerchant #:nodoc:
|
|
269
269
|
def build_billing_details(xml, opts)
|
270
270
|
xml.tag! 'billingDetails' do
|
271
271
|
xml.tag! 'cardPayMethod', 'WEB'
|
272
|
-
build_address(xml, opts[:billing_address]
|
272
|
+
build_address(xml, opts[:billing_address]) if opts[:billing_address]
|
273
|
+
xml.tag! 'email', opts[:email] if opts[:email]
|
273
274
|
end
|
274
275
|
end
|
275
276
|
|
276
277
|
def build_shipping_details(xml, opts)
|
277
278
|
xml.tag! 'shippingDetails' do
|
278
|
-
build_address(xml, opts[:shipping_address]
|
279
|
+
build_address(xml, opts[:shipping_address])
|
280
|
+
xml.tag! 'email', opts[:email] if opts[:email]
|
279
281
|
end if opts[:shipping_address].present?
|
280
282
|
end
|
281
283
|
|
282
|
-
def build_address(xml, addr
|
284
|
+
def build_address(xml, addr)
|
283
285
|
if addr[:name]
|
284
286
|
xml.tag! 'firstName', addr[:name].split(' ').first
|
285
287
|
xml.tag! 'lastName' , addr[:name].split(' ').last
|
@@ -294,7 +296,6 @@ module ActiveMerchant #:nodoc:
|
|
294
296
|
xml.tag! 'country', addr[:country] if addr[:country].present?
|
295
297
|
xml.tag! 'zip' , addr[:zip] if addr[:zip].present?
|
296
298
|
xml.tag! 'phone' , addr[:phone] if addr[:phone].present?
|
297
|
-
xml.tag! 'email', email if email
|
298
299
|
end
|
299
300
|
|
300
301
|
def card_type(key)
|
@@ -196,6 +196,13 @@ module ActiveMerchant #:nodoc:
|
|
196
196
|
commit(order, :authorize, options[:trace_number])
|
197
197
|
end
|
198
198
|
|
199
|
+
def verify(creditcard, options = {})
|
200
|
+
MultiResponse.run(:use_first_response) do |r|
|
201
|
+
r.process { authorize(100, creditcard, options) }
|
202
|
+
r.process(:ignore_result) { void(r.authorization) }
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
199
206
|
# AC – Authorization and Capture
|
200
207
|
def purchase(money, creditcard, options = {})
|
201
208
|
order = build_new_order_xml(AUTH_AND_CAPTURE, money, options) do |xml|
|
@@ -0,0 +1,243 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
class PayuInGateway < Gateway
|
6
|
+
self.test_url = "https://test.payu.in/_payment"
|
7
|
+
self.live_url = "https://secure.payu.in/_payment"
|
8
|
+
|
9
|
+
TEST_INFO_URL = "https://test.payu.in/merchant/postservice.php?form=2"
|
10
|
+
LIVE_INFO_URL = "https://info.payu.in/merchant/postservice.php?form=2"
|
11
|
+
|
12
|
+
self.supported_countries = ['IN']
|
13
|
+
self.default_currency = 'INR'
|
14
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
|
15
|
+
|
16
|
+
self.homepage_url = 'https://www.payu.in/'
|
17
|
+
self.display_name = 'PayU India'
|
18
|
+
|
19
|
+
def initialize(options={})
|
20
|
+
requires!(options, :key, :salt)
|
21
|
+
super
|
22
|
+
end
|
23
|
+
|
24
|
+
def purchase(money, payment, options={})
|
25
|
+
requires!(options, :order_id)
|
26
|
+
|
27
|
+
post = {}
|
28
|
+
add_invoice(post, money, options)
|
29
|
+
add_payment(post, payment)
|
30
|
+
add_addresses(post, options)
|
31
|
+
add_customer_data(post, options)
|
32
|
+
add_auth(post)
|
33
|
+
|
34
|
+
MultiResponse.run do |r|
|
35
|
+
r.process{commit(url("purchase"), post)}
|
36
|
+
if(r.params["enrolled"].to_s == "0")
|
37
|
+
r.process{commit(r.params["post_uri"], r.params["form_post_vars"])}
|
38
|
+
else
|
39
|
+
r.process{handle_3dsecure(r)}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def refund(money, authorization, options={})
|
45
|
+
raise ArgumentError, "Amount is required" unless money
|
46
|
+
|
47
|
+
post = {}
|
48
|
+
|
49
|
+
post[:command] = "cancel_refund_transaction"
|
50
|
+
post[:var1] = authorization
|
51
|
+
post[:var2] = generate_unique_id
|
52
|
+
post[:var3] = amount(money)
|
53
|
+
|
54
|
+
add_auth(post, :command, :var1)
|
55
|
+
|
56
|
+
commit(url("refund"), post)
|
57
|
+
end
|
58
|
+
|
59
|
+
def supports_scrubbing?
|
60
|
+
true
|
61
|
+
end
|
62
|
+
|
63
|
+
def scrub(transcript)
|
64
|
+
transcript.
|
65
|
+
gsub(/(ccnum=)[^&\n"]*(&|\n|"|$)/, '\1[FILTERED]\2').
|
66
|
+
gsub(/(ccvv=)[^&\n"]*(&|\n|"|$)/, '\1[FILTERED]\2').
|
67
|
+
gsub(/(card_hash=)[^&\n"]*(&|\n|"|$)/, '\1[FILTERED]\2').
|
68
|
+
gsub(/(ccnum":")[^"]*(")/, '\1[FILTERED]\2').
|
69
|
+
gsub(/(ccvv":")[^"]*(")/, '\1[FILTERED]\2')
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
PAYMENT_DIGEST_KEYS = %w(
|
75
|
+
txnid amount productinfo firstname email
|
76
|
+
udf1 udf2 udf3 udf4 udf5
|
77
|
+
bogus bogus bogus bogus bogus
|
78
|
+
)
|
79
|
+
def add_auth(post, *digest_keys)
|
80
|
+
post[:key] = @options[:key]
|
81
|
+
post[:txn_s2s_flow] = 1
|
82
|
+
|
83
|
+
digest_keys = PAYMENT_DIGEST_KEYS if digest_keys.empty?
|
84
|
+
digest = Digest::SHA2.new(512)
|
85
|
+
digest << @options[:key] << "|"
|
86
|
+
digest_keys.each do |key|
|
87
|
+
digest << (post[key.to_sym] || "") << "|"
|
88
|
+
end
|
89
|
+
digest << @options[:salt]
|
90
|
+
post[:hash] = digest.hexdigest
|
91
|
+
end
|
92
|
+
|
93
|
+
def add_customer_data(post, options)
|
94
|
+
post[:email] = clean(options[:email] || "unknown@example.com", nil, 50)
|
95
|
+
post[:phone] = clean((options[:billing_address] && options[:billing_address][:phone]) || "11111111111", :numeric, 50)
|
96
|
+
end
|
97
|
+
|
98
|
+
def add_addresses(post, options)
|
99
|
+
if options[:billing_address]
|
100
|
+
post[:address1] = clean(options[:billing_address][:address1], :text, 100)
|
101
|
+
post[:address2] = clean(options[:billing_address][:address2], :text, 100)
|
102
|
+
post[:city] = clean(options[:billing_address][:city], :text, 50)
|
103
|
+
post[:state] = clean(options[:billing_address][:state], :text, 50)
|
104
|
+
post[:country] = clean(options[:billing_address][:country], :text, 50)
|
105
|
+
post[:zipcode] = clean(options[:billing_address][:zip], :numeric, 20)
|
106
|
+
end
|
107
|
+
|
108
|
+
if options[:shipping_address]
|
109
|
+
if options[:shipping_address][:name]
|
110
|
+
first, *rest = options[:shipping_address][:name].split(/\s+/)
|
111
|
+
post[:shipping_firstname] = clean(first, :name, 60)
|
112
|
+
post[:shipping_lastname] = clean(rest.join(" "), :name, 20)
|
113
|
+
end
|
114
|
+
post[:shipping_address1] = clean(options[:shipping_address][:address1], :text, 100)
|
115
|
+
post[:shipping_address2] = clean(options[:shipping_address][:address2], :text, 100)
|
116
|
+
post[:shipping_city] = clean(options[:shipping_address][:city], :text, 50)
|
117
|
+
post[:shipping_state] = clean(options[:shipping_address][:state], :text, 50)
|
118
|
+
post[:shipping_country] = clean(options[:shipping_address][:country], :text, 50)
|
119
|
+
post[:shipping_zipcode] = clean(options[:shipping_address][:zip], :numeric, 20)
|
120
|
+
post[:shipping_phone] = clean(options[:shipping_address][:phone], :numeric, 50)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def add_invoice(post, money, options)
|
125
|
+
post[:amount] = amount(money)
|
126
|
+
|
127
|
+
post[:txnid] = clean(options[:order_id], :alphanumeric, 25)
|
128
|
+
post[:productinfo] = clean(options[:description] || "Purchase", nil, 100)
|
129
|
+
|
130
|
+
post[:surl] = "http://example.com"
|
131
|
+
post[:furl] = "http://example.com"
|
132
|
+
end
|
133
|
+
|
134
|
+
BRAND_MAP = {
|
135
|
+
visa: "VISA",
|
136
|
+
master: "MAST",
|
137
|
+
american_express: "AMEX",
|
138
|
+
diners_club: "DINR"
|
139
|
+
}
|
140
|
+
|
141
|
+
def add_payment(post, payment)
|
142
|
+
post[:pg] = "CC"
|
143
|
+
post[:firstname] = clean(payment.first_name, :name, 60)
|
144
|
+
post[:lastname] = clean(payment.last_name, :name, 20)
|
145
|
+
|
146
|
+
post[:bankcode] = BRAND_MAP[payment.brand.to_sym]
|
147
|
+
post[:ccnum] = payment.number
|
148
|
+
post[:ccvv] = payment.verification_value
|
149
|
+
post[:ccname] = payment.name
|
150
|
+
post[:ccexpmon] = format(payment.month, :two_digits)
|
151
|
+
post[:ccexpyr] = format(payment.year, :four_digits)
|
152
|
+
end
|
153
|
+
|
154
|
+
def clean(value, format, maxlength)
|
155
|
+
value ||= ""
|
156
|
+
value = case format
|
157
|
+
when :alphanumeric
|
158
|
+
value.gsub(/[^A-Za-z0-9]/, "")
|
159
|
+
when :name
|
160
|
+
value.gsub(/[^A-Za-z ]/, "")
|
161
|
+
when :numeric
|
162
|
+
value.gsub(/[^0-9]/, "")
|
163
|
+
when :text
|
164
|
+
value.gsub(/[^A-Za-z0-9@\-_\/\. ]/, "")
|
165
|
+
when nil
|
166
|
+
value
|
167
|
+
else
|
168
|
+
raise "Unknown format #{format} for #{value}"
|
169
|
+
end
|
170
|
+
value[0...maxlength]
|
171
|
+
end
|
172
|
+
|
173
|
+
def parse(body)
|
174
|
+
top = JSON.parse(body)
|
175
|
+
|
176
|
+
if result = top.delete("result")
|
177
|
+
result.split("&").inject({}) do |hash, string|
|
178
|
+
key, value = string.split("=")
|
179
|
+
hash[CGI.unescape(key).downcase] = CGI.unescape(value || "")
|
180
|
+
hash
|
181
|
+
end.each do |key, value|
|
182
|
+
if top[key]
|
183
|
+
top["result_#{key}"] = value
|
184
|
+
else
|
185
|
+
top[key] = value
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
if response = top.delete("response")
|
191
|
+
top.merge!(response)
|
192
|
+
end
|
193
|
+
|
194
|
+
top
|
195
|
+
end
|
196
|
+
|
197
|
+
def commit(url, parameters)
|
198
|
+
response = parse(ssl_post(url, post_data(parameters), "Accept-Encoding" => "identity"))
|
199
|
+
|
200
|
+
Response.new(
|
201
|
+
success_from(response),
|
202
|
+
message_from(response),
|
203
|
+
response,
|
204
|
+
authorization: authorization_from(response),
|
205
|
+
test: test?
|
206
|
+
)
|
207
|
+
end
|
208
|
+
|
209
|
+
def url(action)
|
210
|
+
case action
|
211
|
+
when "purchase"
|
212
|
+
(test? ? test_url : live_url)
|
213
|
+
else
|
214
|
+
(test? ? TEST_INFO_URL : LIVE_INFO_URL)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
def success_from(response)
|
219
|
+
if response["result_status"]
|
220
|
+
(response["status"] == "success" && response["result_status"] == "success")
|
221
|
+
else
|
222
|
+
(response["status"] == "success" || response["status"].to_s == "1")
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def message_from(response)
|
227
|
+
(response["error_message"] || response["error"] || response["msg"])
|
228
|
+
end
|
229
|
+
|
230
|
+
def authorization_from(response)
|
231
|
+
response["mihpayid"]
|
232
|
+
end
|
233
|
+
|
234
|
+
def post_data(parameters = {})
|
235
|
+
PostData.new.merge!(parameters).to_post_data
|
236
|
+
end
|
237
|
+
|
238
|
+
def handle_3dsecure(response)
|
239
|
+
Response.new(false, "3D-secure enrolled cards are not supported.")
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
@@ -1,371 +1,25 @@
|
|
1
1
|
require 'rexml/document'
|
2
2
|
require 'digest/md5'
|
3
3
|
|
4
|
+
require 'active_merchant/billing/gateways/quickpay/quickpay_v10'
|
5
|
+
require 'active_merchant/billing/gateways/quickpay/quickpay_v4to7'
|
6
|
+
|
4
7
|
module ActiveMerchant #:nodoc:
|
5
8
|
module Billing #:nodoc:
|
6
9
|
class QuickpayGateway < Gateway
|
7
|
-
self.
|
8
|
-
|
9
|
-
self.default_currency = 'DKK'
|
10
|
-
self.money_format = :cents
|
11
|
-
self.supported_cardtypes = [:dankort, :forbrugsforeningen, :visa, :master, :american_express, :diners_club, :jcb, :maestro]
|
12
|
-
self.supported_countries = ['DE', 'DK', 'ES', 'FI', 'FR', 'FO', 'GB', 'IS', 'NO', 'SE']
|
13
|
-
self.homepage_url = 'http://quickpay.net/'
|
14
|
-
self.display_name = 'QuickPay'
|
15
|
-
|
16
|
-
MD5_CHECK_FIELDS = {
|
17
|
-
3 => {
|
18
|
-
:authorize => %w(protocol msgtype merchant ordernumber amount
|
19
|
-
currency autocapture cardnumber expirationdate
|
20
|
-
cvd cardtypelock testmode),
|
21
|
-
|
22
|
-
:capture => %w(protocol msgtype merchant amount finalize transaction),
|
23
|
-
|
24
|
-
:cancel => %w(protocol msgtype merchant transaction),
|
25
|
-
|
26
|
-
:refund => %w(protocol msgtype merchant amount transaction),
|
27
|
-
|
28
|
-
:subscribe => %w(protocol msgtype merchant ordernumber cardnumber
|
29
|
-
expirationdate cvd cardtypelock description testmode),
|
30
|
-
|
31
|
-
:recurring => %w(protocol msgtype merchant ordernumber amount
|
32
|
-
currency autocapture transaction),
|
33
|
-
|
34
|
-
:status => %w(protocol msgtype merchant transaction),
|
35
|
-
|
36
|
-
:chstatus => %w(protocol msgtype merchant)
|
37
|
-
},
|
38
|
-
|
39
|
-
4 => {
|
40
|
-
:authorize => %w(protocol msgtype merchant ordernumber amount
|
41
|
-
currency autocapture cardnumber expirationdate cvd
|
42
|
-
cardtypelock testmode fraud_remote_addr
|
43
|
-
fraud_http_accept fraud_http_accept_language
|
44
|
-
fraud_http_accept_encoding fraud_http_accept_charset
|
45
|
-
fraud_http_referer fraud_http_user_agent apikey),
|
46
|
-
|
47
|
-
:capture => %w(protocol msgtype merchant amount finalize transaction apikey),
|
48
|
-
|
49
|
-
:cancel => %w(protocol msgtype merchant transaction apikey),
|
50
|
-
|
51
|
-
:refund => %w(protocol msgtype merchant amount transaction apikey),
|
52
|
-
|
53
|
-
:subscribe => %w(protocol msgtype merchant ordernumber cardnumber
|
54
|
-
expirationdate cvd cardtypelock description testmode
|
55
|
-
fraud_remote_addr fraud_http_accept fraud_http_accept_language
|
56
|
-
fraud_http_accept_encoding fraud_http_accept_charset
|
57
|
-
fraud_http_referer fraud_http_user_agent apikey),
|
58
|
-
|
59
|
-
:recurring => %w(protocol msgtype merchant ordernumber amount currency
|
60
|
-
autocapture transaction apikey),
|
61
|
-
|
62
|
-
:status => %w(protocol msgtype merchant transaction apikey),
|
63
|
-
|
64
|
-
:chstatus => %w(protocol msgtype merchant apikey)
|
65
|
-
},
|
66
|
-
|
67
|
-
5 => {
|
68
|
-
:authorize => %w(protocol msgtype merchant ordernumber amount
|
69
|
-
currency autocapture cardnumber expirationdate cvd
|
70
|
-
cardtypelock testmode fraud_remote_addr
|
71
|
-
fraud_http_accept fraud_http_accept_language
|
72
|
-
fraud_http_accept_encoding fraud_http_accept_charset
|
73
|
-
fraud_http_referer fraud_http_user_agent apikey),
|
74
|
-
|
75
|
-
:capture => %w(protocol msgtype merchant amount finalize transaction apikey),
|
76
|
-
|
77
|
-
:cancel => %w(protocol msgtype merchant transaction apikey),
|
78
|
-
|
79
|
-
:refund => %w(protocol msgtype merchant amount transaction apikey),
|
80
|
-
|
81
|
-
:subscribe => %w(protocol msgtype merchant ordernumber cardnumber
|
82
|
-
expirationdate cvd cardtypelock description testmode
|
83
|
-
fraud_remote_addr fraud_http_accept fraud_http_accept_language
|
84
|
-
fraud_http_accept_encoding fraud_http_accept_charset
|
85
|
-
fraud_http_referer fraud_http_user_agent apikey),
|
86
|
-
|
87
|
-
:recurring => %w(protocol msgtype merchant ordernumber amount currency
|
88
|
-
autocapture transaction apikey),
|
89
|
-
|
90
|
-
:status => %w(protocol msgtype merchant transaction apikey),
|
91
|
-
|
92
|
-
:chstatus => %w(protocol msgtype merchant apikey)
|
93
|
-
},
|
94
|
-
|
95
|
-
6 => {
|
96
|
-
:authorize => %w(protocol msgtype merchant ordernumber amount
|
97
|
-
currency autocapture cardnumber expirationdate cvd
|
98
|
-
cardtypelock testmode fraud_remote_addr
|
99
|
-
fraud_http_accept fraud_http_accept_language
|
100
|
-
fraud_http_accept_encoding fraud_http_accept_charset
|
101
|
-
fraud_http_referer fraud_http_user_agent apikey),
|
102
|
-
|
103
|
-
:capture => %w(protocol msgtype merchant amount finalize transaction
|
104
|
-
apikey),
|
105
|
-
|
106
|
-
:cancel => %w(protocol msgtype merchant transaction apikey),
|
107
|
-
|
108
|
-
:refund => %w(protocol msgtype merchant amount transaction apikey),
|
109
|
-
|
110
|
-
:subscribe => %w(protocol msgtype merchant ordernumber cardnumber
|
111
|
-
expirationdate cvd cardtypelock description testmode
|
112
|
-
fraud_remote_addr fraud_http_accept fraud_http_accept_language
|
113
|
-
fraud_http_accept_encoding fraud_http_accept_charset
|
114
|
-
fraud_http_referer fraud_http_user_agent apikey),
|
115
|
-
|
116
|
-
:recurring => %w(protocol msgtype merchant ordernumber amount currency
|
117
|
-
autocapture transaction apikey),
|
118
|
-
|
119
|
-
:status => %w(protocol msgtype merchant transaction apikey),
|
120
|
-
|
121
|
-
:chstatus => %w(protocol msgtype merchant apikey)
|
122
|
-
},
|
123
|
-
|
124
|
-
7 => {
|
125
|
-
:authorize => %w(protocol msgtype merchant ordernumber amount
|
126
|
-
currency autocapture cardnumber expirationdate cvd
|
127
|
-
acquirers cardtypelock testmode fraud_remote_addr
|
128
|
-
fraud_http_accept fraud_http_accept_language
|
129
|
-
fraud_http_accept_encoding fraud_http_accept_charset
|
130
|
-
fraud_http_referer fraud_http_user_agent apikey),
|
131
|
-
|
132
|
-
:capture => %w(protocol msgtype merchant amount finalize transaction
|
133
|
-
apikey),
|
134
|
-
|
135
|
-
:cancel => %w(protocol msgtype merchant transaction apikey),
|
136
|
-
|
137
|
-
:refund => %w(protocol msgtype merchant amount transaction apikey),
|
138
|
-
|
139
|
-
:subscribe => %w(protocol msgtype merchant ordernumber amount currency
|
140
|
-
cardnumber expirationdate cvd acquirers cardtypelock
|
141
|
-
description testmode fraud_remote_addr fraud_http_accept
|
142
|
-
fraud_http_accept_language fraud_http_accept_encoding
|
143
|
-
fraud_http_accept_charset fraud_http_referer
|
144
|
-
fraud_http_user_agent apikey),
|
145
|
-
|
146
|
-
:recurring => %w(protocol msgtype merchant ordernumber amount currency
|
147
|
-
autocapture transaction apikey),
|
148
|
-
|
149
|
-
:status => %w(protocol msgtype merchant transaction apikey),
|
150
|
-
|
151
|
-
:chstatus => %w(protocol msgtype merchant apikey)
|
152
|
-
}
|
153
|
-
}
|
154
|
-
|
155
|
-
APPROVED = '000'
|
156
|
-
|
157
|
-
# The login is the QuickpayId
|
158
|
-
# The password is the md5checkword from the Quickpay manager
|
159
|
-
# To use the API-key from the Quickpay manager, specify :api-key
|
160
|
-
# Using the API-key, requires that you use version 4+. Specify :version => 4/5/6/7 in options.
|
161
|
-
def initialize(options = {})
|
162
|
-
requires!(options, :login, :password)
|
163
|
-
@protocol = options.delete(:version) || 7 # default to protocol version 7
|
164
|
-
super
|
165
|
-
end
|
166
|
-
|
167
|
-
def authorize(money, credit_card_or_reference, options = {})
|
168
|
-
post = {}
|
169
|
-
|
170
|
-
action = recurring_or_authorize(credit_card_or_reference)
|
171
|
-
|
172
|
-
add_amount(post, money, options)
|
173
|
-
add_invoice(post, options)
|
174
|
-
add_creditcard_or_reference(post, credit_card_or_reference, options)
|
175
|
-
add_autocapture(post, false)
|
176
|
-
add_fraud_parameters(post, options) if action.eql?(:authorize)
|
177
|
-
add_testmode(post)
|
178
|
-
|
179
|
-
commit(action, post)
|
180
|
-
end
|
181
|
-
|
182
|
-
def purchase(money, credit_card_or_reference, options = {})
|
183
|
-
post = {}
|
184
|
-
|
185
|
-
action = recurring_or_authorize(credit_card_or_reference)
|
186
|
-
|
187
|
-
add_amount(post, money, options)
|
188
|
-
add_creditcard_or_reference(post, credit_card_or_reference, options)
|
189
|
-
add_invoice(post, options)
|
190
|
-
add_fraud_parameters(post, options) if action.eql?(:authorize)
|
191
|
-
add_autocapture(post, true)
|
192
|
-
|
193
|
-
commit(action, post)
|
194
|
-
end
|
195
|
-
|
196
|
-
def capture(money, authorization, options = {})
|
197
|
-
post = {}
|
198
|
-
|
199
|
-
add_finalize(post, options)
|
200
|
-
add_reference(post, authorization)
|
201
|
-
add_amount_without_currency(post, money)
|
202
|
-
commit(:capture, post)
|
203
|
-
end
|
204
|
-
|
205
|
-
def void(identification, options = {})
|
206
|
-
post = {}
|
207
|
-
|
208
|
-
add_reference(post, identification)
|
10
|
+
self.abstract_class = true
|
209
11
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
def refund(money, identification, options = {})
|
214
|
-
post = {}
|
215
|
-
|
216
|
-
add_amount_without_currency(post, money)
|
217
|
-
add_reference(post, identification)
|
218
|
-
|
219
|
-
commit(:refund, post)
|
220
|
-
end
|
221
|
-
|
222
|
-
def credit(money, identification, options = {})
|
223
|
-
ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
|
224
|
-
refund(money, identification, options)
|
225
|
-
end
|
226
|
-
|
227
|
-
def store(creditcard, options = {})
|
228
|
-
post = {}
|
229
|
-
|
230
|
-
add_creditcard(post, creditcard, options)
|
231
|
-
add_amount(post, 0, options) if @protocol >= 7
|
232
|
-
add_invoice(post, options)
|
233
|
-
add_description(post, options)
|
234
|
-
add_fraud_parameters(post, options)
|
235
|
-
add_testmode(post)
|
236
|
-
|
237
|
-
commit(:subscribe, post)
|
238
|
-
end
|
239
|
-
|
240
|
-
private
|
241
|
-
|
242
|
-
def add_amount(post, money, options = {})
|
243
|
-
post[:amount] = amount(money)
|
244
|
-
post[:currency] = options[:currency] || currency(money)
|
245
|
-
end
|
246
|
-
|
247
|
-
def add_amount_without_currency(post, money, options = {})
|
248
|
-
post[:amount] = amount(money)
|
249
|
-
end
|
250
|
-
|
251
|
-
def add_invoice(post, options)
|
252
|
-
post[:ordernumber] = format_order_number(options[:order_id])
|
253
|
-
end
|
254
|
-
|
255
|
-
def add_creditcard(post, credit_card, options)
|
256
|
-
post[:cardnumber] = credit_card.number
|
257
|
-
post[:cvd] = credit_card.verification_value
|
258
|
-
post[:expirationdate] = expdate(credit_card)
|
259
|
-
post[:cardtypelock] = options[:cardtypelock] unless options[:cardtypelock].blank?
|
260
|
-
post[:acquirers] = options[:acquirers] unless options[:acquirers].blank?
|
261
|
-
end
|
262
|
-
|
263
|
-
def add_reference(post, identification)
|
264
|
-
post[:transaction] = identification
|
265
|
-
end
|
12
|
+
def self.new(options = {})
|
13
|
+
options.fetch(:login) rescue raise ArgumentError.new("Missing required parameter: login")
|
266
14
|
|
267
|
-
|
268
|
-
if
|
269
|
-
|
15
|
+
version = options[:login].to_i < 10000000 ? 10 : 7
|
16
|
+
if version <= 7
|
17
|
+
QuickpayV4to7Gateway.new(options)
|
270
18
|
else
|
271
|
-
|
272
|
-
end
|
273
|
-
end
|
274
|
-
|
275
|
-
def add_autocapture(post, autocapture)
|
276
|
-
post[:autocapture] = autocapture ? 1 : 0
|
277
|
-
end
|
278
|
-
|
279
|
-
def recurring_or_authorize(credit_card_or_reference)
|
280
|
-
credit_card_or_reference.is_a?(String) ? :recurring : :authorize
|
281
|
-
end
|
282
|
-
|
283
|
-
def add_description(post, options)
|
284
|
-
post[:description] = options[:description]
|
285
|
-
end
|
286
|
-
|
287
|
-
def add_testmode(post)
|
288
|
-
return if post[:transaction].present?
|
289
|
-
post[:testmode] = test? ? '1' : '0'
|
290
|
-
end
|
291
|
-
|
292
|
-
def add_fraud_parameters(post, options)
|
293
|
-
if @protocol >= 4
|
294
|
-
post[:fraud_remote_addr] = options[:ip] if options[:ip]
|
295
|
-
post[:fraud_http_accept] = options[:fraud_http_accept] if options[:fraud_http_accept]
|
296
|
-
post[:fraud_http_accept_language] = options[:fraud_http_accept_language] if options[:fraud_http_accept_language]
|
297
|
-
post[:fraud_http_accept_encoding] = options[:fraud_http_accept_encoding] if options[:fraud_http_accept_encoding]
|
298
|
-
post[:fraud_http_accept_charset] = options[:fraud_http_accept_charset] if options[:fraud_http_accept_charset]
|
299
|
-
post[:fraud_http_referer] = options[:fraud_http_referer] if options[:fraud_http_referer]
|
300
|
-
post[:fraud_http_user_agent] = options[:fraud_http_user_agent] if options[:fraud_http_user_agent]
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
def add_finalize(post, options)
|
305
|
-
post[:finalize] = options[:finalize] ? '1' : '0'
|
306
|
-
end
|
307
|
-
|
308
|
-
def commit(action, params)
|
309
|
-
response = parse(ssl_post(self.live_url, post_data(action, params)))
|
310
|
-
|
311
|
-
Response.new(successful?(response), message_from(response), response,
|
312
|
-
:test => test?,
|
313
|
-
:authorization => response[:transaction]
|
314
|
-
)
|
315
|
-
end
|
316
|
-
|
317
|
-
def successful?(response)
|
318
|
-
response[:qpstat] == APPROVED
|
319
|
-
end
|
320
|
-
|
321
|
-
def parse(data)
|
322
|
-
response = {}
|
323
|
-
|
324
|
-
doc = REXML::Document.new(data)
|
325
|
-
|
326
|
-
doc.root.elements.each do |element|
|
327
|
-
response[element.name.to_sym] = element.text
|
19
|
+
QuickpayV10Gateway.new(options)
|
328
20
|
end
|
329
|
-
|
330
|
-
response
|
331
|
-
end
|
332
|
-
|
333
|
-
def message_from(response)
|
334
|
-
response[:qpstatmsg].to_s
|
335
|
-
end
|
336
|
-
|
337
|
-
def post_data(action, params = {})
|
338
|
-
params[:protocol] = @protocol
|
339
|
-
params[:msgtype] = action.to_s
|
340
|
-
params[:merchant] = @options[:login]
|
341
|
-
params[:apikey] = @options[:apikey] if @options[:apikey]
|
342
|
-
params[:md5check] = generate_check_hash(action, params)
|
343
|
-
|
344
|
-
params.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
345
|
-
end
|
346
|
-
|
347
|
-
def generate_check_hash(action, params)
|
348
|
-
string = MD5_CHECK_FIELDS[@protocol][action].collect do |key|
|
349
|
-
params[key.to_sym]
|
350
|
-
end.join('')
|
351
|
-
|
352
|
-
# Add the md5checkword
|
353
|
-
string << @options[:password].to_s
|
354
|
-
|
355
|
-
Digest::MD5.hexdigest(string)
|
356
|
-
end
|
357
|
-
|
358
|
-
def expdate(credit_card)
|
359
|
-
year = format(credit_card.year, :two_digits)
|
360
|
-
month = format(credit_card.month, :two_digits)
|
361
|
-
|
362
|
-
"#{year}#{month}"
|
363
|
-
end
|
364
|
-
|
365
|
-
# Limited to 20 digits max
|
366
|
-
def format_order_number(number)
|
367
|
-
number.to_s.gsub(/[^\w]/, '').rjust(4, "0")[0...20]
|
368
21
|
end
|
22
|
+
|
369
23
|
end
|
370
24
|
end
|
371
25
|
end
|