activemerchant 1.42.7 → 1.42.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +2 -3
- data/CHANGELOG +10 -0
- data/lib/active_merchant/billing/gateways/cecabank.rb +6 -6
- data/lib/active_merchant/billing/gateways/iridium.rb +173 -0
- data/lib/active_merchant/billing/gateways/litle.rb +196 -456
- data/lib/active_merchant/billing/gateways/paypal_express_common.rb +1 -1
- data/lib/active_merchant/billing/gateways/wirecard.rb +7 -2
- data/lib/active_merchant/billing/integrations/action_view_helper.rb +1 -1
- data/lib/active_merchant/billing/integrations/citrus.rb +0 -23
- data/lib/active_merchant/billing/integrations/citrus/helper.rb +17 -0
- data/lib/active_merchant/billing/integrations/helper.rb +27 -21
- data/lib/active_merchant/billing/integrations/mollie_ideal.rb +98 -0
- data/lib/active_merchant/billing/integrations/mollie_ideal/helper.rb +67 -0
- data/lib/active_merchant/billing/integrations/mollie_ideal/notification.rb +69 -0
- data/lib/active_merchant/billing/integrations/mollie_ideal/return.rb +10 -0
- data/lib/active_merchant/billing/integrations/universal.rb +23 -0
- data/lib/active_merchant/billing/integrations/universal/helper.rb +76 -0
- data/lib/active_merchant/billing/integrations/universal/notification.rb +52 -0
- data/lib/active_merchant/billing/integrations/universal/return.rb +18 -0
- data/lib/active_merchant/version.rb +1 -1
- metadata +120 -120
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
ZTFjN2I2ZjQ3ZTdkZTIwZWY0ZGY0OTFhNzhjOTkwYWIxNDFlYTI3OA==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 81edb8d2513f065dd9170ead1d0d6f72d4fc39c8
|
4
|
+
data.tar.gz: b14933f6c29ebd5ed555e12238a29828a959687a
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
Y2I3ZDVhYjkzZDA4NTAyYjk0ZDU3ZjZkODAyMmEzOWVjMjg1OTJlNmRiYzg4
|
11
|
-
YTQ5YTc4ZGRjMmVmZGU5N2ZlMWI0MjdiNmRjZjUyZmVlN2NhMzU=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
YTY3ZGViYTg2MTIxOTFhZmFhMzE5Y2JiZmYxNzZlMzMzMDJhNDYwNTA1OTE0
|
14
|
-
ZDEzNWQ1OGYyZjJkOTM5ODE0OGViNGFiNmFmNjg3NDczMmQyOTI1OWYyMDZi
|
15
|
-
ZTZjYzVkZWM5ZTFhNzhkOGU4MTc3YWY1NGI3OWMyM2Q0OGIzYTA=
|
6
|
+
metadata.gz: 9350271f4a9016fd5c8d0113def4e0ec6a654578d63d824b07647a59128110f6b9bd2a33c3205ad2c89debe1b013b555d08cbd51e68b2333a24a0f98a7a20326
|
7
|
+
data.tar.gz: 3ce7cf004ee44048d02e6805dd2b63808c104a6cad0d42980246707fb8d50a302d4798c63ced00a2ff7526bedf93e84dfd88ebf2adac2326f10a5a51666bc32c
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
@@ -1,3 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
,�!8TD)�(�J3��"��;�"i�l���5�B�
|
1
|
+
e��k�M����6Q�)Q ��*ki-1P������{��2\v2����68B��kU�?i����]CE1m����\�3�Jh�`�T�4���U���n�œM������B�S����u�zL�u������e2Q�b"ͯu��7<��S���^A-��j�n+/}n/U.R �'>>lޡvy��o�>���?i#]Q�\$z
|
2
|
+
��c���"P����q�x�i�[(�Wa�u�[��t)J�(�Tx���;
|
data/CHANGELOG
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
= ActiveMerchant CHANGELOG
|
2
2
|
|
3
|
+
== Version 1.42.8 (April 4, 2014)
|
4
|
+
|
5
|
+
* Cecabank: Handle invalid xml response body [duff]
|
6
|
+
* Wirecard: Capture error code in the response [duff]
|
7
|
+
* Litle: Remove gem dependency [duff]
|
8
|
+
* Litle: Fix case of missing address parts [duff]
|
9
|
+
* Universal: Add universal offsite API implementation [bslobodin]
|
10
|
+
* Iridium: Add more currencies [bslobodin]
|
11
|
+
* iDeal: Add Mollie iDeal offsite implementation [wvanbergen, maartenvg]
|
12
|
+
|
3
13
|
== Version 1.42.7 (March 18, 2014)
|
4
14
|
|
5
15
|
* SagePay: Add support for ReferrerID [markabe]
|
@@ -113,30 +113,24 @@ module ActiveMerchant #:nodoc:
|
|
113
113
|
root = REXML::Document.new(body).root
|
114
114
|
|
115
115
|
response[:success] = (root.attributes['valor'] == "OK")
|
116
|
-
|
117
|
-
#common params to all responses
|
118
116
|
response[:date] = root.attributes['fecha']
|
119
117
|
response[:operation_number] = root.attributes['numeroOperacion']
|
120
118
|
response[:message] = root.attributes['valor']
|
121
119
|
|
122
|
-
#success
|
123
120
|
if root.elements['OPERACION']
|
124
121
|
response[:operation_type] = root.elements['OPERACION'].attributes['tipo']
|
125
122
|
response[:amount] = root.elements['OPERACION/importe'].text.strip
|
126
123
|
end
|
127
124
|
|
128
|
-
#optional params
|
129
125
|
response[:description] = root.elements['OPERACION/descripcion'].text if root.elements['OPERACION/descripcion']
|
130
126
|
response[:authorization_number] = root.elements['OPERACION/numeroAutorizacion'].text if root.elements['OPERACION/numeroAutorizacion']
|
131
127
|
response[:reference] = root.elements['OPERACION/referencia'].text if root.elements['OPERACION/referencia']
|
132
128
|
response[:pan] = root.elements['OPERACION/pan'].text if root.elements['OPERACION/pan']
|
133
129
|
|
134
130
|
if root.elements['ERROR']
|
135
|
-
#error
|
136
131
|
response[:error_code] = root.elements['ERROR/codigo'].text
|
137
132
|
response[:error_message] = root.elements['ERROR/descripcion'].text
|
138
133
|
else
|
139
|
-
#authorization
|
140
134
|
if("000" == root.elements['OPERACION'].attributes['numeroOperacion'])
|
141
135
|
if(root.elements['OPERACION/numeroAutorizacion'])
|
142
136
|
response[:authorization] = root.elements['OPERACION/numeroAutorizacion'].text
|
@@ -146,6 +140,12 @@ module ActiveMerchant #:nodoc:
|
|
146
140
|
end
|
147
141
|
end
|
148
142
|
|
143
|
+
return response
|
144
|
+
|
145
|
+
rescue REXML::ParseException => e
|
146
|
+
response[:success] = false
|
147
|
+
response[:message] = "Unable to parse the response."
|
148
|
+
response[:error_message] = e.message
|
149
149
|
response
|
150
150
|
end
|
151
151
|
|
@@ -24,13 +24,186 @@ module ActiveMerchant #:nodoc:
|
|
24
24
|
self.display_name = 'Iridium'
|
25
25
|
|
26
26
|
CURRENCY_CODES = {
|
27
|
+
"AED" => '784',
|
28
|
+
"AFN" => '971',
|
29
|
+
"ALL" => '008',
|
30
|
+
"AMD" => '051',
|
31
|
+
"ANG" => '532',
|
32
|
+
"AOA" => '973',
|
33
|
+
"ARS" => '032',
|
27
34
|
"AUD" => '036',
|
35
|
+
"AWG" => '533',
|
36
|
+
"AZN" => '944',
|
37
|
+
"BAM" => '977',
|
38
|
+
"BBD" => '052',
|
39
|
+
"BDT" => '050',
|
40
|
+
"BGN" => '975',
|
41
|
+
"BHD" => '048',
|
42
|
+
"BIF" => '108',
|
43
|
+
"BMD" => '060',
|
44
|
+
"BND" => '096',
|
45
|
+
"BOB" => '068',
|
46
|
+
"BOV" => '984',
|
47
|
+
"BRL" => '986',
|
48
|
+
"BSD" => '044',
|
49
|
+
"BTN" => '064',
|
50
|
+
"BWP" => '072',
|
51
|
+
"BYR" => '974',
|
52
|
+
"BZD" => '084',
|
28
53
|
"CAD" => '124',
|
54
|
+
"CDF" => '976',
|
55
|
+
"CHE" => '947',
|
56
|
+
"CHF" => '756',
|
57
|
+
"CHW" => '948',
|
58
|
+
"CLF" => '990',
|
59
|
+
"CLP" => '152',
|
60
|
+
"CNY" => '156',
|
61
|
+
"COP" => '170',
|
62
|
+
"COU" => '970',
|
63
|
+
"CRC" => '188',
|
64
|
+
"CUP" => '192',
|
65
|
+
"CVE" => '132',
|
66
|
+
"CYP" => '196',
|
67
|
+
"CZK" => '203',
|
68
|
+
"DJF" => '262',
|
69
|
+
"DKK" => '208',
|
70
|
+
"DOP" => '214',
|
71
|
+
"DZD" => '012',
|
72
|
+
"EEK" => '233',
|
73
|
+
"EGP" => '818',
|
74
|
+
"ERN" => '232',
|
75
|
+
"ETB" => '230',
|
29
76
|
"EUR" => '978',
|
77
|
+
"FJD" => '242',
|
78
|
+
"FKP" => '238',
|
30
79
|
"GBP" => '826',
|
80
|
+
"GEL" => '981',
|
81
|
+
"GHS" => '288',
|
82
|
+
"GIP" => '292',
|
83
|
+
"GMD" => '270',
|
84
|
+
"GNF" => '324',
|
85
|
+
"GTQ" => '320',
|
86
|
+
"GYD" => '328',
|
87
|
+
"HKD" => '344',
|
88
|
+
"HNL" => '340',
|
89
|
+
"HRK" => '191',
|
90
|
+
"HTG" => '332',
|
91
|
+
"HUF" => '348',
|
92
|
+
"IDR" => '360',
|
93
|
+
"ILS" => '376',
|
94
|
+
"INR" => '356',
|
95
|
+
"IQD" => '368',
|
96
|
+
"IRR" => '364',
|
97
|
+
"ISK" => '352',
|
98
|
+
"JMD" => '388',
|
99
|
+
"JOD" => '400',
|
100
|
+
"JPY" => '392',
|
101
|
+
"KES" => '404',
|
102
|
+
"KGS" => '417',
|
103
|
+
"KHR" => '116',
|
104
|
+
"KMF" => '174',
|
105
|
+
"KPW" => '408',
|
106
|
+
"KRW" => '410',
|
107
|
+
"KWD" => '414',
|
108
|
+
"KYD" => '136',
|
109
|
+
"KZT" => '398',
|
110
|
+
"LAK" => '418',
|
111
|
+
"LBP" => '422',
|
112
|
+
"LKR" => '144',
|
113
|
+
"LRD" => '430',
|
114
|
+
"LSL" => '426',
|
115
|
+
"LTL" => '440',
|
116
|
+
"LVL" => '428',
|
117
|
+
"LYD" => '434',
|
118
|
+
"MAD" => '504',
|
119
|
+
"MDL" => '498',
|
120
|
+
"MGA" => '969',
|
121
|
+
"MKD" => '807',
|
122
|
+
"MMK" => '104',
|
123
|
+
"MNT" => '496',
|
124
|
+
"MOP" => '446',
|
125
|
+
"MRO" => '478',
|
126
|
+
"MTL" => '470',
|
127
|
+
"MUR" => '480',
|
128
|
+
"MVR" => '462',
|
129
|
+
"MWK" => '454',
|
31
130
|
"MXN" => '484',
|
131
|
+
"MXV" => '979',
|
132
|
+
"MYR" => '458',
|
133
|
+
"MZN" => '943',
|
134
|
+
"NAD" => '516',
|
135
|
+
"NGN" => '566',
|
136
|
+
"NIO" => '558',
|
137
|
+
"NOK" => '578',
|
138
|
+
"NPR" => '524',
|
32
139
|
"NZD" => '554',
|
140
|
+
"OMR" => '512',
|
141
|
+
"PAB" => '590',
|
142
|
+
"PEN" => '604',
|
143
|
+
"PGK" => '598',
|
144
|
+
"PHP" => '608',
|
145
|
+
"PKR" => '586',
|
146
|
+
"PLN" => '985',
|
147
|
+
"PYG" => '600',
|
148
|
+
"QAR" => '634',
|
149
|
+
"ROL" => '642',
|
150
|
+
"RON" => '946',
|
151
|
+
"RSD" => '941',
|
152
|
+
"RUB" => '643',
|
153
|
+
"RWF" => '646',
|
154
|
+
"SAR" => '682',
|
155
|
+
"SBD" => '090',
|
156
|
+
"SCR" => '690',
|
157
|
+
"SDG" => '938',
|
158
|
+
"SEK" => '752',
|
159
|
+
"SGD" => '702',
|
160
|
+
"SHP" => '654',
|
161
|
+
"SKK" => '703',
|
162
|
+
"SLL" => '694',
|
163
|
+
"SOS" => '706',
|
164
|
+
"SRD" => '968',
|
165
|
+
"STD" => '678',
|
166
|
+
"SYP" => '760',
|
167
|
+
"SZL" => '748',
|
168
|
+
"THB" => '764',
|
169
|
+
"TJS" => '972',
|
170
|
+
"TMM" => '795',
|
171
|
+
"TND" => '788',
|
172
|
+
"TOP" => '776',
|
173
|
+
"TRY" => '949',
|
174
|
+
"TTD" => '780',
|
175
|
+
"TWD" => '901',
|
176
|
+
"TZS" => '834',
|
177
|
+
"UAH" => '980',
|
178
|
+
"UGX" => '800',
|
33
179
|
"USD" => '840',
|
180
|
+
"USN" => '997',
|
181
|
+
"USS" => '998',
|
182
|
+
"UYU" => '858',
|
183
|
+
"UZS" => '860',
|
184
|
+
"VEB" => '862',
|
185
|
+
"VND" => '704',
|
186
|
+
"VUV" => '548',
|
187
|
+
"WST" => '882',
|
188
|
+
"XAF" => '950',
|
189
|
+
"XAG" => '961',
|
190
|
+
"XAU" => '959',
|
191
|
+
"XBA" => '955',
|
192
|
+
"XBB" => '956',
|
193
|
+
"XBC" => '957',
|
194
|
+
"XBD" => '958',
|
195
|
+
"XCD" => '951',
|
196
|
+
"XDR" => '960',
|
197
|
+
"XOF" => '952',
|
198
|
+
"XPD" => '964',
|
199
|
+
"XPF" => '953',
|
200
|
+
"XPT" => '962',
|
201
|
+
"XTS" => '963',
|
202
|
+
"XXX" => '999',
|
203
|
+
"YER" => '886',
|
204
|
+
"ZAR" => '710',
|
205
|
+
"ZMK" => '894',
|
206
|
+
"ZWD" => '716',
|
34
207
|
}
|
35
208
|
|
36
209
|
def initialize(options = {})
|
@@ -1,141 +1,119 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
1
3
|
module ActiveMerchant #:nodoc:
|
2
4
|
module Billing #:nodoc:
|
3
5
|
class LitleGateway < Gateway
|
4
|
-
|
5
|
-
# * <tt>:merchant_id</tt> - Merchant Id assigned by Litle
|
6
|
-
# * <tt>:user</tt> - Username assigned by Litle
|
7
|
-
# * <tt>:password</tt> - Password assigned by Litle
|
8
|
-
# * <tt>:version</tt> - The version of the api you are using (eg, '8.10')
|
9
|
-
# * <tt>:proxy_addr</tt> - Proxy address - nil if not needed
|
10
|
-
# * <tt>:proxy_port</tt> - Proxy port - nil if not needed
|
11
|
-
# * <tt>:url</tt> - URL assigned by Litle (for testing, use the sandbox)
|
12
|
-
#
|
13
|
-
# Standard Active Merchant options
|
14
|
-
# * <tt>:order_id</tt> - The order number
|
15
|
-
# * <tt>:ip</tt> - The IP address of the customer making the purchase
|
16
|
-
# * <tt>:customer</tt> - The name, customer number, or other information that identifies the customer
|
17
|
-
# * <tt>:invoice</tt> - The invoice number
|
18
|
-
# * <tt>:merchant</tt> - The name or description of the merchant offering the product
|
19
|
-
# * <tt>:description</tt> - A description of the transaction
|
20
|
-
# * <tt>:email</tt> - The email address of the customer
|
21
|
-
# * <tt>:currency</tt> - The currency of the transaction. Only important when you are using a currency that is not the default with a gateway that supports multiple currencies.
|
22
|
-
# * <tt>:billing_address</tt> - A hash containing the billing address of the customer.
|
23
|
-
# * <tt>:shipping_address</tt> - A hash containing the shipping address of the customer.
|
24
|
-
#
|
25
|
-
# The <tt>:billing_address</tt>, and <tt>:shipping_address</tt> hashes can have the following keys:
|
26
|
-
#
|
27
|
-
# * <tt>:name</tt> - The full name of the customer.
|
28
|
-
# * <tt>:company</tt> - The company name of the customer.
|
29
|
-
# * <tt>:address1</tt> - The primary street address of the customer.
|
30
|
-
# * <tt>:address2</tt> - Additional line of address information.
|
31
|
-
# * <tt>:city</tt> - The city of the customer.
|
32
|
-
# * <tt>:state</tt> - The state of the customer. The 2 digit code for US and Canadian addresses. The full name of the state or province for foreign addresses.
|
33
|
-
# * <tt>:country</tt> - The [ISO 3166-1-alpha-2 code](http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm) for the customer.
|
34
|
-
# * <tt>:zip</tt> - The zip or postal code of the customer.
|
35
|
-
# * <tt>:phone</tt> - The phone number of the customer.
|
6
|
+
SCHEMA_VERSION = '8.18'
|
36
7
|
|
37
8
|
self.test_url = 'https://www.testlitle.com/sandbox/communicator/online'
|
38
9
|
self.live_url = 'https://payments.litle.com/vap/communicator/online'
|
39
10
|
|
40
|
-
LITLE_SCHEMA_VERSION = '8.13'
|
41
|
-
|
42
|
-
# The countries the gateway supports merchants from as 2 digit ISO country codes
|
43
11
|
self.supported_countries = ['US']
|
44
|
-
|
45
|
-
# The card types supported by the payment gateway
|
12
|
+
self.default_currency = 'USD'
|
46
13
|
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
|
47
14
|
|
48
|
-
|
49
|
-
self.
|
50
|
-
|
51
|
-
# The name of the gateway
|
52
|
-
self.display_name = 'Litle & Co.'
|
15
|
+
self.homepage_url = 'http://www.litle.com/'
|
16
|
+
self.display_name = 'Litle & Co.'
|
53
17
|
|
54
|
-
|
18
|
+
# Public: Create a new Litle gateway.
|
19
|
+
#
|
20
|
+
# options - A hash of options:
|
21
|
+
# :login - The user.
|
22
|
+
# :password - The password.
|
23
|
+
# :merchant_id - The merchant id.
|
24
|
+
def initialize(options={})
|
25
|
+
requires!(options, :login, :password, :merchant_id)
|
26
|
+
super
|
27
|
+
end
|
55
28
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
29
|
+
def purchase(money, payment_method, options={})
|
30
|
+
request = build_xml_request do |doc|
|
31
|
+
add_authentication(doc)
|
32
|
+
doc.sale(transaction_attributes(options)) do
|
33
|
+
add_auth_purchase_params(doc, money, payment_method, options)
|
34
|
+
end
|
61
35
|
end
|
62
36
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
37
|
+
commit(:sale, request)
|
38
|
+
end
|
39
|
+
|
40
|
+
def authorize(money, payment_method, options={})
|
41
|
+
request = build_xml_request do |doc|
|
42
|
+
add_authentication(doc)
|
43
|
+
doc.authorization(transaction_attributes(options)) do
|
44
|
+
add_auth_purchase_params(doc, money, payment_method, options)
|
45
|
+
end
|
69
46
|
end
|
70
47
|
|
71
|
-
|
48
|
+
commit(:authorization, request)
|
49
|
+
end
|
72
50
|
|
73
|
-
|
74
|
-
|
75
|
-
options[:user] ||= options[:login]
|
51
|
+
def capture(money, authorization, options={})
|
52
|
+
transaction_id, kind = split_authorization(authorization)
|
76
53
|
|
77
|
-
|
54
|
+
request = build_xml_request do |doc|
|
55
|
+
add_authentication(doc)
|
56
|
+
doc.capture_(transaction_attributes(options)) do
|
57
|
+
doc.litleTxnId(transaction_id)
|
58
|
+
doc.amount(money) if money
|
59
|
+
end
|
60
|
+
end
|
78
61
|
|
79
|
-
|
62
|
+
commit(:capture, request)
|
80
63
|
end
|
81
64
|
|
82
|
-
def
|
83
|
-
|
84
|
-
|
65
|
+
def credit(money, authorization, options = {})
|
66
|
+
deprecated CREDIT_DEPRECATION_MESSAGE
|
67
|
+
refund(money, authorization, options)
|
85
68
|
end
|
86
69
|
|
87
|
-
def
|
88
|
-
|
89
|
-
|
70
|
+
def refund(money, authorization, options={})
|
71
|
+
transaction_id, kind = split_authorization(authorization)
|
72
|
+
|
73
|
+
request = build_xml_request do |doc|
|
74
|
+
add_authentication(doc)
|
75
|
+
doc.credit(transaction_attributes(options)) do
|
76
|
+
doc.litleTxnId(transaction_id)
|
77
|
+
doc.amount(money) if money
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
commit(:credit, request)
|
90
82
|
end
|
91
83
|
|
92
|
-
def
|
84
|
+
def void(authorization, options={})
|
93
85
|
transaction_id, kind = split_authorization(authorization)
|
94
|
-
to_pass = create_capture_hash(money, transaction_id, options)
|
95
|
-
build_response(:capture, @litle.capture(to_pass))
|
96
|
-
end
|
97
86
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
# A partial auth_reversal can be accomplished by passing :amount as an option
|
104
|
-
def void(identification, options = {})
|
105
|
-
transaction_id, kind = split_authorization(identification)
|
106
|
-
if(kind == 'authorization')
|
107
|
-
to_pass = create_auth_reversal_hash(transaction_id, options[:amount], options)
|
108
|
-
build_response(:authReversal, @litle.auth_reversal(to_pass))
|
109
|
-
else
|
110
|
-
to_pass = create_void_hash(transaction_id, options)
|
111
|
-
build_response(:void, @litle.void(to_pass))
|
87
|
+
request = build_xml_request do |doc|
|
88
|
+
add_authentication(doc)
|
89
|
+
doc.send(void_type(kind), transaction_attributes(options)) do
|
90
|
+
doc.litleTxnId(transaction_id)
|
91
|
+
end
|
112
92
|
end
|
113
|
-
end
|
114
93
|
|
115
|
-
|
116
|
-
to_pass = build_credit_request(money, authorization, options)
|
117
|
-
build_response(:credit, @litle.credit(to_pass))
|
94
|
+
commit(void_type(kind), request)
|
118
95
|
end
|
119
96
|
|
120
|
-
def
|
121
|
-
|
122
|
-
|
123
|
-
|
97
|
+
def store(creditcard, options = {})
|
98
|
+
request = build_xml_request do |doc|
|
99
|
+
add_authentication(doc)
|
100
|
+
doc.registerTokenRequest(transaction_attributes(options)) do
|
101
|
+
doc.orderId(truncated(options[:order_id]))
|
102
|
+
doc.accountNumber(creditcard.number)
|
103
|
+
end
|
104
|
+
end
|
124
105
|
|
125
|
-
|
126
|
-
to_pass = create_token_hash(creditcard_or_paypage_registration_id, options)
|
127
|
-
build_response(:registerToken, @litle.register_token_request(to_pass), %w(000 801 802))
|
106
|
+
commit(:registerToken, request)
|
128
107
|
end
|
129
108
|
|
130
109
|
private
|
131
|
-
|
132
110
|
CARD_TYPE = {
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
111
|
+
'visa' => 'VI',
|
112
|
+
'master' => 'MC',
|
113
|
+
'american_express' => 'AX',
|
114
|
+
'discover' => 'DI',
|
115
|
+
'jcb' => 'JC',
|
116
|
+
'diners_club' => 'DC'
|
139
117
|
}
|
140
118
|
|
141
119
|
AVS_RESPONSE_CODE = {
|
@@ -156,410 +134,172 @@ module ActiveMerchant #:nodoc:
|
|
156
134
|
'40' => 'E'
|
157
135
|
}
|
158
136
|
|
159
|
-
def
|
160
|
-
|
161
|
-
|
162
|
-
test? ? self.test_url : self.live_url
|
163
|
-
end
|
164
|
-
|
165
|
-
def build_response(kind, litle_response, valid_responses=%w(000))
|
166
|
-
response = Hash.from_xml(litle_response.raw_xml.to_s)['litleOnlineResponse']
|
167
|
-
|
168
|
-
if response['response'] == "0"
|
169
|
-
detail = response["#{kind}Response"]
|
170
|
-
fraud = fraud_result(detail)
|
171
|
-
Response.new(
|
172
|
-
valid_responses.include?(detail['response']),
|
173
|
-
detail['message'],
|
174
|
-
{ litleOnlineResponse: response, response_code: detail['response'] },
|
175
|
-
authorization: authorization_from(detail, kind),
|
176
|
-
avs_result: { :code => fraud['avs'] },
|
177
|
-
cvv_result: fraud['cvv'],
|
178
|
-
test: test?
|
179
|
-
)
|
180
|
-
else
|
181
|
-
Response.new(false, response['message'], :litleOnlineResponse => response, :test => test?)
|
182
|
-
end
|
137
|
+
def void_type(kind)
|
138
|
+
(kind == 'authorization') ? :authReversal : :void
|
183
139
|
end
|
184
140
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
when :registerToken
|
190
|
-
authorization = litle_response['litleToken']
|
191
|
-
else
|
192
|
-
authorization = [litle_response['litleTxnId'], kind.to_s].join(";")
|
141
|
+
def add_authentication(doc)
|
142
|
+
doc.authentication do
|
143
|
+
doc.user(@options[:login])
|
144
|
+
doc.password(@options[:password])
|
193
145
|
end
|
194
146
|
end
|
195
147
|
|
196
|
-
def
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
hash = create_hash(money, options)
|
205
|
-
|
206
|
-
add_creditcard_or_cardtoken_hash(hash, payment_method)
|
207
|
-
|
208
|
-
hash
|
148
|
+
def add_auth_purchase_params(doc, money, payment_method, options)
|
149
|
+
doc.orderId(truncated(options[:order_id]))
|
150
|
+
doc.amount(money)
|
151
|
+
doc.orderSource('ecommerce')
|
152
|
+
add_billing_address(doc, payment_method, options)
|
153
|
+
add_shipping_address(doc, payment_method, options)
|
154
|
+
add_payment_method(doc, payment_method)
|
209
155
|
end
|
210
156
|
|
211
|
-
def
|
212
|
-
payment_method
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
157
|
+
def add_payment_method(doc, payment_method)
|
158
|
+
if payment_method.is_a?(String)
|
159
|
+
doc.token do
|
160
|
+
doc.litleToken(payment_method)
|
161
|
+
end
|
162
|
+
else
|
163
|
+
doc.card do
|
164
|
+
doc.type_(CARD_TYPE[payment_method.brand])
|
165
|
+
doc.number(payment_method.number)
|
166
|
+
doc.expDate(exp_date(payment_method))
|
167
|
+
doc.cardValidationNum(payment_method.verification_value)
|
168
|
+
end
|
169
|
+
end
|
219
170
|
end
|
220
171
|
|
221
|
-
def
|
222
|
-
|
172
|
+
def add_billing_address(doc, payment_method, options)
|
173
|
+
return if payment_method.is_a?(String)
|
223
174
|
|
224
|
-
|
175
|
+
doc.billToAddress do
|
176
|
+
doc.name(payment_method.name)
|
177
|
+
doc.email(options[:email]) if options[:email]
|
225
178
|
|
226
|
-
|
227
|
-
|
228
|
-
unless payment_method.is_a?(LitleCardToken)
|
229
|
-
hash['orderSource'] = nil
|
230
|
-
hash['orderId'] = nil
|
179
|
+
add_address(doc, options[:billing_address])
|
231
180
|
end
|
232
|
-
|
233
|
-
hash
|
234
181
|
end
|
235
182
|
|
236
|
-
def
|
237
|
-
|
183
|
+
def add_shipping_address(doc, payment_method, options)
|
184
|
+
return if payment_method.is_a?(String)
|
238
185
|
|
239
|
-
|
240
|
-
|
241
|
-
result = LitleCardToken.new(:token => payment_method)
|
242
|
-
result.month = options[:token][:month]
|
243
|
-
result.year = options[:token][:year]
|
244
|
-
result.verification_value = options[:token][:verification_value]
|
245
|
-
result.brand = options[:token][:brand]
|
186
|
+
doc.shipToAddress do
|
187
|
+
add_address(doc, options[:shipping_address])
|
246
188
|
end
|
247
|
-
|
248
|
-
result
|
249
189
|
end
|
250
190
|
|
251
|
-
def
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
191
|
+
def add_address(doc, address)
|
192
|
+
return unless address
|
193
|
+
|
194
|
+
doc.companyName(address[:company]) unless address[:company].blank?
|
195
|
+
doc.addressLine1(address[:address1]) unless address[:address1].blank?
|
196
|
+
doc.addressLine2(address[:address2]) unless address[:address2].blank?
|
197
|
+
doc.city(address[:city]) unless address[:city].blank?
|
198
|
+
doc.state(address[:state]) unless address[:state].blank?
|
199
|
+
doc.zip(address[:zip]) unless address[:zip].blank?
|
200
|
+
doc.country(address[:country]) unless address[:country].blank?
|
201
|
+
doc.phone(address[:phone]) unless address[:phone].blank?
|
257
202
|
end
|
258
203
|
|
259
|
-
def
|
260
|
-
|
261
|
-
add_cardtoken_hash(hash, identification_or_cardtoken)
|
262
|
-
else
|
263
|
-
transaction_id, kind = split_authorization(identification_or_cardtoken)
|
264
|
-
hash['litleTxnId'] = transaction_id
|
265
|
-
end
|
204
|
+
def exp_date(payment_method)
|
205
|
+
"#{format(payment_method.month, :two_digits)}#{format(payment_method.year, :two_digits)}"
|
266
206
|
end
|
267
207
|
|
268
|
-
def
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
208
|
+
def parse(kind, xml)
|
209
|
+
parsed = {}
|
210
|
+
|
211
|
+
doc = Nokogiri::XML(xml).remove_namespaces!
|
212
|
+
doc.xpath("//litleOnlineResponse/#{kind}Response/*").each do |node|
|
213
|
+
if (node.elements.empty?)
|
214
|
+
parsed[node.name.to_sym] = node.text
|
215
|
+
else
|
216
|
+
node.elements.each do |childnode|
|
217
|
+
name = "#{node.name}_#{childnode.name}"
|
218
|
+
parsed[name.to_sym] = childnode.text
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
274
222
|
|
275
|
-
|
276
|
-
hash
|
223
|
+
parsed
|
277
224
|
end
|
278
225
|
|
279
|
-
def
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
'number' => creditcard.number,
|
288
|
-
'expDate' => exp_date,
|
289
|
-
'cardValidationNum' => creditcard.verification_value
|
226
|
+
def commit(kind, request)
|
227
|
+
parsed = parse(kind, ssl_post(url, request, headers))
|
228
|
+
|
229
|
+
options = {
|
230
|
+
authorization: authorization_from(kind, parsed),
|
231
|
+
test: test?,
|
232
|
+
:avs_result => { :code => AVS_RESPONSE_CODE[parsed[:fraudResult_avsResult]] },
|
233
|
+
:cvv_result => parsed[:fraudResult_cardValidationResult]
|
290
234
|
}
|
291
235
|
|
292
|
-
|
293
|
-
hash
|
236
|
+
Response.new(success_from(kind, parsed), parsed[:message], parsed, options)
|
294
237
|
end
|
295
238
|
|
296
|
-
def
|
297
|
-
|
298
|
-
|
299
|
-
hash['litleTxnId'] = authorization
|
300
|
-
hash
|
239
|
+
def success_from(kind, parsed)
|
240
|
+
return (parsed[:response] == '000') unless kind == :registerToken
|
241
|
+
%w(000 801 802).include?(parsed[:response])
|
301
242
|
end
|
302
243
|
|
303
|
-
def
|
304
|
-
|
305
|
-
|
306
|
-
if creditcard_or_paypage_registration_id.is_a?(String)
|
307
|
-
hash['paypageRegistrationId'] = creditcard_or_paypage_registration_id
|
308
|
-
else
|
309
|
-
hash['accountNumber'] = creditcard_or_paypage_registration_id.number
|
310
|
-
end
|
311
|
-
|
312
|
-
hash
|
244
|
+
def authorization_from(kind, parsed)
|
245
|
+
(kind == :registerToken) ? parsed[:litleToken] : "#{parsed[:litleTxnId]};#{kind}"
|
313
246
|
end
|
314
247
|
|
315
|
-
def
|
316
|
-
|
317
|
-
|
318
|
-
hash
|
248
|
+
def split_authorization(authorization)
|
249
|
+
transaction_id, kind = authorization.to_s.split(';')
|
250
|
+
[transaction_id, kind]
|
319
251
|
end
|
320
252
|
|
321
|
-
def
|
322
|
-
|
323
|
-
|
324
|
-
|
253
|
+
def transaction_attributes(options)
|
254
|
+
attributes = {}
|
255
|
+
attributes[:id] = truncated(options[:id] || options[:order_id])
|
256
|
+
attributes[:reportGroup] = options[:merchant] || 'Default Report Group'
|
257
|
+
attributes[:customerId] = options[:customer]
|
258
|
+
attributes.delete_if { |key, value| value == nil }
|
259
|
+
attributes
|
325
260
|
end
|
326
261
|
|
327
|
-
def
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
if options[:invoice]
|
335
|
-
enhanced_data['invoiceReferenceNumber'] = options[:invoice]
|
336
|
-
end
|
337
|
-
|
338
|
-
if options[:description]
|
339
|
-
enhanced_data['customerReference'] = options[:description][0..16]
|
340
|
-
end
|
262
|
+
def root_attributes
|
263
|
+
{
|
264
|
+
merchantId: @options[:merchant_id],
|
265
|
+
version: SCHEMA_VERSION,
|
266
|
+
xmlns: "http://www.litle.com/schema"
|
267
|
+
}
|
268
|
+
end
|
341
269
|
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
'addressLine1' => options[:billing_address][:address1],
|
347
|
-
'addressLine2' => options[:billing_address][:address2],
|
348
|
-
'city' => options[:billing_address][:city],
|
349
|
-
'state' => options[:billing_address][:state],
|
350
|
-
'zip' => options[:billing_address][:zip],
|
351
|
-
'country' => options[:billing_address][:country],
|
352
|
-
'email' => options[:email],
|
353
|
-
'phone' => options[:billing_address][:phone]
|
354
|
-
}
|
270
|
+
def build_xml_request
|
271
|
+
builder = Nokogiri::XML::Builder.new
|
272
|
+
builder.__send__('litleOnlineRequest', root_attributes) do |doc|
|
273
|
+
yield(doc)
|
355
274
|
end
|
356
|
-
|
357
|
-
|
358
|
-
'name' => options[:shipping_address][:name],
|
359
|
-
'companyName' => options[:shipping_address][:company],
|
360
|
-
'addressLine1' => options[:shipping_address][:address1],
|
361
|
-
'addressLine2' => options[:shipping_address][:address2],
|
362
|
-
'city' => options[:shipping_address][:city],
|
363
|
-
'state' => options[:shipping_address][:state],
|
364
|
-
'zip' => options[:shipping_address][:zip],
|
365
|
-
'country' => options[:shipping_address][:country],
|
366
|
-
'email' => options[:email],
|
367
|
-
'phone' => options[:shipping_address][:phone]
|
368
|
-
}
|
369
|
-
end
|
370
|
-
|
371
|
-
hash = {
|
372
|
-
'billToAddress' => bill_to_address,
|
373
|
-
'shipToAddress' => ship_to_address,
|
374
|
-
'orderId' => truncated_order_id(options),
|
375
|
-
'customerId' => options[:customer],
|
376
|
-
'reportGroup' => (options[:merchant] || @options[:merchant]),
|
377
|
-
'merchantId' => (options[:merchant_id] || @options[:merchant_id]),
|
378
|
-
'orderSource' => (options[:order_source] || 'ecommerce'),
|
379
|
-
'enhancedData' => enhanced_data,
|
380
|
-
'fraudCheckType' => fraud_check_type,
|
381
|
-
'user' => (options[:user] || @options[:user]),
|
382
|
-
'password' => (options[:password] || @options[:password]),
|
383
|
-
'version' => (options[:version] || @options[:version]),
|
384
|
-
'url' => (options[:url] || url),
|
385
|
-
'proxy_addr' => (options[:proxy_addr] || @options[:proxy_addr]),
|
386
|
-
'proxy_port' => (options[:proxy_port] || @options[:proxy_port]),
|
387
|
-
'id' => (options[:id] || options[:order_id] || @options[:order_id])
|
388
|
-
}
|
275
|
+
builder.doc.root.to_xml
|
276
|
+
end
|
389
277
|
|
390
|
-
|
278
|
+
def url
|
279
|
+
test? ? test_url : live_url
|
280
|
+
end
|
391
281
|
|
392
|
-
|
282
|
+
def truncated(value)
|
283
|
+
return unless value
|
284
|
+
value[0..24]
|
393
285
|
end
|
394
286
|
|
395
287
|
def truncated_order_id(options)
|
396
|
-
|
397
|
-
|
398
|
-
order_id[0..24]
|
288
|
+
return unless options[:order_id]
|
289
|
+
options[:order_id][0..24]
|
399
290
|
end
|
400
291
|
|
401
|
-
def
|
402
|
-
|
403
|
-
|
404
|
-
cvv_to_pass = result['cardValidationResult'].blank? ? "P" : result['cardValidationResult']
|
405
|
-
end
|
406
|
-
|
407
|
-
avs_to_pass = AVS_RESPONSE_CODE[result['avsResult']] unless result['avsResult'].blank?
|
408
|
-
end
|
409
|
-
{ 'cvv' => cvv_to_pass, 'avs' => avs_to_pass }
|
292
|
+
def truncated_id(options)
|
293
|
+
return unless options[:id]
|
294
|
+
options[:id][0..24]
|
410
295
|
end
|
411
296
|
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
# == Example Usage
|
416
|
-
# token = LitleCardToken.new(
|
417
|
-
# :token => '1234567890123456',
|
418
|
-
# :month => '9',
|
419
|
-
# :year => '2010',
|
420
|
-
# :brand => 'visa',
|
421
|
-
# :verification_value => '123'
|
422
|
-
# )
|
423
|
-
#
|
424
|
-
# token.valid? # => true
|
425
|
-
# cc.exp_date # => 0910
|
426
|
-
#
|
427
|
-
class LitleCardToken
|
428
|
-
include Validateable
|
429
|
-
|
430
|
-
# Returns or sets the token. (required)
|
431
|
-
#
|
432
|
-
# @return [String]
|
433
|
-
attr_accessor :token
|
434
|
-
|
435
|
-
# Returns or sets the expiry month for the card associated with token. (optional)
|
436
|
-
#
|
437
|
-
# @return [Integer]
|
438
|
-
attr_accessor :month
|
439
|
-
|
440
|
-
# Returns or sets the expiry year for the card associated with token. (optional)
|
441
|
-
#
|
442
|
-
# @return [Integer]
|
443
|
-
attr_accessor :year
|
444
|
-
|
445
|
-
# Returns or sets the card verification value. (optional)
|
446
|
-
#
|
447
|
-
# @return [String] the verification value
|
448
|
-
attr_accessor :verification_value
|
449
|
-
|
450
|
-
# Returns or sets the credit card brand. (optional)
|
451
|
-
#
|
452
|
-
# Valid card types are
|
453
|
-
#
|
454
|
-
# * +'visa'+
|
455
|
-
# * +'master'+
|
456
|
-
# * +'discover'+
|
457
|
-
# * +'american_express'+
|
458
|
-
# * +'diners_club'+
|
459
|
-
# * +'jcb'+
|
460
|
-
# * +'switch'+
|
461
|
-
# * +'solo'+
|
462
|
-
# * +'dankort'+
|
463
|
-
# * +'maestro'+
|
464
|
-
# * +'forbrugsforeningen'+
|
465
|
-
# * +'laser'+
|
466
|
-
#
|
467
|
-
# @return (String) the credit card brand
|
468
|
-
attr_accessor :brand
|
469
|
-
|
470
|
-
# Returns the Litle credit card type identifier.
|
471
|
-
#
|
472
|
-
# @return (String) the credit card type identifier
|
473
|
-
def type
|
474
|
-
CARD_TYPE[brand] unless brand.blank?
|
475
|
-
end
|
476
|
-
|
477
|
-
# Returns true if the expiration date is set.
|
478
|
-
#
|
479
|
-
# @return (Boolean)
|
480
|
-
def exp_date?
|
481
|
-
!month.to_i.zero? && !year.to_i.zero?
|
482
|
-
end
|
483
|
-
|
484
|
-
# Returns the card token expiration date in MMYY format.
|
485
|
-
#
|
486
|
-
# @return (String) the expiration date in MMYY format
|
487
|
-
def exp_date
|
488
|
-
result = ''
|
489
|
-
if exp_date?
|
490
|
-
exp_date_yr = year.to_s[2..3]
|
491
|
-
exp_date_mo = '%02d' % month.to_i
|
492
|
-
|
493
|
-
result = exp_date_mo + exp_date_yr
|
494
|
-
end
|
495
|
-
result
|
496
|
-
end
|
497
|
-
|
498
|
-
# Validates the card token details.
|
499
|
-
#
|
500
|
-
# Any validation errors are added to the {#errors} attribute.
|
501
|
-
def validate
|
502
|
-
validate_card_token
|
503
|
-
validate_expiration_date
|
504
|
-
validate_card_brand
|
505
|
-
end
|
506
|
-
|
507
|
-
def check?
|
508
|
-
false
|
509
|
-
end
|
510
|
-
|
511
|
-
private
|
512
|
-
|
513
|
-
CARD_TYPE = {
|
514
|
-
'visa' => 'VI',
|
515
|
-
'master' => 'MC',
|
516
|
-
'american_express' => 'AX',
|
517
|
-
'discover' => 'DI',
|
518
|
-
'jcb' => 'DI',
|
519
|
-
'diners_club' => 'DI'
|
297
|
+
def headers
|
298
|
+
{
|
299
|
+
'Content-Type' => 'text/xml'
|
520
300
|
}
|
521
|
-
|
522
|
-
def before_validate #:nodoc:
|
523
|
-
self.month = month.to_i
|
524
|
-
self.year = year.to_i
|
525
|
-
end
|
526
|
-
|
527
|
-
# Litle XML Reference Guide 1.8.2
|
528
|
-
#
|
529
|
-
# The length of the original card number is reflected in the token, so a
|
530
|
-
# submitted 16-digit number results in a 16-digit token. Also, all tokens
|
531
|
-
# use only numeric characters, so you do not have to change your
|
532
|
-
# systems to accept alpha-numeric characters.
|
533
|
-
#
|
534
|
-
# The credit card token numbers themselves have two parts.
|
535
|
-
# The last four digits match the last four digits of the card number.
|
536
|
-
# The remaining digits (length can vary based upon original card number
|
537
|
-
# length) are a randomly generated.
|
538
|
-
def validate_card_token #:nodoc:
|
539
|
-
if token.to_s.length < 12 || token.to_s.match(/\A\d+\Z/).nil?
|
540
|
-
errors.add :token, "is not a valid card token"
|
541
|
-
end
|
542
|
-
end
|
543
|
-
|
544
|
-
def validate_expiration_date #:nodoc:
|
545
|
-
if !month.to_i.zero? || !year.to_i.zero?
|
546
|
-
errors.add :month, "is not a valid month" unless valid_month?(month)
|
547
|
-
errors.add :year, "is not a valid year" unless valid_expiry_year?(year)
|
548
|
-
end
|
549
|
-
end
|
550
|
-
|
551
|
-
def validate_card_brand #:nodoc:
|
552
|
-
errors.add :brand, "is invalid" unless brand.blank? || CreditCard.card_companies.keys.include?(brand)
|
553
|
-
end
|
554
|
-
|
555
|
-
def valid_month?(month)
|
556
|
-
(1..12).include?(month.to_i)
|
557
|
-
end
|
558
|
-
|
559
|
-
def valid_expiry_year?(year)
|
560
|
-
year.to_s =~ /\A\d{4}\Z/ && year.to_i > 1987
|
561
|
-
end
|
562
301
|
end
|
302
|
+
|
563
303
|
end
|
564
304
|
end
|
565
305
|
end
|