start_activemerchant 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 +7 -0
- data/CHANGELOG +1769 -0
- data/CONTRIBUTORS +540 -0
- data/MIT-LICENSE +20 -0
- data/README.md +226 -0
- data/lib/active_merchant.rb +67 -0
- data/lib/active_merchant/billing.rb +15 -0
- data/lib/active_merchant/billing/apple_pay_payment_token.rb +22 -0
- data/lib/active_merchant/billing/avs_result.rb +98 -0
- data/lib/active_merchant/billing/base.rb +72 -0
- data/lib/active_merchant/billing/check.rb +76 -0
- data/lib/active_merchant/billing/compatibility.rb +120 -0
- data/lib/active_merchant/billing/credit_card.rb +404 -0
- data/lib/active_merchant/billing/credit_card_formatting.rb +24 -0
- data/lib/active_merchant/billing/credit_card_methods.rb +195 -0
- data/lib/active_merchant/billing/cvv_result.rb +38 -0
- data/lib/active_merchant/billing/gateway.rb +291 -0
- data/lib/active_merchant/billing/gateways.rb +14 -0
- data/lib/active_merchant/billing/gateways/allied_wallet.rb +203 -0
- data/lib/active_merchant/billing/gateways/app55.rb +176 -0
- data/lib/active_merchant/billing/gateways/authorize_net.rb +510 -0
- data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +417 -0
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +976 -0
- data/lib/active_merchant/billing/gateways/axcessms.rb +181 -0
- data/lib/active_merchant/billing/gateways/balanced.rb +256 -0
- data/lib/active_merchant/billing/gateways/bank_frick.rb +225 -0
- data/lib/active_merchant/billing/gateways/banwire.rb +105 -0
- data/lib/active_merchant/billing/gateways/barclays_epdq.rb +314 -0
- data/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb +15 -0
- data/lib/active_merchant/billing/gateways/be2bill.rb +131 -0
- data/lib/active_merchant/billing/gateways/beanstream.rb +192 -0
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +389 -0
- data/lib/active_merchant/billing/gateways/beanstream_interac.rb +58 -0
- data/lib/active_merchant/billing/gateways/blue_pay.rb +506 -0
- data/lib/active_merchant/billing/gateways/bogus.rb +140 -0
- data/lib/active_merchant/billing/gateways/borgun.rb +211 -0
- data/lib/active_merchant/billing/gateways/bpoint.rb +277 -0
- data/lib/active_merchant/billing/gateways/braintree.rb +19 -0
- data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +574 -0
- data/lib/active_merchant/billing/gateways/braintree_orange.rb +20 -0
- data/lib/active_merchant/billing/gateways/bridge_pay.rb +189 -0
- data/lib/active_merchant/billing/gateways/card_save.rb +23 -0
- data/lib/active_merchant/billing/gateways/card_stream.rb +238 -0
- data/lib/active_merchant/billing/gateways/cashnet.rb +202 -0
- data/lib/active_merchant/billing/gateways/cc5.rb +201 -0
- data/lib/active_merchant/billing/gateways/cecabank.rb +229 -0
- data/lib/active_merchant/billing/gateways/cenpos.rb +262 -0
- data/lib/active_merchant/billing/gateways/certo_direct.rb +278 -0
- data/lib/active_merchant/billing/gateways/checkout.rb +216 -0
- data/lib/active_merchant/billing/gateways/checkout_v2.rb +200 -0
- data/lib/active_merchant/billing/gateways/commercegate.rb +143 -0
- data/lib/active_merchant/billing/gateways/conekta.rb +210 -0
- data/lib/active_merchant/billing/gateways/cyber_source.rb +720 -0
- data/lib/active_merchant/billing/gateways/data_cash.rb +600 -0
- data/lib/active_merchant/billing/gateways/dibs.rb +206 -0
- data/lib/active_merchant/billing/gateways/efsnet.rb +219 -0
- data/lib/active_merchant/billing/gateways/elavon.rb +348 -0
- data/lib/active_merchant/billing/gateways/epay.rb +274 -0
- data/lib/active_merchant/billing/gateways/evo_ca.rb +308 -0
- data/lib/active_merchant/billing/gateways/eway.rb +214 -0
- data/lib/active_merchant/billing/gateways/eway_managed.rb +291 -0
- data/lib/active_merchant/billing/gateways/eway_rapid.rb +522 -0
- data/lib/active_merchant/billing/gateways/exact.rb +227 -0
- data/lib/active_merchant/billing/gateways/ezic.rb +206 -0
- data/lib/active_merchant/billing/gateways/fat_zebra.rb +213 -0
- data/lib/active_merchant/billing/gateways/federated_canada.rb +160 -0
- data/lib/active_merchant/billing/gateways/finansbank.rb +23 -0
- data/lib/active_merchant/billing/gateways/first_giving.rb +143 -0
- data/lib/active_merchant/billing/gateways/first_pay.rb +160 -0
- data/lib/active_merchant/billing/gateways/firstdata_e4.rb +413 -0
- data/lib/active_merchant/billing/gateways/flo2cash.rb +215 -0
- data/lib/active_merchant/billing/gateways/flo2cash_simple.rb +20 -0
- data/lib/active_merchant/billing/gateways/garanti.rb +261 -0
- data/lib/active_merchant/billing/gateways/global_transport.rb +179 -0
- data/lib/active_merchant/billing/gateways/hdfc.rb +207 -0
- data/lib/active_merchant/billing/gateways/hps.rb +287 -0
- data/lib/active_merchant/billing/gateways/iats_payments.rb +277 -0
- data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +246 -0
- data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
- data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
- data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +66 -0
- data/lib/active_merchant/billing/gateways/inspire.rb +219 -0
- data/lib/active_merchant/billing/gateways/instapay.rb +163 -0
- data/lib/active_merchant/billing/gateways/ipp.rb +175 -0
- data/lib/active_merchant/billing/gateways/iridium.rb +457 -0
- data/lib/active_merchant/billing/gateways/itransact.rb +448 -0
- data/lib/active_merchant/billing/gateways/jetpay.rb +275 -0
- data/lib/active_merchant/billing/gateways/linkpoint.rb +438 -0
- data/lib/active_merchant/billing/gateways/litle.rb +345 -0
- data/lib/active_merchant/billing/gateways/maxipago.rb +197 -0
- data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +170 -0
- data/lib/active_merchant/billing/gateways/merchant_one.rb +114 -0
- data/lib/active_merchant/billing/gateways/merchant_partners.rb +245 -0
- data/lib/active_merchant/billing/gateways/merchant_ware.rb +319 -0
- data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +268 -0
- data/lib/active_merchant/billing/gateways/merchant_warrior.rb +195 -0
- data/lib/active_merchant/billing/gateways/mercury.rb +326 -0
- data/lib/active_merchant/billing/gateways/metrics_global.rb +303 -0
- data/lib/active_merchant/billing/gateways/migs.rb +280 -0
- data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
- data/lib/active_merchant/billing/gateways/modern_payments.rb +37 -0
- data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +219 -0
- data/lib/active_merchant/billing/gateways/monei.rb +307 -0
- data/lib/active_merchant/billing/gateways/moneris.rb +309 -0
- data/lib/active_merchant/billing/gateways/moneris_us.rb +298 -0
- data/lib/active_merchant/billing/gateways/money_movers.rb +152 -0
- data/lib/active_merchant/billing/gateways/nab_transact.rb +290 -0
- data/lib/active_merchant/billing/gateways/net_registry.rb +198 -0
- data/lib/active_merchant/billing/gateways/netaxept.rb +181 -0
- data/lib/active_merchant/billing/gateways/netbilling.rb +224 -0
- data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
- data/lib/active_merchant/billing/gateways/network_merchants.rb +242 -0
- data/lib/active_merchant/billing/gateways/nmi.rb +256 -0
- data/lib/active_merchant/billing/gateways/ogone.rb +435 -0
- data/lib/active_merchant/billing/gateways/omise.rb +319 -0
- data/lib/active_merchant/billing/gateways/openpay.rb +194 -0
- data/lib/active_merchant/billing/gateways/optimal_payment.rb +314 -0
- data/lib/active_merchant/billing/gateways/orbital.rb +834 -0
- data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +47 -0
- data/lib/active_merchant/billing/gateways/pac_net_raven.rb +207 -0
- data/lib/active_merchant/billing/gateways/pago_facil.rb +122 -0
- data/lib/active_merchant/billing/gateways/pay_conex.rb +246 -0
- data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +277 -0
- data/lib/active_merchant/billing/gateways/pay_hub.rb +213 -0
- data/lib/active_merchant/billing/gateways/pay_junction.rb +390 -0
- data/lib/active_merchant/billing/gateways/pay_secure.rb +112 -0
- data/lib/active_merchant/billing/gateways/paybox_direct.rb +188 -0
- data/lib/active_merchant/billing/gateways/payex.rb +412 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +308 -0
- data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +220 -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_express.rb +224 -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 +353 -0
- data/lib/active_merchant/billing/gateways/paymill.rb +282 -0
- data/lib/active_merchant/billing/gateways/paypal.rb +129 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +679 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +65 -0
- data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +262 -0
- data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
- data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +44 -0
- data/lib/active_merchant/billing/gateways/paypal_express.rb +264 -0
- data/lib/active_merchant/billing/gateways/paypal_express_common.rb +30 -0
- data/lib/active_merchant/billing/gateways/payscout.rb +162 -0
- data/lib/active_merchant/billing/gateways/paystation.rb +199 -0
- data/lib/active_merchant/billing/gateways/payu_in.rb +247 -0
- data/lib/active_merchant/billing/gateways/payway.rb +207 -0
- data/lib/active_merchant/billing/gateways/pin.rb +207 -0
- data/lib/active_merchant/billing/gateways/plugnpay.rb +283 -0
- data/lib/active_merchant/billing/gateways/psigate.rb +216 -0
- data/lib/active_merchant/billing/gateways/psl_card.rb +303 -0
- data/lib/active_merchant/billing/gateways/qbms.rb +292 -0
- data/lib/active_merchant/billing/gateways/quantum.rb +276 -0
- data/lib/active_merchant/billing/gateways/quickbooks.rb +280 -0
- data/lib/active_merchant/billing/gateways/quickpay.rb +26 -0
- 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/qvalent.rb +179 -0
- data/lib/active_merchant/billing/gateways/realex.rb +298 -0
- data/lib/active_merchant/billing/gateways/redsys.rb +406 -0
- data/lib/active_merchant/billing/gateways/s5.rb +226 -0
- data/lib/active_merchant/billing/gateways/sage.rb +173 -0
- data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +89 -0
- data/lib/active_merchant/billing/gateways/sage/sage_core.rb +115 -0
- data/lib/active_merchant/billing/gateways/sage/sage_vault.rb +149 -0
- data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
- data/lib/active_merchant/billing/gateways/sage_pay.rb +399 -0
- data/lib/active_merchant/billing/gateways/sallie_mae.rb +143 -0
- data/lib/active_merchant/billing/gateways/secure_net.rb +263 -0
- data/lib/active_merchant/billing/gateways/secure_pay.rb +201 -0
- data/lib/active_merchant/billing/gateways/secure_pay_au.rb +281 -0
- data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +105 -0
- data/lib/active_merchant/billing/gateways/skip_jack.rb +451 -0
- data/lib/active_merchant/billing/gateways/smart_ps.rb +283 -0
- data/lib/active_merchant/billing/gateways/so_easy_pay.rb +194 -0
- data/lib/active_merchant/billing/gateways/spreedly_core.rb +247 -0
- data/lib/active_merchant/billing/gateways/stripe.rb +489 -0
- data/lib/active_merchant/billing/gateways/swipe_checkout.rb +157 -0
- data/lib/active_merchant/billing/gateways/tns.rb +227 -0
- data/lib/active_merchant/billing/gateways/trans_first.rb +126 -0
- data/lib/active_merchant/billing/gateways/transax.rb +23 -0
- data/lib/active_merchant/billing/gateways/transnational.rb +10 -0
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +416 -0
- data/lib/active_merchant/billing/gateways/usa_epay.rb +25 -0
- data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1516 -0
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +259 -0
- data/lib/active_merchant/billing/gateways/vanco.rb +280 -0
- data/lib/active_merchant/billing/gateways/verifi.rb +225 -0
- data/lib/active_merchant/billing/gateways/viaklix.rb +183 -0
- data/lib/active_merchant/billing/gateways/webpay.rb +97 -0
- data/lib/active_merchant/billing/gateways/wepay.rb +205 -0
- data/lib/active_merchant/billing/gateways/wirecard.rb +420 -0
- data/lib/active_merchant/billing/gateways/worldpay.rb +331 -0
- data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +204 -0
- data/lib/active_merchant/billing/gateways/worldpay_us.rb +181 -0
- data/lib/active_merchant/billing/model.rb +30 -0
- data/lib/active_merchant/billing/network_tokenization_credit_card.rb +24 -0
- data/lib/active_merchant/billing/payment_token.rb +21 -0
- data/lib/active_merchant/billing/rails.rb +3 -0
- data/lib/active_merchant/billing/response.rb +92 -0
- data/lib/active_merchant/connection.rb +172 -0
- data/lib/active_merchant/country.rb +332 -0
- data/lib/active_merchant/empty.rb +20 -0
- data/lib/active_merchant/errors.rb +35 -0
- data/lib/active_merchant/network_connection_retries.rb +79 -0
- data/lib/active_merchant/post_data.rb +24 -0
- data/lib/active_merchant/posts_data.rb +84 -0
- data/lib/active_merchant/version.rb +3 -0
- data/lib/activemerchant.rb +1 -0
- data/lib/certs/cacert.pem +3866 -0
- data/lib/support/gateway_support.rb +71 -0
- data/lib/support/outbound_hosts.rb +28 -0
- data/lib/support/ssl_verify.rb +93 -0
- metadata +387 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
require 'nokogiri'
|
|
3
|
+
|
|
4
|
+
module ActiveMerchant #:nodoc:
|
|
5
|
+
module Billing #:nodoc:
|
|
6
|
+
# = Redsys Merchant Gateway
|
|
7
|
+
#
|
|
8
|
+
# Gateway support for the Spanish "Redsys" payment gateway system. This is
|
|
9
|
+
# used by many banks in Spain and is particularly well supported by
|
|
10
|
+
# Catalunya Caixa's ecommerce department.
|
|
11
|
+
#
|
|
12
|
+
# Redsys requires an order_id be provided with each transaction and it must
|
|
13
|
+
# follow a specific format. The rules are as follows:
|
|
14
|
+
#
|
|
15
|
+
# * First 4 digits must be numerical
|
|
16
|
+
# * Remaining 8 digits may be alphanumeric
|
|
17
|
+
# * Max length: 12
|
|
18
|
+
#
|
|
19
|
+
# If an invalid order_id is provided, we do our best to clean it up.
|
|
20
|
+
#
|
|
21
|
+
# Much of the code for this library is based on the active_merchant_sermepa
|
|
22
|
+
# integration gateway which uses essentially the same API but with the
|
|
23
|
+
# banks own payment screen.
|
|
24
|
+
#
|
|
25
|
+
# Written by Samuel Lown for Cabify. For implementation questions, or
|
|
26
|
+
# test access details please get in touch: sam@cabify.com.
|
|
27
|
+
class RedsysGateway < Gateway
|
|
28
|
+
self.live_url = "https://sis.sermepa.es/sis/operaciones"
|
|
29
|
+
self.test_url = "https://sis-t.redsys.es:25443/sis/operaciones"
|
|
30
|
+
|
|
31
|
+
self.supported_countries = ['ES']
|
|
32
|
+
self.default_currency = 'EUR'
|
|
33
|
+
self.money_format = :cents
|
|
34
|
+
|
|
35
|
+
# Not all card types may be activated by the bank!
|
|
36
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :jcb, :diners_club]
|
|
37
|
+
self.homepage_url = "http://www.redsys.es/"
|
|
38
|
+
self.display_name = "Redsys"
|
|
39
|
+
|
|
40
|
+
CURRENCY_CODES = {
|
|
41
|
+
"ARS" => '032',
|
|
42
|
+
"AUD" => '036',
|
|
43
|
+
"BRL" => '986',
|
|
44
|
+
"BOB" => '068',
|
|
45
|
+
"CAD" => '124',
|
|
46
|
+
"CHF" => '756',
|
|
47
|
+
"CLP" => '152',
|
|
48
|
+
"COP" => '170',
|
|
49
|
+
"EUR" => '978',
|
|
50
|
+
"GBP" => '826',
|
|
51
|
+
"GTQ" => '320',
|
|
52
|
+
"JPY" => '392',
|
|
53
|
+
"MYR" => '458',
|
|
54
|
+
"MXN" => '484',
|
|
55
|
+
"NZD" => '554',
|
|
56
|
+
"PEN" => '604',
|
|
57
|
+
"RUB" => '643',
|
|
58
|
+
"SGD" => '702',
|
|
59
|
+
"USD" => '840',
|
|
60
|
+
"UYU" => '858'
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# The set of supported transactions for this gateway.
|
|
64
|
+
# More operations are supported by the gateway itself, but
|
|
65
|
+
# are not supported in this library.
|
|
66
|
+
SUPPORTED_TRANSACTIONS = {
|
|
67
|
+
:purchase => 'A',
|
|
68
|
+
:authorize => '1',
|
|
69
|
+
:capture => '2',
|
|
70
|
+
:refund => '3',
|
|
71
|
+
:cancel => '9'
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# These are the text meanings sent back by the acquirer when
|
|
75
|
+
# a card has been rejected. Syntax or general request errors
|
|
76
|
+
# are not covered here.
|
|
77
|
+
RESPONSE_TEXTS = {
|
|
78
|
+
0 => "Transaction Approved",
|
|
79
|
+
400 => "Cancellation Accepted",
|
|
80
|
+
481 => "Cancellation Accepted",
|
|
81
|
+
500 => "Reconciliation Accepted",
|
|
82
|
+
900 => "Refund / Confirmation approved",
|
|
83
|
+
|
|
84
|
+
101 => "Card expired",
|
|
85
|
+
102 => "Card blocked temporarily or under susciption of fraud",
|
|
86
|
+
104 => "Transaction not permitted",
|
|
87
|
+
107 => "Contact the card issuer",
|
|
88
|
+
109 => "Invalid identification by merchant or POS terminal",
|
|
89
|
+
110 => "Invalid amount",
|
|
90
|
+
114 => "Card cannot be used to the requested transaction",
|
|
91
|
+
116 => "Insufficient credit",
|
|
92
|
+
118 => "Non-registered card",
|
|
93
|
+
125 => "Card not effective",
|
|
94
|
+
129 => "CVV2/CVC2 Error",
|
|
95
|
+
167 => "Contact the card issuer: suspected fraud",
|
|
96
|
+
180 => "Card out of service",
|
|
97
|
+
181 => "Card with credit or debit restrictions",
|
|
98
|
+
182 => "Card with credit or debit restrictions",
|
|
99
|
+
184 => "Authentication error",
|
|
100
|
+
190 => "Refusal with no specific reason",
|
|
101
|
+
191 => "Expiry date incorrect",
|
|
102
|
+
|
|
103
|
+
201 => "Card expired",
|
|
104
|
+
202 => "Card blocked temporarily or under suspicion of fraud",
|
|
105
|
+
204 => "Transaction not permitted",
|
|
106
|
+
207 => "Contact the card issuer",
|
|
107
|
+
208 => "Lost or stolen card",
|
|
108
|
+
209 => "Lost or stolen card",
|
|
109
|
+
280 => "CVV2/CVC2 Error",
|
|
110
|
+
290 => "Declined with no specific reason",
|
|
111
|
+
|
|
112
|
+
480 => "Original transaction not located, or time-out exceeded",
|
|
113
|
+
501 => "Original transaction not located, or time-out exceeded",
|
|
114
|
+
502 => "Original transaction not located, or time-out exceeded",
|
|
115
|
+
503 => "Original transaction not located, or time-out exceeded",
|
|
116
|
+
|
|
117
|
+
904 => "Merchant not registered at FUC",
|
|
118
|
+
909 => "System error",
|
|
119
|
+
912 => "Issuer not available",
|
|
120
|
+
913 => "Duplicate transmission",
|
|
121
|
+
916 => "Amount too low",
|
|
122
|
+
928 => "Time-out exceeded",
|
|
123
|
+
940 => "Transaction cancelled previously",
|
|
124
|
+
941 => "Authorization operation already cancelled",
|
|
125
|
+
942 => "Original authorization declined",
|
|
126
|
+
943 => "Different details from origin transaction",
|
|
127
|
+
944 => "Session error",
|
|
128
|
+
945 => "Duplicate transmission",
|
|
129
|
+
946 => "Cancellation of transaction while in progress",
|
|
130
|
+
947 => "Duplicate tranmission while in progress",
|
|
131
|
+
949 => "POS Inoperative",
|
|
132
|
+
950 => "Refund not possible",
|
|
133
|
+
9064 => "Card number incorrect",
|
|
134
|
+
9078 => "No payment method available",
|
|
135
|
+
9093 => "Non-existent card",
|
|
136
|
+
9218 => "Recursive transaction in bad gateway",
|
|
137
|
+
9253 => "Check-digit incorrect",
|
|
138
|
+
9256 => "Preauth not allowed for merchant",
|
|
139
|
+
9257 => "Preauth not allowed for card",
|
|
140
|
+
9261 => "Operating limit exceeded",
|
|
141
|
+
9912 => "Issuer not available",
|
|
142
|
+
9913 => "Confirmation error",
|
|
143
|
+
9914 => "KO Confirmation"
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
# Creates a new instance
|
|
147
|
+
#
|
|
148
|
+
# Redsys requires a login and secret_key, and optionally also accepts a
|
|
149
|
+
# non-default terminal.
|
|
150
|
+
#
|
|
151
|
+
# ==== Options
|
|
152
|
+
#
|
|
153
|
+
# * <tt>:login</tt> -- The Redsys Merchant ID (REQUIRED)
|
|
154
|
+
# * <tt>:secret_key</tt> -- The Redsys Secret Key. (REQUIRED)
|
|
155
|
+
# * <tt>:terminal</tt> -- The Redsys Terminal. Defaults to 1. (OPTIONAL)
|
|
156
|
+
# * <tt>:test</tt> -- +true+ or +false+. Defaults to +false+. (OPTIONAL)
|
|
157
|
+
def initialize(options = {})
|
|
158
|
+
requires!(options, :login, :secret_key)
|
|
159
|
+
options[:terminal] ||= 1
|
|
160
|
+
super
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def purchase(money, payment, options = {})
|
|
164
|
+
requires!(options, :order_id)
|
|
165
|
+
|
|
166
|
+
data = {}
|
|
167
|
+
add_action(data, :purchase)
|
|
168
|
+
add_amount(data, money, options)
|
|
169
|
+
add_order(data, options[:order_id])
|
|
170
|
+
add_payment(data, payment)
|
|
171
|
+
data[:description] = options[:description]
|
|
172
|
+
data[:store_in_vault] = options[:store]
|
|
173
|
+
|
|
174
|
+
commit data
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def authorize(money, payment, options = {})
|
|
178
|
+
requires!(options, :order_id)
|
|
179
|
+
|
|
180
|
+
data = {}
|
|
181
|
+
add_action(data, :authorize)
|
|
182
|
+
add_amount(data, money, options)
|
|
183
|
+
add_order(data, options[:order_id])
|
|
184
|
+
add_payment(data, payment)
|
|
185
|
+
data[:description] = options[:description]
|
|
186
|
+
data[:store_in_vault] = options[:store]
|
|
187
|
+
|
|
188
|
+
commit data
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def capture(money, authorization, options = {})
|
|
192
|
+
data = {}
|
|
193
|
+
add_action(data, :capture)
|
|
194
|
+
add_amount(data, money, options)
|
|
195
|
+
order_id, _, _ = split_authorization(authorization)
|
|
196
|
+
add_order(data, order_id)
|
|
197
|
+
data[:description] = options[:description]
|
|
198
|
+
|
|
199
|
+
commit data
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def void(authorization, options = {})
|
|
203
|
+
data = {}
|
|
204
|
+
add_action(data, :cancel)
|
|
205
|
+
order_id, amount, currency = split_authorization(authorization)
|
|
206
|
+
add_amount(data, amount, :currency => currency)
|
|
207
|
+
add_order(data, order_id)
|
|
208
|
+
data[:description] = options[:description]
|
|
209
|
+
|
|
210
|
+
commit data
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def refund(money, authorization, options = {})
|
|
214
|
+
data = {}
|
|
215
|
+
add_action(data, :refund)
|
|
216
|
+
add_amount(data, money, options)
|
|
217
|
+
order_id, _, _ = split_authorization(authorization)
|
|
218
|
+
add_order(data, order_id)
|
|
219
|
+
data[:description] = options[:description]
|
|
220
|
+
|
|
221
|
+
commit data
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def verify(creditcard, options = {})
|
|
225
|
+
MultiResponse.run(:use_first_response) do |r|
|
|
226
|
+
r.process { authorize(100, creditcard, options) }
|
|
227
|
+
r.process(:ignore_result) { void(r.authorization, options) }
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
private
|
|
232
|
+
|
|
233
|
+
def add_action(data, action)
|
|
234
|
+
data[:action] = transaction_code(action)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def add_amount(data, money, options)
|
|
238
|
+
data[:amount] = amount(money).to_s
|
|
239
|
+
data[:currency] = currency_code(options[:currency] || currency(money))
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def add_order(data, order_id)
|
|
243
|
+
data[:order_id] = clean_order_id(order_id)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def url
|
|
247
|
+
test? ? test_url : live_url
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def add_payment(data, card)
|
|
251
|
+
if card.is_a?(String)
|
|
252
|
+
data[:credit_card_token] = card
|
|
253
|
+
else
|
|
254
|
+
name = [card.first_name, card.last_name].join(' ').slice(0, 60)
|
|
255
|
+
year = sprintf("%.4i", card.year)
|
|
256
|
+
month = sprintf("%.2i", card.month)
|
|
257
|
+
data[:card] = {
|
|
258
|
+
:name => name,
|
|
259
|
+
:pan => card.number,
|
|
260
|
+
:date => "#{year[2..3]}#{month}",
|
|
261
|
+
:cvv => card.verification_value
|
|
262
|
+
}
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def commit(data)
|
|
267
|
+
headers = {
|
|
268
|
+
'Content-Type' => 'application/x-www-form-urlencoded'
|
|
269
|
+
}
|
|
270
|
+
xml = build_xml_request(data)
|
|
271
|
+
parse(ssl_post(url, "entrada=#{CGI.escape(xml)}", headers))
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def build_signature(data)
|
|
275
|
+
str = data[:amount] +
|
|
276
|
+
data[:order_id].to_s +
|
|
277
|
+
@options[:login].to_s +
|
|
278
|
+
data[:currency]
|
|
279
|
+
|
|
280
|
+
if card = data[:card]
|
|
281
|
+
str << card[:pan]
|
|
282
|
+
str << card[:cvv] if card[:cvv]
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
str << data[:action]
|
|
286
|
+
if data[:store_in_vault]
|
|
287
|
+
str << 'REQUIRED'
|
|
288
|
+
elsif data[:credit_card_token]
|
|
289
|
+
str << data[:credit_card_token]
|
|
290
|
+
end
|
|
291
|
+
str << @options[:secret_key]
|
|
292
|
+
|
|
293
|
+
Digest::SHA1.hexdigest(str)
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def build_xml_request(data)
|
|
297
|
+
xml = Builder::XmlMarkup.new :indent => 2
|
|
298
|
+
xml.DATOSENTRADA do
|
|
299
|
+
# Basic elements
|
|
300
|
+
xml.DS_Version 0.1
|
|
301
|
+
xml.DS_MERCHANT_CURRENCY data[:currency]
|
|
302
|
+
xml.DS_MERCHANT_AMOUNT data[:amount]
|
|
303
|
+
xml.DS_MERCHANT_ORDER data[:order_id]
|
|
304
|
+
xml.DS_MERCHANT_TRANSACTIONTYPE data[:action]
|
|
305
|
+
xml.DS_MERCHANT_PRODUCTDESCRIPTION data[:description]
|
|
306
|
+
xml.DS_MERCHANT_TERMINAL @options[:terminal]
|
|
307
|
+
xml.DS_MERCHANT_MERCHANTCODE @options[:login]
|
|
308
|
+
xml.DS_MERCHANT_MERCHANTSIGNATURE build_signature(data)
|
|
309
|
+
|
|
310
|
+
# Only when card is present
|
|
311
|
+
if data[:card]
|
|
312
|
+
xml.DS_MERCHANT_TITULAR data[:card][:name]
|
|
313
|
+
xml.DS_MERCHANT_PAN data[:card][:pan]
|
|
314
|
+
xml.DS_MERCHANT_EXPIRYDATE data[:card][:date]
|
|
315
|
+
xml.DS_MERCHANT_CVV2 data[:card][:cvv]
|
|
316
|
+
xml.DS_MERCHANT_IDENTIFIER 'REQUIRED' if data[:store_in_vault]
|
|
317
|
+
elsif data[:credit_card_token]
|
|
318
|
+
xml.DS_MERCHANT_IDENTIFIER data[:credit_card_token]
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
xml.target!
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def parse(data)
|
|
325
|
+
params = {}
|
|
326
|
+
success = false
|
|
327
|
+
message = ""
|
|
328
|
+
options = @options.merge(:test => test?)
|
|
329
|
+
xml = Nokogiri::XML(data)
|
|
330
|
+
code = xml.xpath("//RETORNOXML/CODIGO").text
|
|
331
|
+
if code == "0"
|
|
332
|
+
op = xml.xpath("//RETORNOXML/OPERACION")
|
|
333
|
+
op.children.each do |element|
|
|
334
|
+
params[element.name.downcase.to_sym] = element.text
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
if validate_signature(params)
|
|
338
|
+
message = response_text(params[:ds_response])
|
|
339
|
+
options[:authorization] = build_authorization(params)
|
|
340
|
+
success = is_success_response?(params[:ds_response])
|
|
341
|
+
else
|
|
342
|
+
message = "Response failed validation check"
|
|
343
|
+
end
|
|
344
|
+
else
|
|
345
|
+
# Some kind of programmer error with the request!
|
|
346
|
+
message = "#{code} ERROR"
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
Response.new(success, message, params, options)
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
def validate_signature(data)
|
|
353
|
+
str = data[:ds_amount] +
|
|
354
|
+
data[:ds_order].to_s +
|
|
355
|
+
data[:ds_merchantcode] +
|
|
356
|
+
data[:ds_currency] +
|
|
357
|
+
data[:ds_response] +
|
|
358
|
+
data[:ds_cardnumber].to_s +
|
|
359
|
+
data[:ds_transactiontype].to_s +
|
|
360
|
+
data[:ds_securepayment].to_s +
|
|
361
|
+
@options[:secret_key]
|
|
362
|
+
|
|
363
|
+
sig = Digest::SHA1.hexdigest(str)
|
|
364
|
+
data[:ds_signature].to_s.downcase == sig
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
def build_authorization(params)
|
|
368
|
+
[params[:ds_order], params[:ds_amount], params[:ds_currency]].join("|")
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def split_authorization(authorization)
|
|
372
|
+
order_id, amount, currency = authorization.split("|")
|
|
373
|
+
[order_id, amount.to_i, currency]
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def currency_code(currency)
|
|
377
|
+
return currency if currency =~ /^\d+$/
|
|
378
|
+
raise ArgumentError, "Unknown currency #{currency}" unless CURRENCY_CODES[currency]
|
|
379
|
+
CURRENCY_CODES[currency]
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
def transaction_code(type)
|
|
383
|
+
SUPPORTED_TRANSACTIONS[type]
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def response_text(code)
|
|
387
|
+
code = code.to_i
|
|
388
|
+
code = 0 if code < 100
|
|
389
|
+
RESPONSE_TEXTS[code] || "Unkown code, please check in manual"
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def is_success_response?(code)
|
|
393
|
+
(code.to_i < 100) || [400, 481, 500, 900].include?(code.to_i)
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
def clean_order_id(order_id)
|
|
397
|
+
cleansed = order_id.gsub(/[^\da-zA-Z]/, '')
|
|
398
|
+
if cleansed =~ /^\d{4}/
|
|
399
|
+
cleansed[0..11]
|
|
400
|
+
else
|
|
401
|
+
"%04d%s" % [rand(0..9999), cleansed[0...8]]
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
end
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
require 'nokogiri'
|
|
2
|
+
|
|
3
|
+
module ActiveMerchant #:nodoc:
|
|
4
|
+
module Billing #:nodoc:
|
|
5
|
+
class S5Gateway < Gateway
|
|
6
|
+
self.test_url = 'https://test.ctpe.io/payment/ctpe'
|
|
7
|
+
self.live_url = 'https://ctpe.io/payment/ctpe'
|
|
8
|
+
|
|
9
|
+
self.supported_countries = ['DK']
|
|
10
|
+
self.default_currency = 'EUR'
|
|
11
|
+
self.supported_cardtypes = [:visa, :master, :maestro]
|
|
12
|
+
|
|
13
|
+
self.homepage_url = 'http://www.s5.dk/'
|
|
14
|
+
self.display_name = 'S5'
|
|
15
|
+
|
|
16
|
+
SUPPORTED_TRANSACTIONS = {
|
|
17
|
+
'sale' => 'CC.DB',
|
|
18
|
+
'authonly' => 'CC.PA',
|
|
19
|
+
'capture' => 'CC.CP',
|
|
20
|
+
'refund' => 'CC.RF',
|
|
21
|
+
'void' => 'CC.RV',
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
def initialize(options={})
|
|
25
|
+
requires!(options, :sender, :channel, :login, :password)
|
|
26
|
+
super
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def purchase(money, payment, options={})
|
|
30
|
+
request = build_xml_request do |xml|
|
|
31
|
+
add_payment(xml, money, 'sale', options)
|
|
32
|
+
add_account(xml, payment)
|
|
33
|
+
add_customer(xml, payment, options)
|
|
34
|
+
add_recurrence_mode(xml, options)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
commit(request)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def refund(money, authorization, options={})
|
|
41
|
+
request = build_xml_request do |xml|
|
|
42
|
+
add_identification(xml, authorization)
|
|
43
|
+
add_payment(xml, money, 'refund', options)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
commit(request)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def authorize(money, payment, options={})
|
|
50
|
+
request = build_xml_request do |xml|
|
|
51
|
+
add_payment(xml, money, 'authonly', options)
|
|
52
|
+
add_account(xml, payment)
|
|
53
|
+
add_customer(xml, payment, options)
|
|
54
|
+
add_recurrence_mode(xml, options)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
commit(request)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def capture(money, authorization, options={})
|
|
61
|
+
request = build_xml_request do |xml|
|
|
62
|
+
add_identification(xml, authorization)
|
|
63
|
+
add_payment(xml, money, 'capture', options)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
commit(request)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def void(authorization, options={})
|
|
70
|
+
request = build_xml_request do |xml|
|
|
71
|
+
add_identification(xml, authorization)
|
|
72
|
+
add_payment(xml, nil, 'void', options)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
commit(request)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def verify(credit_card, options={})
|
|
79
|
+
MultiResponse.run(:use_first_response) do |r|
|
|
80
|
+
r.process { authorize(100, credit_card, options) }
|
|
81
|
+
r.process(:ignore_result) { void(r.authorization, options) }
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def supports_scrubbing?
|
|
86
|
+
true
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def scrub(transcript)
|
|
90
|
+
transcript.
|
|
91
|
+
gsub(%r((pwd=).+?(/>))i, '\1[FILTERED]\2').
|
|
92
|
+
gsub(%r((<Number>).+?(</Number>))i, '\1[FILTERED]\2').
|
|
93
|
+
gsub(%r((<Verification>).+?(</Verification>))i, '\1[FILTERED]\2')
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
def add_identification(xml, authorization)
|
|
99
|
+
xml.Identification do
|
|
100
|
+
xml.ReferenceID authorization
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def add_payment(xml, money, action, options)
|
|
105
|
+
xml.Payment(code: SUPPORTED_TRANSACTIONS[action]) do
|
|
106
|
+
xml.Memo "return_code=#{options[:memo]}" if options[:memo]
|
|
107
|
+
xml.Presentation do
|
|
108
|
+
xml.Amount amount(money)
|
|
109
|
+
xml.Currency options[:currency] || currency(money)
|
|
110
|
+
xml.Usage options[:description]
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def add_account(xml, creditcard)
|
|
116
|
+
xml.Account do
|
|
117
|
+
xml.Number creditcard.number
|
|
118
|
+
xml.Holder "#{creditcard.first_name} #{creditcard.last_name}"
|
|
119
|
+
xml.Brand creditcard.brand
|
|
120
|
+
xml.Expiry(year: creditcard.year, month: creditcard.month)
|
|
121
|
+
xml.Verification creditcard.verification_value
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def add_customer(xml, creditcard, options)
|
|
126
|
+
address = options[:billing_address]
|
|
127
|
+
xml.Customer do
|
|
128
|
+
xml.Contact do
|
|
129
|
+
xml.Email options[:email]
|
|
130
|
+
xml.Ip options[:ip]
|
|
131
|
+
xml.Phone address[:phone] if address
|
|
132
|
+
end
|
|
133
|
+
add_address(xml, address)
|
|
134
|
+
xml.Name do
|
|
135
|
+
xml.Given creditcard.first_name
|
|
136
|
+
xml.Family creditcard.last_name
|
|
137
|
+
xml.Company options[:company]
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def add_address(xml, address)
|
|
143
|
+
return unless address
|
|
144
|
+
|
|
145
|
+
xml.Address do
|
|
146
|
+
xml.Street "#{address[:address1]} #{address[:address2]}"
|
|
147
|
+
xml.Zip address[:zip]
|
|
148
|
+
xml.City address[:city]
|
|
149
|
+
xml.State address[:state]
|
|
150
|
+
xml.Country address[:country]
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def add_recurrence_mode(xml, options)
|
|
155
|
+
if options[:recurring] == true
|
|
156
|
+
xml.Recurrence(mode: "REPEATED")
|
|
157
|
+
else
|
|
158
|
+
xml.Recurrence(mode: "INITIAL")
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def parse(body)
|
|
163
|
+
results = {}
|
|
164
|
+
xml = Nokogiri::XML(body)
|
|
165
|
+
resp = xml.xpath("//Response/Transaction/Identification")
|
|
166
|
+
resp.children.each do |element|
|
|
167
|
+
results[element.name.downcase.to_sym] = element.text
|
|
168
|
+
end
|
|
169
|
+
resp = xml.xpath("//Response/Transaction/Processing")
|
|
170
|
+
resp.children.each do |element|
|
|
171
|
+
results[element.name.downcase.to_sym] = element.text
|
|
172
|
+
end
|
|
173
|
+
results
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def commit(xml)
|
|
177
|
+
url = (test? ? test_url : live_url)
|
|
178
|
+
headers = {
|
|
179
|
+
'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
response = parse(ssl_post(url, post_data(xml), headers))
|
|
183
|
+
|
|
184
|
+
Response.new(
|
|
185
|
+
success_from(response),
|
|
186
|
+
message_from(response),
|
|
187
|
+
response,
|
|
188
|
+
authorization: authorization_from(response),
|
|
189
|
+
test: test?
|
|
190
|
+
)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def success_from(response)
|
|
194
|
+
response[:result] == 'ACK'
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def message_from(response)
|
|
198
|
+
response[:return]
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def authorization_from(response)
|
|
202
|
+
response[:uniqueid]
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def post_data(xml)
|
|
206
|
+
"load=#{xml}"
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def build_xml_request
|
|
210
|
+
builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
|
211
|
+
xml.Request(version: '1.0') do
|
|
212
|
+
xml.Header do
|
|
213
|
+
xml.Security(sender: @options[:sender])
|
|
214
|
+
end
|
|
215
|
+
xml.Transaction(mode: @options[:mode] || 'LIVE', channel: @options[:channel]) do
|
|
216
|
+
xml.User(login: @options[:login], pwd: @options[:password])
|
|
217
|
+
yield(xml)
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
builder.to_xml
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|