johnreitano-activemerchant 1.5.2
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/CHANGELOG +508 -0
- data/CONTRIBUTORS +134 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +136 -0
- data/gem-public_cert.pem +20 -0
- data/lib/active_merchant/billing/avs_result.rb +98 -0
- data/lib/active_merchant/billing/base.rb +57 -0
- data/lib/active_merchant/billing/check.rb +68 -0
- data/lib/active_merchant/billing/credit_card.rb +159 -0
- data/lib/active_merchant/billing/credit_card_formatting.rb +21 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +125 -0
- data/lib/active_merchant/billing/cvv_result.rb +38 -0
- data/lib/active_merchant/billing/expiry_date.rb +34 -0
- data/lib/active_merchant/billing/gateway.rb +163 -0
- data/lib/active_merchant/billing/gateways/authorize_net.rb +654 -0
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +736 -0
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +244 -0
- data/lib/active_merchant/billing/gateways/beanstream.rb +102 -0
- data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
- data/lib/active_merchant/billing/gateways/bogus.rb +98 -0
- data/lib/active_merchant/billing/gateways/braintree.rb +17 -0
- data/lib/active_merchant/billing/gateways/card_stream.rb +230 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +594 -0
- data/lib/active_merchant/billing/gateways/data_cash.rb +593 -0
- data/lib/active_merchant/billing/gateways/efsnet.rb +229 -0
- data/lib/active_merchant/billing/gateways/elavon.rb +134 -0
- data/lib/active_merchant/billing/gateways/eway.rb +277 -0
- data/lib/active_merchant/billing/gateways/exact.rb +222 -0
- data/lib/active_merchant/billing/gateways/first_pay.rb +172 -0
- data/lib/active_merchant/billing/gateways/instapay.rb +164 -0
- data/lib/active_merchant/billing/gateways/jetpay.rb +270 -0
- data/lib/active_merchant/billing/gateways/linkpoint.rb +449 -0
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +154 -0
- data/lib/active_merchant/billing/gateways/merchant_ware.rb +283 -0
- data/lib/active_merchant/billing/gateways/modern_payments.rb +36 -0
- data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +220 -0
- data/lib/active_merchant/billing/gateways/moneris.rb +205 -0
- data/lib/active_merchant/billing/gateways/net_registry.rb +189 -0
- data/lib/active_merchant/billing/gateways/netbilling.rb +168 -0
- data/lib/active_merchant/billing/gateways/ogone.rb +279 -0
- data/lib/active_merchant/billing/gateways/pay_junction.rb +392 -0
- data/lib/active_merchant/billing/gateways/pay_secure.rb +120 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +207 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +236 -0
- data/lib/active_merchant/billing/gateways/payflow_express.rb +138 -0
- data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
- data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
- data/lib/active_merchant/billing/gateways/payment_express.rb +230 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +326 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +38 -0
- data/lib/active_merchant/billing/gateways/paypal.rb +121 -0
- data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +130 -0
- data/lib/active_merchant/billing/gateways/paypal_express_common.rb +20 -0
- data/lib/active_merchant/billing/gateways/plugnpay.rb +292 -0
- data/lib/active_merchant/billing/gateways/psigate.rb +214 -0
- data/lib/active_merchant/billing/gateways/psl_card.rb +304 -0
- data/lib/active_merchant/billing/gateways/quickpay.rb +213 -0
- data/lib/active_merchant/billing/gateways/realex.rb +200 -0
- data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +88 -0
- data/lib/active_merchant/billing/gateways/sage/sage_core.rb +116 -0
- data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
- data/lib/active_merchant/billing/gateways/sage.rb +146 -0
- data/lib/active_merchant/billing/gateways/sage_pay.rb +309 -0
- data/lib/active_merchant/billing/gateways/sallie_mae.rb +144 -0
- data/lib/active_merchant/billing/gateways/secure_pay.rb +31 -0
- data/lib/active_merchant/billing/gateways/secure_pay_au.rb +157 -0
- data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +113 -0
- data/lib/active_merchant/billing/gateways/skip_jack.rb +453 -0
- data/lib/active_merchant/billing/gateways/smart_ps.rb +265 -0
- data/lib/active_merchant/billing/gateways/trans_first.rb +127 -0
- data/lib/active_merchant/billing/gateways/transax.rb +25 -0
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +418 -0
- data/lib/active_merchant/billing/gateways/usa_epay.rb +194 -0
- data/lib/active_merchant/billing/gateways/verifi.rb +228 -0
- data/lib/active_merchant/billing/gateways/viaklix.rb +189 -0
- data/lib/active_merchant/billing/gateways/wirecard.rb +318 -0
- data/lib/active_merchant/billing/gateways.rb +18 -0
- data/lib/active_merchant/billing/integrations/action_view_helper.rb +79 -0
- data/lib/active_merchant/billing/integrations/bogus/helper.rb +17 -0
- data/lib/active_merchant/billing/integrations/bogus/notification.rb +11 -0
- data/lib/active_merchant/billing/integrations/bogus/return.rb +10 -0
- data/lib/active_merchant/billing/integrations/bogus.rb +23 -0
- data/lib/active_merchant/billing/integrations/chronopay/helper.rb +120 -0
- data/lib/active_merchant/billing/integrations/chronopay/notification.rb +158 -0
- data/lib/active_merchant/billing/integrations/chronopay/return.rb +10 -0
- data/lib/active_merchant/billing/integrations/chronopay.rb +23 -0
- data/lib/active_merchant/billing/integrations/gestpay/common.rb +42 -0
- data/lib/active_merchant/billing/integrations/gestpay/helper.rb +70 -0
- data/lib/active_merchant/billing/integrations/gestpay/notification.rb +85 -0
- data/lib/active_merchant/billing/integrations/gestpay/return.rb +10 -0
- data/lib/active_merchant/billing/integrations/gestpay.rb +25 -0
- data/lib/active_merchant/billing/integrations/helper.rb +93 -0
- data/lib/active_merchant/billing/integrations/hi_trust/helper.rb +58 -0
- data/lib/active_merchant/billing/integrations/hi_trust/notification.rb +59 -0
- data/lib/active_merchant/billing/integrations/hi_trust/return.rb +67 -0
- data/lib/active_merchant/billing/integrations/hi_trust.rb +27 -0
- data/lib/active_merchant/billing/integrations/nochex/helper.rb +68 -0
- data/lib/active_merchant/billing/integrations/nochex/notification.rb +94 -0
- data/lib/active_merchant/billing/integrations/nochex/return.rb +10 -0
- data/lib/active_merchant/billing/integrations/nochex.rb +88 -0
- data/lib/active_merchant/billing/integrations/notification.rb +62 -0
- data/lib/active_merchant/billing/integrations/paypal/helper.rb +119 -0
- data/lib/active_merchant/billing/integrations/paypal/notification.rb +154 -0
- data/lib/active_merchant/billing/integrations/paypal/return.rb +10 -0
- data/lib/active_merchant/billing/integrations/paypal.rb +39 -0
- data/lib/active_merchant/billing/integrations/quickpay/helper.rb +72 -0
- data/lib/active_merchant/billing/integrations/quickpay/notification.rb +74 -0
- data/lib/active_merchant/billing/integrations/quickpay.rb +17 -0
- data/lib/active_merchant/billing/integrations/return.rb +35 -0
- data/lib/active_merchant/billing/integrations/two_checkout/helper.rb +59 -0
- data/lib/active_merchant/billing/integrations/two_checkout/notification.rb +114 -0
- data/lib/active_merchant/billing/integrations/two_checkout/return.rb +17 -0
- data/lib/active_merchant/billing/integrations/two_checkout.rb +23 -0
- data/lib/active_merchant/billing/integrations.rb +29 -0
- data/lib/active_merchant/billing/response.rb +32 -0
- data/lib/active_merchant/billing.rb +9 -0
- data/lib/active_merchant/lib/connection.rb +170 -0
- data/lib/active_merchant/lib/country.rb +319 -0
- data/lib/active_merchant/lib/error.rb +4 -0
- data/lib/active_merchant/lib/post_data.rb +22 -0
- data/lib/active_merchant/lib/posts_data.rb +47 -0
- data/lib/active_merchant/lib/requires_parameters.rb +16 -0
- data/lib/active_merchant/lib/utils.rb +18 -0
- data/lib/active_merchant/lib/validateable.rb +76 -0
- data/lib/active_merchant.rb +46 -0
- data/lib/certs/cacert.pem +7815 -0
- data/lib/support/gateway_support.rb +58 -0
- metadata +218 -0
@@ -0,0 +1,318 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
class WirecardGateway < Gateway
|
6
|
+
# Test server location
|
7
|
+
TEST_URL = 'https://c3-test.wirecard.com/secure/ssl-gateway'
|
8
|
+
|
9
|
+
# Live server location
|
10
|
+
LIVE_URL = 'https://c3.wirecard.com/secure/ssl-gateway'
|
11
|
+
|
12
|
+
# The Namespaces are not really needed, because it just tells the System, that there's actually no namespace used.
|
13
|
+
# It's just specified here for completeness.
|
14
|
+
ENVELOPE_NAMESPACES = {
|
15
|
+
'xmlns:xsi' => 'http://www.w3.org/1999/XMLSchema-instance',
|
16
|
+
'xsi:noNamespaceSchemaLocation' => 'wirecard.xsd'
|
17
|
+
}
|
18
|
+
|
19
|
+
PERMITTED_TRANSACTIONS = %w[ AUTHORIZATION CAPTURE_AUTHORIZATION PURCHASE ]
|
20
|
+
|
21
|
+
RETURN_CODES = %w[ ACK NOK ]
|
22
|
+
|
23
|
+
# Wirecard only allows phone numbers with a format like this: +xxx(yyy)zzz-zzzz-ppp, where:
|
24
|
+
# xxx = Country code
|
25
|
+
# yyy = Area or city code
|
26
|
+
# zzz-zzzz = Local number
|
27
|
+
# ppp = PBX extension
|
28
|
+
# For example, a typical U.S. or Canadian number would be "+1(202)555-1234-739" indicating PBX extension 739 at phone
|
29
|
+
# number 5551234 within area code 202 (country code 1).
|
30
|
+
VALID_PHONE_FORMAT = /\+\d{1,3}(\(?\d{3}\)?)?\d{3}-\d{4}-\d{3}/
|
31
|
+
|
32
|
+
# The countries the gateway supports merchants from as 2 digit ISO country codes
|
33
|
+
# TODO: Check supported countries
|
34
|
+
self.supported_countries = ['DE']
|
35
|
+
|
36
|
+
# Wirecard supports all major credit and debit cards:
|
37
|
+
# Visa, Mastercard, American Express, Diners Club,
|
38
|
+
# JCB, Switch, VISA Carte Bancaire, Visa Electron and UATP cards.
|
39
|
+
# They also support the latest anti-fraud systems such as Verified by Visa or Master Secure Code.
|
40
|
+
self.supported_cardtypes = [
|
41
|
+
:visa, :master, :american_express, :diners_club, :jcb, :switch
|
42
|
+
]
|
43
|
+
|
44
|
+
# The homepage URL of the gateway
|
45
|
+
self.homepage_url = 'http://www.wirecard.com'
|
46
|
+
|
47
|
+
# The name of the gateway
|
48
|
+
self.display_name = 'Wirecard'
|
49
|
+
|
50
|
+
# The currency should normally be EUROs
|
51
|
+
self.default_currency = 'EUR'
|
52
|
+
|
53
|
+
# 100 is 1.00 Euro
|
54
|
+
self.money_format = :cents
|
55
|
+
|
56
|
+
def initialize(options = {})
|
57
|
+
# verify that username and password are supplied
|
58
|
+
requires!(options, :login, :password)
|
59
|
+
# unfortunately Wirecard also requires a BusinessCaseSignature in the XML request
|
60
|
+
requires!(options, :signature)
|
61
|
+
@options = options
|
62
|
+
super
|
63
|
+
end
|
64
|
+
|
65
|
+
# Should run against the test servers or not?
|
66
|
+
def test?
|
67
|
+
@options[:test] || super
|
68
|
+
end
|
69
|
+
|
70
|
+
# Authorization
|
71
|
+
def authorize(money, creditcard, options = {})
|
72
|
+
prepare_options_hash(options)
|
73
|
+
@options[:credit_card] = creditcard
|
74
|
+
request = build_request(:authorization, money, @options)
|
75
|
+
commit(request)
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
# Capture Authorization
|
80
|
+
def capture(money, authorization, options = {})
|
81
|
+
prepare_options_hash(options)
|
82
|
+
@options[:authorization] = authorization
|
83
|
+
request = build_request(:capture_authorization, money, @options)
|
84
|
+
commit(request)
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
# Purchase
|
89
|
+
def purchase(money, creditcard, options = {})
|
90
|
+
prepare_options_hash(options)
|
91
|
+
@options[:credit_card] = creditcard
|
92
|
+
request = build_request(:purchase, money, @options)
|
93
|
+
commit(request)
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def prepare_options_hash(options)
|
99
|
+
@options.update(options)
|
100
|
+
setup_address_hash!(options)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Create all address hash key value pairs so that
|
104
|
+
# it still works if only provided with one or two of them
|
105
|
+
def setup_address_hash!(options)
|
106
|
+
options[:billing_address] = options[:billing_address] || options[:address] || {}
|
107
|
+
options[:shipping_address] = options[:shipping_address] || {}
|
108
|
+
# Include Email in address-hash from options-hash
|
109
|
+
options[:billing_address][:email] = options[:email] if options[:email]
|
110
|
+
end
|
111
|
+
|
112
|
+
# Contact WireCard, make the XML request, and parse the
|
113
|
+
# reply into a Response object
|
114
|
+
def commit(request)
|
115
|
+
headers = { 'Content-Type' => 'text/xml',
|
116
|
+
'Authorization' => encoded_credentials }
|
117
|
+
|
118
|
+
response = parse(ssl_post(test? ? TEST_URL : LIVE_URL, request, headers))
|
119
|
+
# Pending Status also means Acknowledged (as stated in their specification)
|
120
|
+
success = response[:FunctionResult] == "ACK" || response[:FunctionResult] == "PENDING"
|
121
|
+
message = response[:Message]
|
122
|
+
authorization = (success && @options[:action] == :authorization) ? response[:GuWID] : nil
|
123
|
+
|
124
|
+
Response.new(success, message, response,
|
125
|
+
:test => test?,
|
126
|
+
:authorization => authorization,
|
127
|
+
:avs_result => { :code => response[:avsCode] },
|
128
|
+
:cvv_result => response[:cvCode]
|
129
|
+
)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Generates the complete xml-message, that gets sent to the gateway
|
133
|
+
def build_request(action, money, options = {})
|
134
|
+
xml = Builder::XmlMarkup.new :indent => 2
|
135
|
+
xml.instruct!
|
136
|
+
xml.tag! 'WIRECARD_BXML' do
|
137
|
+
xml.tag! 'W_REQUEST' do
|
138
|
+
xml.tag! 'W_JOB' do
|
139
|
+
# TODO: OPTIONAL, check what value needs to be insert here
|
140
|
+
xml.tag! 'JobID', 'test dummy data'
|
141
|
+
# UserID for this transaction
|
142
|
+
xml.tag! 'BusinessCaseSignature', options[:signature] || options[:login]
|
143
|
+
# Create the whole rest of the message
|
144
|
+
add_transaction_data(xml, action, money, options)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
xml.target!
|
149
|
+
end
|
150
|
+
|
151
|
+
# Includes the whole transaction data (payment, creditcard, address)
|
152
|
+
def add_transaction_data(xml, action, money, options = {})
|
153
|
+
options[:action] = action
|
154
|
+
# TODO: require order_id instead of auto-generating it if not supplied
|
155
|
+
options[:order_id] ||= generate_unique_id
|
156
|
+
transaction_type = action.to_s.upcase
|
157
|
+
|
158
|
+
xml.tag! "FNC_CC_#{transaction_type}" do
|
159
|
+
# TODO: OPTIONAL, check which param should be used here
|
160
|
+
xml.tag! 'FunctionID', options[:description] || 'Test dummy FunctionID'
|
161
|
+
|
162
|
+
xml.tag! 'CC_TRANSACTION' do
|
163
|
+
xml.tag! 'TransactionID', options[:order_id]
|
164
|
+
if [:authorization, :purchase].include?(action)
|
165
|
+
add_invoice(xml, money, options)
|
166
|
+
add_creditcard(xml, options[:credit_card])
|
167
|
+
add_address(xml, options[:billing_address])
|
168
|
+
elsif action == :capture_authorization
|
169
|
+
xml.tag! 'GuWID', options[:authorization] if options[:authorization]
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Includes the payment (amount, currency, country) to the transaction-xml
|
176
|
+
def add_invoice(xml, money, options)
|
177
|
+
xml.tag! 'Amount', amount(money)
|
178
|
+
xml.tag! 'Currency', options[:currency] || currency(money)
|
179
|
+
xml.tag! 'CountryCode', options[:billing_address][:country]
|
180
|
+
xml.tag! 'RECURRING_TRANSACTION' do
|
181
|
+
xml.tag! 'Type', options[:recurring] || 'Single'
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Includes the credit-card data to the transaction-xml
|
186
|
+
def add_creditcard(xml, creditcard)
|
187
|
+
raise "Creditcard must be supplied!" if creditcard.nil?
|
188
|
+
xml.tag! 'CREDIT_CARD_DATA' do
|
189
|
+
xml.tag! 'CreditCardNumber', creditcard.number
|
190
|
+
xml.tag! 'CVC2', creditcard.verification_value
|
191
|
+
xml.tag! 'ExpirationYear', creditcard.year
|
192
|
+
xml.tag! 'ExpirationMonth', format(creditcard.month, :two_digits)
|
193
|
+
xml.tag! 'CardHolderName', [creditcard.first_name, creditcard.last_name].join(' ')
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Includes the IP address of the customer to the transaction-xml
|
198
|
+
def add_customer_data(xml, options)
|
199
|
+
return unless options[:ip]
|
200
|
+
xml.tag! 'CONTACT_DATA' do
|
201
|
+
xml.tag! 'IPAddress', options[:ip]
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Includes the address to the transaction-xml
|
206
|
+
def add_address(xml, address)
|
207
|
+
return if address.nil?
|
208
|
+
xml.tag! 'CORPTRUSTCENTER_DATA' do
|
209
|
+
xml.tag! 'ADDRESS' do
|
210
|
+
xml.tag! 'Address1', address[:address1]
|
211
|
+
xml.tag! 'Address2', address[:address2] if address[:address2]
|
212
|
+
xml.tag! 'City', address[:city]
|
213
|
+
xml.tag! 'ZipCode', address[:zip]
|
214
|
+
|
215
|
+
if address[:state] =~ /[A-Za-z]{2}/ && address[:country] =~ /^(us|ca)$/i
|
216
|
+
xml.tag! 'State', address[:state].upcase
|
217
|
+
end
|
218
|
+
|
219
|
+
xml.tag! 'Country', address[:country]
|
220
|
+
xml.tag! 'Phone', address[:phone] if address[:phone] =~ VALID_PHONE_FORMAT
|
221
|
+
xml.tag! 'Email', address[:email]
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
|
227
|
+
# Read the XML message from the gateway and check if it was successful,
|
228
|
+
# and also extract required return values from the response.
|
229
|
+
def parse(xml)
|
230
|
+
basepath = '/WIRECARD_BXML/W_RESPONSE'
|
231
|
+
response = {}
|
232
|
+
|
233
|
+
xml = REXML::Document.new(xml)
|
234
|
+
if root = REXML::XPath.first(xml, "#{basepath}/W_JOB")
|
235
|
+
parse_response(response, root)
|
236
|
+
elsif root = REXML::XPath.first(xml, "//ERROR")
|
237
|
+
parse_error(response, root)
|
238
|
+
else
|
239
|
+
response[:Message] = "No valid XML response message received. \
|
240
|
+
Propably wrong credentials supplied with HTTP header."
|
241
|
+
end
|
242
|
+
|
243
|
+
response
|
244
|
+
end
|
245
|
+
|
246
|
+
# Parse the <ProcessingStatus> Element which containts all important information
|
247
|
+
def parse_response(response, root)
|
248
|
+
status = nil
|
249
|
+
# get the root element for this Transaction
|
250
|
+
root.elements.to_a.each do |node|
|
251
|
+
if node.name =~ /FNC_CC_/
|
252
|
+
status = REXML::XPath.first(node, "CC_TRANSACTION/PROCESSING_STATUS")
|
253
|
+
end
|
254
|
+
end
|
255
|
+
message = ""
|
256
|
+
if status
|
257
|
+
if info = status.elements['Info']
|
258
|
+
message << info.text
|
259
|
+
end
|
260
|
+
# Get basic response information
|
261
|
+
status.elements.to_a.each do |node|
|
262
|
+
response[node.name.to_sym] = (node.text || '').strip
|
263
|
+
end
|
264
|
+
end
|
265
|
+
parse_error(root, message)
|
266
|
+
response[:Message] = message
|
267
|
+
end
|
268
|
+
|
269
|
+
# Parse a generic error response from the gateway
|
270
|
+
def parse_error(root, message = "")
|
271
|
+
# Get errors if available and append them to the message
|
272
|
+
errors = errors_to_string(root)
|
273
|
+
unless errors.strip.blank?
|
274
|
+
message << ' - ' unless message.strip.blank?
|
275
|
+
message << errors
|
276
|
+
end
|
277
|
+
message
|
278
|
+
end
|
279
|
+
|
280
|
+
# Parses all <ERROR> elements in the response and converts the information
|
281
|
+
# to a single string
|
282
|
+
def errors_to_string(root)
|
283
|
+
# Get context error messages (can be 0..*)
|
284
|
+
errors = []
|
285
|
+
REXML::XPath.each(root, "//ERROR") do |error_elem|
|
286
|
+
error = {}
|
287
|
+
error[:Advice] = []
|
288
|
+
error[:Message] = error_elem.elements['Message'].text
|
289
|
+
error_elem.elements.each('Advice') do |advice|
|
290
|
+
error[:Advice] << advice.text
|
291
|
+
end
|
292
|
+
errors << error
|
293
|
+
end
|
294
|
+
# Convert all messages to a single string
|
295
|
+
string = ''
|
296
|
+
errors.each do |error|
|
297
|
+
string << error[:Message]
|
298
|
+
error[:Advice].each_with_index do |advice, index|
|
299
|
+
string << ' (' if index == 0
|
300
|
+
string << "#{index+1}. #{advice}"
|
301
|
+
string << ' and ' if index < error[:Advice].size - 1
|
302
|
+
string << ')' if index == error[:Advice].size - 1
|
303
|
+
end
|
304
|
+
end
|
305
|
+
string
|
306
|
+
end
|
307
|
+
|
308
|
+
# Encode login and password in Base64 to supply as HTTP header
|
309
|
+
# (for http basic authentication)
|
310
|
+
def encoded_credentials
|
311
|
+
credentials = [@options[:login], @options[:password]].join(':')
|
312
|
+
"Basic " << Base64.encode64(credentials).strip
|
313
|
+
end
|
314
|
+
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ActiveMerchant
|
2
|
+
module Billing
|
3
|
+
autoload :Gateway, 'active_merchant/billing/gateway'
|
4
|
+
|
5
|
+
Dir[File.dirname(__FILE__) + '/gateways/**/*.rb'].each do |f|
|
6
|
+
|
7
|
+
# Get camelized class name
|
8
|
+
filename = File.basename(f, '.rb')
|
9
|
+
# Add _gateway suffix
|
10
|
+
gateway_name = filename + '_gateway'
|
11
|
+
# Camelize the string to get the class name
|
12
|
+
gateway_class = gateway_name.camelize
|
13
|
+
|
14
|
+
# Register for autoloading
|
15
|
+
autoload gateway_class, f
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require_library_or_gem 'action_pack'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
module Integrations #:nodoc:
|
6
|
+
module ActionViewHelper
|
7
|
+
# This helper allows the usage of different payment integrations
|
8
|
+
# through a single form helper. Payment integrations are the
|
9
|
+
# type of service where the user is redirected to the secure
|
10
|
+
# site of the service, like Paypal or Chronopay.
|
11
|
+
#
|
12
|
+
# The helper creates a scope around a payment service helper
|
13
|
+
# which provides the specific mapping for that service.
|
14
|
+
#
|
15
|
+
# <% payment_service_for 1000, 'paypalemail@mystore.com',
|
16
|
+
# :amount => 50.00,
|
17
|
+
# :currency => 'CAD',
|
18
|
+
# :service => :paypal,
|
19
|
+
# :html => { :id => 'payment-form' } do |service| %>
|
20
|
+
#
|
21
|
+
# <% service.customer :first_name => 'Cody',
|
22
|
+
# :last_name => 'Fauser',
|
23
|
+
# :phone => '(555)555-5555',
|
24
|
+
# :email => 'codyfauser@gmail.com' %>
|
25
|
+
#
|
26
|
+
# <% service.billing_address :city => 'Ottawa',
|
27
|
+
# :address1 => '21 Snowy Brook Lane',
|
28
|
+
# :address2 => 'Apt. 36',
|
29
|
+
# :state => 'ON',
|
30
|
+
# :country => 'CA',
|
31
|
+
# :zip => 'K1J1E5' %>
|
32
|
+
#
|
33
|
+
# <% service.invoice '#1000' %>
|
34
|
+
# <% service.shipping '0.00' %>
|
35
|
+
# <% service.tax '0.00' %>
|
36
|
+
#
|
37
|
+
# <% service.notify_url url_for(:only_path => false, :action => 'notify') %>
|
38
|
+
# <% service.return_url url_for(:only_path => false, :action => 'done') %>
|
39
|
+
# <% service.cancel_return_url 'http://mystore.com' %>
|
40
|
+
# <% end %>
|
41
|
+
#
|
42
|
+
def payment_service_for(order, account, options = {}, &proc)
|
43
|
+
raise ArgumentError, "Missing block" unless block_given?
|
44
|
+
|
45
|
+
integration_module = ActiveMerchant::Billing::Integrations.const_get(options.delete(:service).to_s.classify)
|
46
|
+
|
47
|
+
if ignore_binding?
|
48
|
+
concat(form_tag(integration_module.service_url, options.delete(:html) || {}))
|
49
|
+
else
|
50
|
+
concat(form_tag(integration_module.service_url, options.delete(:html) || {}), proc.binding)
|
51
|
+
end
|
52
|
+
result = "\n"
|
53
|
+
|
54
|
+
service_class = integration_module.const_get('Helper')
|
55
|
+
service = service_class.new(order, account, options)
|
56
|
+
yield service
|
57
|
+
|
58
|
+
result << service.form_fields.collect do |field, value|
|
59
|
+
hidden_field_tag(field, value)
|
60
|
+
end.join("\n")
|
61
|
+
|
62
|
+
result << "\n"
|
63
|
+
result << '</form>'
|
64
|
+
|
65
|
+
if ignore_binding?
|
66
|
+
concat(result)
|
67
|
+
else
|
68
|
+
concat(result, proc.binding)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
def ignore_binding?
|
74
|
+
ActionPack::VERSION::MAJOR >= 2 && ActionPack::VERSION::MINOR >= 2
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
module Integrations #:nodoc:
|
4
|
+
module Bogus
|
5
|
+
class Helper < ActiveMerchant::Billing::Integrations::Helper
|
6
|
+
mapping :account, 'account'
|
7
|
+
mapping :order, 'order'
|
8
|
+
mapping :amount, 'amount'
|
9
|
+
mapping :currency, 'currency'
|
10
|
+
mapping :customer, :first_name => 'first_name',
|
11
|
+
:last_name => 'last_name'
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
module ActiveMerchant #:nodoc:
|
3
|
+
module Billing #:nodoc:
|
4
|
+
module Integrations #:nodoc:
|
5
|
+
module Bogus
|
6
|
+
autoload :Return, 'active_merchant/billing/integrations/bogus/return.rb'
|
7
|
+
autoload :Helper, 'active_merchant/billing/integrations/bogus/helper.rb'
|
8
|
+
autoload :Notification, 'active_merchant/billing/integrations/bogus/notification.rb'
|
9
|
+
|
10
|
+
mattr_accessor :service_url
|
11
|
+
self.service_url = 'http://www.bogus.com'
|
12
|
+
|
13
|
+
def self.notification(post)
|
14
|
+
Notification.new(post)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.return(query_string)
|
18
|
+
Return.new(query_string)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
module Integrations #:nodoc:
|
4
|
+
module Chronopay
|
5
|
+
class Helper < ActiveMerchant::Billing::Integrations::Helper
|
6
|
+
# All currently supported checkout languages:
|
7
|
+
# es (Spanish)
|
8
|
+
# en (English)
|
9
|
+
# de (German)
|
10
|
+
# pt (Portuguese)
|
11
|
+
# lv (Latvian)
|
12
|
+
# cn1 (Chinese Version 1)
|
13
|
+
# cn2 (Chinese version 2)
|
14
|
+
# nl (Dutch)
|
15
|
+
# ru (Russian)
|
16
|
+
COUNTRIES_FOR_LANG = {
|
17
|
+
'ES' => %w( AR BO CL CO CR CU DO EC SV GQ GT HN MX NI PA PY PE ES UY VE),
|
18
|
+
'DE' => %w( DE AT CH LI ),
|
19
|
+
'PT' => %w( AO BR CV GW MZ PT ST TL),
|
20
|
+
'RU' => %w( BY KG KZ RU ),
|
21
|
+
'LV' => 'LV',
|
22
|
+
'CN1' => 'CN',
|
23
|
+
'NL' => 'NL'
|
24
|
+
}
|
25
|
+
|
26
|
+
LANG_FOR_COUNTRY = COUNTRIES_FOR_LANG.inject(Hash.new("EN")) do |memo, (lang, countries)|
|
27
|
+
countries.each do |code|
|
28
|
+
memo[code] = lang
|
29
|
+
end
|
30
|
+
memo
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
self.country_format = :alpha3
|
35
|
+
|
36
|
+
def initialize(order, account, options = {})
|
37
|
+
super
|
38
|
+
add_field('cb_type', 'p')
|
39
|
+
end
|
40
|
+
|
41
|
+
# product_id
|
42
|
+
mapping :account, 'product_id'
|
43
|
+
# product_name
|
44
|
+
mapping :invoice, 'product_name'
|
45
|
+
# product_price
|
46
|
+
mapping :amount, 'product_price'
|
47
|
+
# product_price_currency
|
48
|
+
mapping :currency, 'product_price_currency'
|
49
|
+
|
50
|
+
# f_name
|
51
|
+
# s_name
|
52
|
+
# email
|
53
|
+
mapping :customer, :first_name => 'f_name',
|
54
|
+
:last_name => 's_name',
|
55
|
+
:phone => 'phone',
|
56
|
+
:email => 'email'
|
57
|
+
|
58
|
+
# city
|
59
|
+
# street
|
60
|
+
# state
|
61
|
+
# zip
|
62
|
+
# country - The country must be a 3 digit country code
|
63
|
+
# phone
|
64
|
+
|
65
|
+
mapping :billing_address, :city => 'city',
|
66
|
+
:address1 => 'street',
|
67
|
+
:state => 'state',
|
68
|
+
:zip => 'zip',
|
69
|
+
:country => 'country'
|
70
|
+
|
71
|
+
def billing_address(mapping = {})
|
72
|
+
# Gets the country code in the appropriate format or returns what we were given
|
73
|
+
# The appropriate format for Chronopay is the alpha 3 country code
|
74
|
+
country_code = lookup_country_code(mapping.delete(:country))
|
75
|
+
add_field(mappings[:billing_address][:country], country_code)
|
76
|
+
|
77
|
+
countries_with_supported_states = ['USA', 'CAN']
|
78
|
+
if !countries_with_supported_states.include?(country_code)
|
79
|
+
mapping.delete(:state)
|
80
|
+
add_field(mappings[:billing_address][:state], 'XX')
|
81
|
+
end
|
82
|
+
mapping.each do |k, v|
|
83
|
+
field = mappings[:billing_address][k]
|
84
|
+
add_field(field, v) unless field.nil?
|
85
|
+
end
|
86
|
+
add_field('language', checkout_language_from_country(country_code))
|
87
|
+
end
|
88
|
+
|
89
|
+
# card_no
|
90
|
+
# exp_month
|
91
|
+
# exp_year
|
92
|
+
mapping :credit_card, :number => 'card_no',
|
93
|
+
:expiry_month => 'exp_month',
|
94
|
+
:expiry_year => 'exp_year'
|
95
|
+
|
96
|
+
# cb_url
|
97
|
+
mapping :notify_url, 'cb_url'
|
98
|
+
|
99
|
+
# cs1
|
100
|
+
mapping :order, 'cs1'
|
101
|
+
|
102
|
+
# cs2
|
103
|
+
# cs3
|
104
|
+
# decline_url
|
105
|
+
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def checkout_language_from_country(country_code)
|
110
|
+
country = Country.find(country_code)
|
111
|
+
short_code = country.code(:alpha2).to_s
|
112
|
+
LANG_FOR_COUNTRY[short_code]
|
113
|
+
rescue InvalidCountryCodeError
|
114
|
+
'EN'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|