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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42f985c77801a167c97a8fd6a09ce6516a75f645
|
4
|
+
data.tar.gz: 878116909f094338c4d837cdb33315bd6bff34e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22674a72518b5aa6376d75366344dea6e0e4a9d021e0fa38672d8c423bda37459722f8818fa852fba4245b330deec8e7d0d7ee4d4af761c2ba204552dc1d9439
|
7
|
+
data.tar.gz: 8e2a471639e936c5ec32465f691ae39df7b535490d533569a8efaf9024342219b4fd16410bd9667daf37688c3f4824b6dd41057b8a7adf3cb08a01518fa188c1
|
data/CHANGELOG
CHANGED
@@ -1,5 +1,52 @@
|
|
1
1
|
= ActiveMerchant CHANGELOG
|
2
2
|
|
3
|
+
== Version 1.50.0 (June 1, 2015)
|
4
|
+
|
5
|
+
* Vanco: Add gateway [duff]
|
6
|
+
* Conekta: Move device fingerprint to root [MauricioMurga]
|
7
|
+
* Conekta: Change default language to Spanish [MauricioMurga]
|
8
|
+
* Vanco: Improve authentication handling [duff]
|
9
|
+
* Vanco: Allow specification of fund_id [duff]
|
10
|
+
* S5: Add gateway [davidsantoso]
|
11
|
+
* SecureNet: Truncate order_id [duff]
|
12
|
+
* [POSSIBLE BREAKAGE] Stripe: Be explicit about API version [duff]
|
13
|
+
* Dibs: Add gateway [mrezentes]
|
14
|
+
* Dibs: Rubyize merchant_id and secret_key [mrezentes]
|
15
|
+
* Stripe: Add support for reverse_transfer [duff]
|
16
|
+
* USA ePay: Add support for manual entry indicator [AnotherJoSmith]
|
17
|
+
* Authorize.Net: Add support for manual entry indicator [AnotherJoSmith]
|
18
|
+
* CenPOS: Change description to invoice_detail [mrezentes]
|
19
|
+
* BPoint: Add gateway [tjstankus]
|
20
|
+
* S5: Remove address requirement for purchase and authorize [davidsantoso]
|
21
|
+
* Vanco: Add support for eChecks [duff]
|
22
|
+
* Remove Adyen support [ntalbott]
|
23
|
+
* CenPOS: Use ProcessCreditCard action [duff]
|
24
|
+
* CASHnet: uri encode the merchant gateway name [mrezentes]
|
25
|
+
* S5: Include card brand in request body [davidsantoso]
|
26
|
+
* Vanco: Handle multiple error responses [duff]
|
27
|
+
* Merchant Partners gateway support [rwdaigle]
|
28
|
+
* BPoint: Update params to contain all response data [tjstankus]
|
29
|
+
* BPoint: Support biller_code in options [tjstankus]
|
30
|
+
* Sagepay: Add Verify [anellis]
|
31
|
+
* S5: Build XML with UTF-8 encoding [tjstankus]
|
32
|
+
* Cashnet: Handle unparsable response body [duff]
|
33
|
+
* CenPOS: Allow specification of customer_code [duff]
|
34
|
+
* Allied Wallet: Add gateway [anellis]
|
35
|
+
* S5: set Regex closure on scrubbing method [davidsantoso]
|
36
|
+
* Dibs: Require TLSv1 [duff]
|
37
|
+
* Optimal: Handle case of no billing address [duff]
|
38
|
+
* Omise: Add gateway [zdk]
|
39
|
+
* CenPOS: Simplify currency handling [duff]
|
40
|
+
* Beanstream: Don't treat redirect as success [aprofeit]
|
41
|
+
* Add PayU India gateway [ntalbott]
|
42
|
+
* NetBilling: Require TLSv1 [duff]
|
43
|
+
* S5: Handle recurring transactions without CVV [davidsantoso]
|
44
|
+
* Stripe: Force USD for verify [duff]
|
45
|
+
* PayU India: Prevent shadowing in response parsing [ntalbott]
|
46
|
+
* QuickPay: Add support for v10 API [ta]
|
47
|
+
* Fat Zebra: Fix refund and store signatures [duff]
|
48
|
+
* Fat Zebra: Allow transactions without a CVV [duff]
|
49
|
+
|
3
50
|
== Version 1.49.0 (May 1, 2015)
|
4
51
|
|
5
52
|
* Braintree: Add support for AVS error codes [ivanvfer]
|
data/CONTRIBUTORS
CHANGED
data/README.md
CHANGED
@@ -76,7 +76,7 @@ end
|
|
76
76
|
```
|
77
77
|
|
78
78
|
For more in-depth documentation and tutorials, see [GettingStarted.md](GettingStarted.md) and the
|
79
|
-
[API documentation](http://rubydoc.info/github/Shopify/active_merchant/
|
79
|
+
[API documentation](http://www.rubydoc.info/github/Shopify/active_merchant/).
|
80
80
|
|
81
81
|
## Supported Payment Gateways
|
82
82
|
|
@@ -107,6 +107,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
|
|
107
107
|
* [Commercegate](http://www.commercegate.com/) - AD, AT, AX, BE, BG, CH, CY, CZ, DE, DK, ES, FI, FR, GB, GG, GI, GR, HR, HU, IE, IM, IS, IT, JE, LI, LT, LU, LV, MC, MT, NL, NO, PL, PT, RO, SE, SI, SK, VA
|
108
108
|
* [Conekta](https://conekta.io) - MX
|
109
109
|
* [CyberSource](http://www.cybersource.com) - US, BR, CA, CN, DK, FI, FR, DE, JP, MX, NO, SE, GB, SG
|
110
|
+
* [DIBS](http://www.dibspayment.com/) - US, FI, NO, SE, GB
|
110
111
|
* [DataCash](http://www.datacash.com/) - GB
|
111
112
|
* [Efsnet](http://www.concordefsnet.com/) - US
|
112
113
|
* [Elavon MyVirtualMerchant](http://www.elavon.com/) - US, CA
|
@@ -178,6 +179,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
|
|
178
179
|
* [Payscout](http://www.payscout.com/) - US
|
179
180
|
* [Paystation](http://paystation.co.nz) - NZ
|
180
181
|
* [Pay Way](http://www.payway.com.au) - AU
|
182
|
+
* [PayU India](https://www.payu.in/) - IN
|
181
183
|
* [Pin Payments](http://www.pin.net.au/) - AU
|
182
184
|
* [Plug'n Pay](http://www.plugnpay.com/) - US
|
183
185
|
* [Psigate](http://www.psigate.com/) - CA
|
@@ -190,6 +192,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
|
|
190
192
|
* [Raven PacNet](http://www.pacnetservices.com/) - US
|
191
193
|
* [Realex](http://www.realexpayments.com/) - IE, GB, FR, BE, NL, LU, IT
|
192
194
|
* [Redsys](http://www.redsys.es/) - ES
|
195
|
+
* [S5](http://www.s5.dk/) - DK
|
193
196
|
* [SagePay](http://www.sagepay.com) - GB, IE
|
194
197
|
* [Sage Payment Solutions](http://www.sagepayments.com) - US, CA
|
195
198
|
* [Sallie Mae](http://www.salliemae.com/) - US
|
@@ -207,6 +210,7 @@ The [ActiveMerchant Wiki](http://github.com/Shopify/active_merchant/wikis) conta
|
|
207
210
|
* [Transnational](http://www.tnbci.com/) - US
|
208
211
|
* [TrustCommerce](http://www.trustcommerce.com/) - US
|
209
212
|
* [USA ePay](http://www.usaepay.com/) - US
|
213
|
+
* [Vanco Payment Solutions](http://vancopayments.com/) - US
|
210
214
|
* [Verifi](http://www.verifi.com/) - US
|
211
215
|
* [ViaKLIX](http://viaklix.com) - US
|
212
216
|
* [WebPay](https://webpay.jp/) - JP
|
@@ -138,6 +138,15 @@ module ActiveMerchant #:nodoc:
|
|
138
138
|
# @return [String]
|
139
139
|
attr_accessor :track_data
|
140
140
|
|
141
|
+
# Returns or sets whether a card has been processed using manual entry.
|
142
|
+
#
|
143
|
+
# This attribute is optional and is only used by gateways who use this information in their transaction risk
|
144
|
+
# calculations. See {this page on 'card not present' transactions}[http://en.wikipedia.org/wiki/Card_not_present_transaction]
|
145
|
+
# for further explanation and examples of this kind of transaction.
|
146
|
+
#
|
147
|
+
# @return [true, false]
|
148
|
+
attr_accessor :manual_entry
|
149
|
+
|
141
150
|
# Returns or sets the ICC/ASN1 credit card data for a EMV transaction, typically this is a BER-encoded TLV string.
|
142
151
|
#
|
143
152
|
# @return [String]
|
@@ -0,0 +1,203 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class AlliedWalletGateway < Gateway
|
4
|
+
self.display_name = "Allied Wallet"
|
5
|
+
self.homepage_url = "https://www.alliedwallet.com"
|
6
|
+
|
7
|
+
self.live_url = "https://api.alliedwallet.com/merchants/"
|
8
|
+
|
9
|
+
self.supported_countries = ["US"]
|
10
|
+
self.default_currency = "USD"
|
11
|
+
self.money_format = :dollars
|
12
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover,
|
13
|
+
:diners_club, :jcb, :maestro]
|
14
|
+
|
15
|
+
def initialize(options={})
|
16
|
+
requires!(options, :site_id, :merchant_id, :token)
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def purchase(amount, payment_method, options={})
|
21
|
+
post = {}
|
22
|
+
add_invoice(post, amount, options)
|
23
|
+
add_payment_method(post, payment_method)
|
24
|
+
add_customer_data(post, options)
|
25
|
+
|
26
|
+
commit(:purchase, post)
|
27
|
+
end
|
28
|
+
|
29
|
+
def authorize(amount, payment_method, options={})
|
30
|
+
post = {}
|
31
|
+
add_invoice(post, amount, options)
|
32
|
+
add_payment_method(post, payment_method)
|
33
|
+
add_customer_data(post, options)
|
34
|
+
|
35
|
+
commit(:authorize, post)
|
36
|
+
end
|
37
|
+
|
38
|
+
def capture(amount, authorization, options={})
|
39
|
+
post = {}
|
40
|
+
add_invoice(post, amount, options)
|
41
|
+
add_reference(post, authorization, :capture)
|
42
|
+
add_customer_data(post, options)
|
43
|
+
|
44
|
+
commit(:capture, post)
|
45
|
+
end
|
46
|
+
|
47
|
+
def void(authorization, options={})
|
48
|
+
post = {}
|
49
|
+
add_reference(post, authorization, :void)
|
50
|
+
|
51
|
+
commit(:void, post)
|
52
|
+
end
|
53
|
+
|
54
|
+
def refund(amount, authorization, options={})
|
55
|
+
post = {}
|
56
|
+
add_invoice(post, amount, options)
|
57
|
+
add_reference(post, authorization, :refund)
|
58
|
+
add_amount(post, amount)
|
59
|
+
add_customer_data(post, options)
|
60
|
+
|
61
|
+
commit(:refund, post)
|
62
|
+
end
|
63
|
+
|
64
|
+
def verify(credit_card, options={})
|
65
|
+
MultiResponse.run(:use_first_response) do |r|
|
66
|
+
r.process { authorize(100, credit_card, options) }
|
67
|
+
r.process(:ignore_result) { void(r.authorization, options) }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def supports_scrubbing?
|
72
|
+
true
|
73
|
+
end
|
74
|
+
|
75
|
+
def scrub(transcript)
|
76
|
+
transcript.
|
77
|
+
gsub(%r((Authorization: Bearer )[a-zA-Z0-9._-]+)i, '\1[FILTERED]').
|
78
|
+
gsub(%r(("cardNumber\\?":\\?")[^"]*)i, '\1[FILTERED]').
|
79
|
+
gsub(%r(("cVVCode\\?":\\?")[^"]*)i, '\1[FILTERED]')
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def add_amount(post, amount)
|
85
|
+
post[:amount] = amount
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_invoice(post, money, options)
|
89
|
+
post[:siteId] = @options[:site_id]
|
90
|
+
post[:amount] = amount(money)
|
91
|
+
post[:trackingId] = options[:order_id]
|
92
|
+
post[:currency] = options[:currency] || currency(money)
|
93
|
+
end
|
94
|
+
|
95
|
+
def add_payment_method(post, payment_method)
|
96
|
+
post[:nameOnCard] = payment_method.name
|
97
|
+
post[:cardNumber] = payment_method.number
|
98
|
+
post[:cVVCode] = payment_method.verification_value
|
99
|
+
post[:expirationYear] = format(payment_method.year, :four_digits)
|
100
|
+
post[:expirationMonth] = format(payment_method.month, :two_digits)
|
101
|
+
end
|
102
|
+
|
103
|
+
def add_customer_data(post, options)
|
104
|
+
post[:email] = options[:email] || "unspecified@example.com"
|
105
|
+
post[:iPAddress] = options[:ip]
|
106
|
+
if (billing_address = options[:billing_address])
|
107
|
+
post[:firstName], post[:lastName] = billing_address[:name].split
|
108
|
+
post[:addressLine1] = billing_address[:address1]
|
109
|
+
post[:addressLine2] = billing_address[:address2]
|
110
|
+
post[:city] = billing_address[:city]
|
111
|
+
post[:state] = billing_address[:state]
|
112
|
+
post[:countryId] = billing_address[:country]
|
113
|
+
post[:postalCode] = billing_address[:zip]
|
114
|
+
post[:phone] = billing_address[:phone]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def add_reference(post, authorization, action)
|
119
|
+
transactions = {
|
120
|
+
capture: :authorizetransactionid,
|
121
|
+
void: :authorizeTransactionid,
|
122
|
+
refund: :referencetransactionid,
|
123
|
+
recurring: :saleTransactionid
|
124
|
+
}
|
125
|
+
post[transactions[action]] = authorization
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
ACTIONS = {
|
130
|
+
purchase: "SALE",
|
131
|
+
authorize: "AUTHORIZE",
|
132
|
+
capture: "CAPTURE",
|
133
|
+
void: "VOID",
|
134
|
+
refund: "REFUND"
|
135
|
+
}
|
136
|
+
|
137
|
+
def commit(action, post)
|
138
|
+
begin
|
139
|
+
raw_response = ssl_post(url(action), post.to_json, headers)
|
140
|
+
response = parse(raw_response)
|
141
|
+
rescue ResponseError => e
|
142
|
+
raise unless(e.response.code.to_s =~ /4\d\d/)
|
143
|
+
response = parse(e.response.body)
|
144
|
+
end
|
145
|
+
|
146
|
+
succeeded = success_from(response["status"])
|
147
|
+
Response.new(
|
148
|
+
succeeded,
|
149
|
+
message_from(succeeded, response),
|
150
|
+
response,
|
151
|
+
authorization: response["id"],
|
152
|
+
:avs_result => AVSResult.new(code: response["avs_response"]),
|
153
|
+
:cvv_result => CVVResult.new(response["cvv2_response"]),
|
154
|
+
test: test?
|
155
|
+
)
|
156
|
+
rescue JSON::ParserError
|
157
|
+
unparsable_response(raw_response)
|
158
|
+
end
|
159
|
+
|
160
|
+
def unparsable_response(raw_response)
|
161
|
+
message = "Unparsable response received from Allied Wallet. Please contact Allied Wallet if you continue to receive this message."
|
162
|
+
message += " (The raw response returned by the API was #{raw_response.inspect})"
|
163
|
+
return Response.new(false, message)
|
164
|
+
end
|
165
|
+
|
166
|
+
def headers
|
167
|
+
{
|
168
|
+
"Content-type" => "application/json",
|
169
|
+
"Authorization" => "Bearer " + @options[:token]
|
170
|
+
}
|
171
|
+
end
|
172
|
+
|
173
|
+
def url(action)
|
174
|
+
live_url + CGI.escape(@options[:merchant_id]) + "/" + ACTIONS[action] + "transactions"
|
175
|
+
end
|
176
|
+
|
177
|
+
def parse(body)
|
178
|
+
JSON.parse(body)
|
179
|
+
end
|
180
|
+
|
181
|
+
def parse_element(response, node)
|
182
|
+
if node.has_elements?
|
183
|
+
node.elements.each{|element| parse_element(response, element) }
|
184
|
+
else
|
185
|
+
response[node.name.underscore.to_sym] = node.text
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def success_from(response)
|
190
|
+
response == "Successful"
|
191
|
+
end
|
192
|
+
|
193
|
+
def message_from(succeeded, response)
|
194
|
+
if succeeded
|
195
|
+
"Succeeded"
|
196
|
+
else
|
197
|
+
response["message"] || "Unable to read error message"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -35,6 +35,11 @@ module ActiveMerchant #:nodoc:
|
|
35
35
|
'24' => STANDARD_ERROR_CODE[:pickup_card]
|
36
36
|
}
|
37
37
|
|
38
|
+
MARKET_TYPE = {
|
39
|
+
:moto => '1',
|
40
|
+
:retail => '2'
|
41
|
+
}
|
42
|
+
|
38
43
|
class_attribute :duplicate_window
|
39
44
|
|
40
45
|
APPROVED, DECLINED, ERROR, FRAUD_REVIEW = 1, 2, 3, 4
|
@@ -66,7 +71,7 @@ module ActiveMerchant #:nodoc:
|
|
66
71
|
add_payment_source(xml, payment)
|
67
72
|
add_invoice(xml, options)
|
68
73
|
add_customer_data(xml, payment, options)
|
69
|
-
|
74
|
+
add_market_type(xml, payment)
|
70
75
|
add_settings(xml, payment, options)
|
71
76
|
add_user_fields(xml, amount, options)
|
72
77
|
end
|
@@ -83,6 +88,7 @@ module ActiveMerchant #:nodoc:
|
|
83
88
|
add_payment_source(xml, payment)
|
84
89
|
add_invoice(xml, options)
|
85
90
|
add_customer_data(xml, payment, options)
|
91
|
+
add_market_type(xml, payment)
|
86
92
|
add_settings(xml, payment, options)
|
87
93
|
add_user_fields(xml, amount, options)
|
88
94
|
end
|
@@ -268,11 +274,16 @@ module ActiveMerchant #:nodoc:
|
|
268
274
|
end
|
269
275
|
end
|
270
276
|
|
271
|
-
def
|
272
|
-
return
|
273
|
-
|
274
|
-
|
275
|
-
|
277
|
+
def add_market_type(xml, payment)
|
278
|
+
return if card_brand(payment) == 'check' or card_brand(payment) == 'apple_pay'
|
279
|
+
if valid_track_data
|
280
|
+
xml.retail do
|
281
|
+
xml.marketType(MARKET_TYPE[:retail])
|
282
|
+
end
|
283
|
+
elsif payment.manual_entry
|
284
|
+
xml.retail do
|
285
|
+
xml.marketType(MARKET_TYPE[:moto])
|
286
|
+
end
|
276
287
|
end
|
277
288
|
end
|
278
289
|
|
@@ -99,6 +99,10 @@ module ActiveMerchant #:nodoc:
|
|
99
99
|
commit(post)
|
100
100
|
end
|
101
101
|
|
102
|
+
def success?(response)
|
103
|
+
response[:trnApproved] == '1' || response[:responseCode] == '1'
|
104
|
+
end
|
105
|
+
|
102
106
|
def recurring(money, source, options = {})
|
103
107
|
ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
|
104
108
|
|
@@ -351,10 +351,6 @@ module ActiveMerchant #:nodoc:
|
|
351
351
|
response[:message]
|
352
352
|
end
|
353
353
|
|
354
|
-
def success?(response)
|
355
|
-
response[:responseType] == 'R' || response[:trnApproved] == '1' || response[:responseCode] == '1'
|
356
|
-
end
|
357
|
-
|
358
354
|
def recurring_success?(response)
|
359
355
|
response[:code] == '1'
|
360
356
|
end
|
@@ -32,6 +32,10 @@ module ActiveMerchant #:nodoc:
|
|
32
32
|
commit(post)
|
33
33
|
end
|
34
34
|
|
35
|
+
def success?(response)
|
36
|
+
response[:responseType] == 'R' || response[:trnApproved] == '1' || response[:responseCode] == '1'
|
37
|
+
end
|
38
|
+
|
35
39
|
# Confirm a transaction posted back from the bank to Beanstream.
|
36
40
|
def confirm(transaction)
|
37
41
|
post(transaction)
|
@@ -0,0 +1,277 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
class BpointGateway < Gateway
|
6
|
+
self.live_url = 'https://www.bpoint.com.au/evolve/service_1_4_4.asmx'
|
7
|
+
|
8
|
+
self.supported_countries = ['AU']
|
9
|
+
self.default_currency = 'AUD'
|
10
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
|
11
|
+
|
12
|
+
self.homepage_url = 'https://www.bpoint.com.au/bpoint'
|
13
|
+
self.display_name = 'BPoint'
|
14
|
+
|
15
|
+
def initialize(options={})
|
16
|
+
requires!(options, :username, :password, :merchant_number)
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def store(credit_card, options={})
|
21
|
+
options[:crn1] ||= 'DEFAULT'
|
22
|
+
request_body = soap_request do |xml|
|
23
|
+
add_token(xml, credit_card, options)
|
24
|
+
end
|
25
|
+
commit(request_body)
|
26
|
+
end
|
27
|
+
|
28
|
+
def purchase(amount, credit_card, options={})
|
29
|
+
request_body = soap_request do |xml|
|
30
|
+
process_payment(xml) do |payment_xml|
|
31
|
+
add_purchase(payment_xml, amount, credit_card, options)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
commit(request_body)
|
35
|
+
end
|
36
|
+
|
37
|
+
def authorize(amount, credit_card, options={})
|
38
|
+
request_body = soap_request do |xml|
|
39
|
+
process_payment(xml) do |payment_xml|
|
40
|
+
add_authorize(payment_xml, amount, credit_card, options)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
commit(request_body)
|
44
|
+
end
|
45
|
+
|
46
|
+
def capture(amount, authorization, options={})
|
47
|
+
request_body = soap_request do |xml|
|
48
|
+
process_payment(xml) do |payment_xml|
|
49
|
+
add_capture(payment_xml, amount, authorization, options)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
commit(request_body)
|
53
|
+
end
|
54
|
+
|
55
|
+
def refund(amount, authorization, options={})
|
56
|
+
request_body = soap_request do |xml|
|
57
|
+
process_payment(xml) do |payment_xml|
|
58
|
+
add_refund(payment_xml, amount, authorization, options)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
commit(request_body)
|
62
|
+
end
|
63
|
+
|
64
|
+
def void(amount, authorization, options={})
|
65
|
+
request_body = soap_request do |xml|
|
66
|
+
process_payment(xml) do |payment_xml|
|
67
|
+
add_void(payment_xml, amount, authorization, options)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
commit(request_body)
|
71
|
+
end
|
72
|
+
|
73
|
+
def verify(credit_card, options={})
|
74
|
+
MultiResponse.run(:use_first_response) do |r|
|
75
|
+
r.process { authorize(100, credit_card, options) }
|
76
|
+
r.process(:ignore_result) { void(100, r.authorization, options) }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def supports_scrubbing?
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
def scrub(transcript)
|
85
|
+
transcript.
|
86
|
+
gsub(%r((<password>).+(</password>)), '\1[FILTERED]\2').
|
87
|
+
gsub(%r((<CardNumber>).+(</CardNumber>)), '\1[FILTERED]\2').
|
88
|
+
gsub(%r((<CVC>).+(</CVC>)), '\1[FILTERED]\2')
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def soap_request
|
94
|
+
Nokogiri::XML::Builder.new(:encoding => 'utf-8') do |xml|
|
95
|
+
xml.send('soap12:Envelope', soap_envelope_attributes) {
|
96
|
+
xml.send('soap12:Body') {
|
97
|
+
yield(xml) if block_given?
|
98
|
+
}
|
99
|
+
}
|
100
|
+
end.to_xml
|
101
|
+
end
|
102
|
+
|
103
|
+
def soap_envelope_attributes
|
104
|
+
{ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
|
105
|
+
'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema',
|
106
|
+
'xmlns:soap12' => 'http://www.w3.org/2003/05/soap-envelope' }
|
107
|
+
end
|
108
|
+
|
109
|
+
def process_payment(xml)
|
110
|
+
xml.send('ProcessPayment', { 'xmlns' => 'urn:Eve_1_4_4' }) {
|
111
|
+
credentials_xml(xml)
|
112
|
+
xml.send('txnReq') {
|
113
|
+
yield(xml) if block_given?
|
114
|
+
}
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
def add_token(xml, credit_card, options)
|
119
|
+
xml.send('AddToken', { 'xmlns' => 'urn:Eve_1_4_4' }) {
|
120
|
+
credentials_xml(xml)
|
121
|
+
xml.send('tokenRequest') {
|
122
|
+
xml.send('CRN1', options[:crn1])
|
123
|
+
xml.send('CRN2', '')
|
124
|
+
xml.send('CRN3', '')
|
125
|
+
xml.send('CardNumber', credit_card.number)
|
126
|
+
xml.send('ExpiryDate', expdate(credit_card))
|
127
|
+
}
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
def credentials_xml(xml)
|
132
|
+
xml.send('username', @options[:username])
|
133
|
+
xml.send('password', @options[:password])
|
134
|
+
xml.send('merchantNumber', @options[:merchant_number])
|
135
|
+
end
|
136
|
+
|
137
|
+
def add_purchase(xml, amount, credit_card, options)
|
138
|
+
payment_xml(xml, 'PAYMENT', amount, options)
|
139
|
+
credit_card_xml(xml, credit_card)
|
140
|
+
end
|
141
|
+
|
142
|
+
def add_authorize(xml, amount, credit_card, options)
|
143
|
+
payment_xml(xml, 'PREAUTH', amount, options)
|
144
|
+
credit_card_xml(xml, credit_card)
|
145
|
+
end
|
146
|
+
|
147
|
+
def add_capture(xml, amount, transaction_number, options)
|
148
|
+
payment_xml(xml, 'CAPTURE', amount, options)
|
149
|
+
transaction_number_xml(xml, transaction_number)
|
150
|
+
end
|
151
|
+
|
152
|
+
def add_refund(xml, amount, transaction_number, options)
|
153
|
+
payment_xml(xml, 'REFUND', amount, options)
|
154
|
+
transaction_number_xml(xml, transaction_number)
|
155
|
+
end
|
156
|
+
|
157
|
+
def add_void(xml, amount, transaction_number, options)
|
158
|
+
payment_xml(xml, 'REVERSAL', amount, options)
|
159
|
+
transaction_number_xml(xml, transaction_number)
|
160
|
+
end
|
161
|
+
|
162
|
+
def payment_xml(xml, payment_type, amount, options)
|
163
|
+
xml.send('PaymentType', payment_type)
|
164
|
+
xml.send('TxnType', 'WEB_SHOP')
|
165
|
+
xml.send('BillerCode', options.fetch(:biller_code, ''))
|
166
|
+
xml.send('MerchantReference', '')
|
167
|
+
xml.send('CRN1', '')
|
168
|
+
xml.send('CRN2', '')
|
169
|
+
xml.send('CRN3', '')
|
170
|
+
xml.send('Amount', amount)
|
171
|
+
end
|
172
|
+
|
173
|
+
def credit_card_xml(xml, credit_card)
|
174
|
+
xml.send('CardNumber', credit_card.number)
|
175
|
+
xml.send('ExpiryDate', expdate(credit_card))
|
176
|
+
xml.send('CVC', credit_card.verification_value)
|
177
|
+
end
|
178
|
+
|
179
|
+
def transaction_number_xml(xml, transaction_number)
|
180
|
+
xml.send('OriginalTransactionNumber', transaction_number)
|
181
|
+
end
|
182
|
+
|
183
|
+
def commit(request_body)
|
184
|
+
parse(ssl_post(live_url, request_body, request_headers))
|
185
|
+
end
|
186
|
+
|
187
|
+
def request_headers
|
188
|
+
{ "Content-Type" => "application/soap+xml; charset=utf-8" }
|
189
|
+
end
|
190
|
+
|
191
|
+
def parse(body)
|
192
|
+
response_for(Nokogiri::XML(body).remove_namespaces!)
|
193
|
+
end
|
194
|
+
|
195
|
+
def response_for(xml_doc)
|
196
|
+
if xml_doc.xpath('//ProcessPaymentResponse').any?
|
197
|
+
ProcessPaymentResponse.new(xml_doc, self).to_response
|
198
|
+
elsif xml_doc.xpath('//AddTokenResponse').any?
|
199
|
+
AddTokenResponse.new(xml_doc, self).to_response
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
class BPointResponse
|
204
|
+
attr_reader :xml_doc, :gateway, :params
|
205
|
+
|
206
|
+
def initialize(xml_doc, gateway)
|
207
|
+
@xml_doc = xml_doc
|
208
|
+
@gateway = gateway
|
209
|
+
@params = init_params
|
210
|
+
end
|
211
|
+
|
212
|
+
def to_response
|
213
|
+
Response.new(success?, message, params, options)
|
214
|
+
end
|
215
|
+
|
216
|
+
private
|
217
|
+
|
218
|
+
def init_params
|
219
|
+
{}.tap do |h|
|
220
|
+
xml_doc.xpath(response_node).each do |node|
|
221
|
+
if node.elements.empty?
|
222
|
+
h[node.name.to_sym] = node.text
|
223
|
+
else
|
224
|
+
node.elements.each do |childnode|
|
225
|
+
name = "#{node.name}_#{childnode.name}"
|
226
|
+
h[name.to_sym] = childnode.text
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def response_node
|
234
|
+
"//#{self.class.name.split('::').last}/*"
|
235
|
+
end
|
236
|
+
|
237
|
+
def options
|
238
|
+
{ authorization: params[authorization_key], test: gateway.test? }
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
class ProcessPaymentResponse < BPointResponse
|
243
|
+
|
244
|
+
private
|
245
|
+
|
246
|
+
def authorization_key
|
247
|
+
:ProcessPaymentResult_TransactionNumber
|
248
|
+
end
|
249
|
+
|
250
|
+
def success?
|
251
|
+
params[:ProcessPaymentResult_ResponseCode] == '0'
|
252
|
+
end
|
253
|
+
|
254
|
+
def message
|
255
|
+
params[:ProcessPaymentResult_AuthorisationResult]
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
class AddTokenResponse < BPointResponse
|
260
|
+
|
261
|
+
private
|
262
|
+
|
263
|
+
def authorization_key
|
264
|
+
:AddTokenResult_Token
|
265
|
+
end
|
266
|
+
|
267
|
+
def success?
|
268
|
+
params[:response_ResponseCode] == 'SUCCESS'
|
269
|
+
end
|
270
|
+
|
271
|
+
def message
|
272
|
+
params[:response_ResponseCode].capitalize
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|