aktivemerchant 2.0.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.
Files changed (193) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +1596 -0
  3. data/CONTRIBUTORS +511 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +18 -0
  6. data/lib/active_merchant.rb +108 -0
  7. data/lib/active_merchant/billing.rb +13 -0
  8. data/lib/active_merchant/billing/apple_pay_payment_token.rb +22 -0
  9. data/lib/active_merchant/billing/avs_result.rb +98 -0
  10. data/lib/active_merchant/billing/base.rb +72 -0
  11. data/lib/active_merchant/billing/check.rb +76 -0
  12. data/lib/active_merchant/billing/compatibility.rb +120 -0
  13. data/lib/active_merchant/billing/credit_card.rb +352 -0
  14. data/lib/active_merchant/billing/credit_card_formatting.rb +24 -0
  15. data/lib/active_merchant/billing/credit_card_methods.rb +160 -0
  16. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  17. data/lib/active_merchant/billing/gateway.rb +268 -0
  18. data/lib/active_merchant/billing/gateways.rb +17 -0
  19. data/lib/active_merchant/billing/gateways/adyen.rb +209 -0
  20. data/lib/active_merchant/billing/gateways/alfabank.rb +117 -0
  21. data/lib/active_merchant/billing/gateways/app55.rb +176 -0
  22. data/lib/active_merchant/billing/gateways/authorize_net.rb +419 -0
  23. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +417 -0
  24. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +976 -0
  25. data/lib/active_merchant/billing/gateways/balanced.rb +256 -0
  26. data/lib/active_merchant/billing/gateways/bank_frick.rb +225 -0
  27. data/lib/active_merchant/billing/gateways/banwire.rb +105 -0
  28. data/lib/active_merchant/billing/gateways/barclays_epdq.rb +314 -0
  29. data/lib/active_merchant/billing/gateways/barclays_epdq_extra_plus.rb +15 -0
  30. data/lib/active_merchant/billing/gateways/be2bill.rb +131 -0
  31. data/lib/active_merchant/billing/gateways/beanstream.rb +188 -0
  32. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +393 -0
  33. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +54 -0
  34. data/lib/active_merchant/billing/gateways/blue_pay.rb +506 -0
  35. data/lib/active_merchant/billing/gateways/bogus.rb +140 -0
  36. data/lib/active_merchant/billing/gateways/borgun.rb +210 -0
  37. data/lib/active_merchant/billing/gateways/braintree.rb +19 -0
  38. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
  39. data/lib/active_merchant/billing/gateways/braintree_blue.rb +515 -0
  40. data/lib/active_merchant/billing/gateways/braintree_orange.rb +20 -0
  41. data/lib/active_merchant/billing/gateways/bridge_pay.rb +189 -0
  42. data/lib/active_merchant/billing/gateways/card_save.rb +23 -0
  43. data/lib/active_merchant/billing/gateways/card_stream.rb +220 -0
  44. data/lib/active_merchant/billing/gateways/cashnet.rb +191 -0
  45. data/lib/active_merchant/billing/gateways/cc5.rb +201 -0
  46. data/lib/active_merchant/billing/gateways/cecabank.rb +229 -0
  47. data/lib/active_merchant/billing/gateways/certo_direct.rb +278 -0
  48. data/lib/active_merchant/billing/gateways/checkout.rb +213 -0
  49. data/lib/active_merchant/billing/gateways/commercegate.rb +143 -0
  50. data/lib/active_merchant/billing/gateways/conekta.rb +209 -0
  51. data/lib/active_merchant/billing/gateways/cyber_source.rb +709 -0
  52. data/lib/active_merchant/billing/gateways/data_cash.rb +600 -0
  53. data/lib/active_merchant/billing/gateways/efsnet.rb +219 -0
  54. data/lib/active_merchant/billing/gateways/elavon.rb +348 -0
  55. data/lib/active_merchant/billing/gateways/epay.rb +275 -0
  56. data/lib/active_merchant/billing/gateways/evo_ca.rb +308 -0
  57. data/lib/active_merchant/billing/gateways/eway.rb +214 -0
  58. data/lib/active_merchant/billing/gateways/eway_managed.rb +291 -0
  59. data/lib/active_merchant/billing/gateways/eway_rapid.rb +524 -0
  60. data/lib/active_merchant/billing/gateways/exact.rb +218 -0
  61. data/lib/active_merchant/billing/gateways/fat_zebra.rb +173 -0
  62. data/lib/active_merchant/billing/gateways/federated_canada.rb +160 -0
  63. data/lib/active_merchant/billing/gateways/finansbank.rb +23 -0
  64. data/lib/active_merchant/billing/gateways/first_giving.rb +143 -0
  65. data/lib/active_merchant/billing/gateways/first_pay.rb +160 -0
  66. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +355 -0
  67. data/lib/active_merchant/billing/gateways/garanti.rb +257 -0
  68. data/lib/active_merchant/billing/gateways/global_transport.rb +183 -0
  69. data/lib/active_merchant/billing/gateways/hdfc.rb +207 -0
  70. data/lib/active_merchant/billing/gateways/hps.rb +288 -0
  71. data/lib/active_merchant/billing/gateways/iats_payments.rb +251 -0
  72. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +246 -0
  73. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
  74. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
  75. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +66 -0
  76. data/lib/active_merchant/billing/gateways/inspire.rb +213 -0
  77. data/lib/active_merchant/billing/gateways/instapay.rb +163 -0
  78. data/lib/active_merchant/billing/gateways/iridium.rb +457 -0
  79. data/lib/active_merchant/billing/gateways/itransact.rb +448 -0
  80. data/lib/active_merchant/billing/gateways/jetpay.rb +275 -0
  81. data/lib/active_merchant/billing/gateways/linkpoint.rb +438 -0
  82. data/lib/active_merchant/billing/gateways/litle.rb +346 -0
  83. data/lib/active_merchant/billing/gateways/maxipago.rb +197 -0
  84. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +170 -0
  85. data/lib/active_merchant/billing/gateways/merchant_one.rb +114 -0
  86. data/lib/active_merchant/billing/gateways/merchant_ware.rb +319 -0
  87. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +268 -0
  88. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +195 -0
  89. data/lib/active_merchant/billing/gateways/mercury.rb +333 -0
  90. data/lib/active_merchant/billing/gateways/metrics_global.rb +303 -0
  91. data/lib/active_merchant/billing/gateways/migs.rb +265 -0
  92. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
  93. data/lib/active_merchant/billing/gateways/modern_payments.rb +37 -0
  94. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +219 -0
  95. data/lib/active_merchant/billing/gateways/moneris.rb +309 -0
  96. data/lib/active_merchant/billing/gateways/moneris_us.rb +291 -0
  97. data/lib/active_merchant/billing/gateways/money_movers.rb +152 -0
  98. data/lib/active_merchant/billing/gateways/nab_transact.rb +280 -0
  99. data/lib/active_merchant/billing/gateways/net_registry.rb +198 -0
  100. data/lib/active_merchant/billing/gateways/netaxept.rb +181 -0
  101. data/lib/active_merchant/billing/gateways/netbilling.rb +190 -0
  102. data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
  103. data/lib/active_merchant/billing/gateways/network_merchants.rb +242 -0
  104. data/lib/active_merchant/billing/gateways/nmi.rb +256 -0
  105. data/lib/active_merchant/billing/gateways/ogone.rb +435 -0
  106. data/lib/active_merchant/billing/gateways/openpay.rb +194 -0
  107. data/lib/active_merchant/billing/gateways/optimal_payment.rb +313 -0
  108. data/lib/active_merchant/billing/gateways/orbital.rb +803 -0
  109. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +47 -0
  110. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +207 -0
  111. data/lib/active_merchant/billing/gateways/pago_facil.rb +122 -0
  112. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +261 -0
  113. data/lib/active_merchant/billing/gateways/pay_junction.rb +390 -0
  114. data/lib/active_merchant/billing/gateways/pay_secure.rb +112 -0
  115. data/lib/active_merchant/billing/gateways/pay_u_latam.rb +462 -0
  116. data/lib/active_merchant/billing/gateways/paybox_direct.rb +188 -0
  117. data/lib/active_merchant/billing/gateways/payex.rb +412 -0
  118. data/lib/active_merchant/billing/gateways/payflow.rb +304 -0
  119. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +209 -0
  120. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
  121. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  122. data/lib/active_merchant/billing/gateways/payflow_express.rb +224 -0
  123. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
  124. data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
  125. data/lib/active_merchant/billing/gateways/payment_express.rb +353 -0
  126. data/lib/active_merchant/billing/gateways/paymill.rb +281 -0
  127. data/lib/active_merchant/billing/gateways/paypal.rb +117 -0
  128. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +670 -0
  129. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +65 -0
  130. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +262 -0
  131. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  132. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +44 -0
  133. data/lib/active_merchant/billing/gateways/paypal_express.rb +264 -0
  134. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +30 -0
  135. data/lib/active_merchant/billing/gateways/payscout.rb +162 -0
  136. data/lib/active_merchant/billing/gateways/paystation.rb +199 -0
  137. data/lib/active_merchant/billing/gateways/payway.rb +207 -0
  138. data/lib/active_merchant/billing/gateways/pin.rb +197 -0
  139. data/lib/active_merchant/billing/gateways/plugnpay.rb +283 -0
  140. data/lib/active_merchant/billing/gateways/psigate.rb +216 -0
  141. data/lib/active_merchant/billing/gateways/psl_card.rb +303 -0
  142. data/lib/active_merchant/billing/gateways/qbms.rb +292 -0
  143. data/lib/active_merchant/billing/gateways/quantum.rb +276 -0
  144. data/lib/active_merchant/billing/gateways/quickpay.rb +367 -0
  145. data/lib/active_merchant/billing/gateways/realex.rb +298 -0
  146. data/lib/active_merchant/billing/gateways/redsys.rb +391 -0
  147. data/lib/active_merchant/billing/gateways/sage.rb +175 -0
  148. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +87 -0
  149. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +114 -0
  150. data/lib/active_merchant/billing/gateways/sage/sage_vault.rb +149 -0
  151. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +102 -0
  152. data/lib/active_merchant/billing/gateways/sage_pay.rb +398 -0
  153. data/lib/active_merchant/billing/gateways/sallie_mae.rb +143 -0
  154. data/lib/active_merchant/billing/gateways/secure_net.rb +252 -0
  155. data/lib/active_merchant/billing/gateways/secure_pay.rb +201 -0
  156. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +281 -0
  157. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +105 -0
  158. data/lib/active_merchant/billing/gateways/skip_jack.rb +452 -0
  159. data/lib/active_merchant/billing/gateways/smart_ps.rb +283 -0
  160. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +194 -0
  161. data/lib/active_merchant/billing/gateways/spreedly_core.rb +247 -0
  162. data/lib/active_merchant/billing/gateways/stripe.rb +411 -0
  163. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +157 -0
  164. data/lib/active_merchant/billing/gateways/tns.rb +227 -0
  165. data/lib/active_merchant/billing/gateways/trans_first.rb +126 -0
  166. data/lib/active_merchant/billing/gateways/transax.rb +23 -0
  167. data/lib/active_merchant/billing/gateways/transnational.rb +10 -0
  168. data/lib/active_merchant/billing/gateways/trust_commerce.rb +416 -0
  169. data/lib/active_merchant/billing/gateways/usa_epay.rb +25 -0
  170. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1516 -0
  171. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +254 -0
  172. data/lib/active_merchant/billing/gateways/verifi.rb +225 -0
  173. data/lib/active_merchant/billing/gateways/viaklix.rb +183 -0
  174. data/lib/active_merchant/billing/gateways/vindicia.rb +385 -0
  175. data/lib/active_merchant/billing/gateways/webpay.rb +97 -0
  176. data/lib/active_merchant/billing/gateways/wepay.rb +189 -0
  177. data/lib/active_merchant/billing/gateways/wirecard.rb +421 -0
  178. data/lib/active_merchant/billing/gateways/worldpay.rb +331 -0
  179. data/lib/active_merchant/billing/gateways/worldpay_us.rb +181 -0
  180. data/lib/active_merchant/billing/model.rb +30 -0
  181. data/lib/active_merchant/billing/payment_token.rb +21 -0
  182. data/lib/active_merchant/billing/rails.rb +3 -0
  183. data/lib/active_merchant/billing/response.rb +91 -0
  184. data/lib/active_merchant/country.rb +332 -0
  185. data/lib/active_merchant/empty.rb +20 -0
  186. data/lib/active_merchant/errors.rb +29 -0
  187. data/lib/active_merchant/offsite_payments_shim.rb +19 -0
  188. data/lib/active_merchant/version.rb +3 -0
  189. data/lib/activemerchant.rb +1 -0
  190. data/lib/support/gateway_support.rb +71 -0
  191. data/lib/support/outbound_hosts.rb +25 -0
  192. data/lib/support/ssl_verify.rb +93 -0
  193. metadata +400 -0
@@ -0,0 +1,438 @@
1
+ require 'rexml/document'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+
6
+ # Initialization Options
7
+ # :login Your store number
8
+ # :pem The text of your linkpoint PEM file. Note
9
+ # this is not the path to file, but its
10
+ # contents. If you are only using one PEM
11
+ # file on your site you can declare it
12
+ # globally and then you won't need to
13
+ # include this option
14
+ #
15
+ #
16
+ # A valid store number is required. Unfortunately, with LinkPoint
17
+ # YOU CAN'T JUST USE ANY OLD STORE NUMBER. Also, you can't just
18
+ # generate your own PEM file. You'll need to use a special PEM file
19
+ # provided by LinkPoint.
20
+ #
21
+ # Go to http://www.linkpoint.com/support/sup_teststore.asp to set up
22
+ # a test account and obtain your PEM file.
23
+ #
24
+ # Declaring PEM file Globally
25
+ # ActiveMerchant::Billing::LinkpointGateway.pem_file = File.read( File.dirname(__FILE__) + '/../mycert.pem' )
26
+ #
27
+ #
28
+ # Valid Order Options
29
+ # :result =>
30
+ # LIVE Production mode
31
+ # GOOD Approved response in test mode
32
+ # DECLINE Declined response in test mode
33
+ # DUPLICATE Duplicate response in test mode
34
+ #
35
+ # :ponumber Order number
36
+ #
37
+ # :transactionorigin => Source of the transaction
38
+ # ECI Email or Internet
39
+ # MAIL Mail order
40
+ # MOTO Mail order/Telephone
41
+ # TELEPHONE Telephone
42
+ # RETAIL Face-to-face
43
+ #
44
+ # :ordertype =>
45
+ # SALE Real live sale
46
+ # PREAUTH Authorize only
47
+ # POSTAUTH Forced Ticket or Ticket Only transaction
48
+ # VOID
49
+ # CREDIT
50
+ # CALCSHIPPING For shipping charges calculations
51
+ # CALCTAX For sales tax calculations
52
+ #
53
+ # Recurring Options
54
+ # :action =>
55
+ # SUBMIT
56
+ # MODIFY
57
+ # CANCEL
58
+ #
59
+ # :installments Identifies how many recurring payments to charge the customer
60
+ # :startdate Date to begin charging the recurring payments. Format: YYYYMMDD or "immediate"
61
+ # :periodicity =>
62
+ # MONTHLY
63
+ # BIMONTHLY
64
+ # WEEKLY
65
+ # BIWEEKLY
66
+ # YEARLY
67
+ # DAILY
68
+ # :threshold Tells how many times to retry the transaction (if it fails) before contacting the merchant.
69
+ # :comments Uh... comments
70
+ #
71
+ #
72
+ # For reference:
73
+ #
74
+ # https://www.linkpointcentral.com/lpc/docs/Help/APIHelp/lpintguide.htm
75
+ #
76
+ # Entities = {
77
+ # :payment => [:subtotal, :tax, :vattax, :shipping, :chargetotal],
78
+ # :billing => [:name, :address1, :address2, :city, :state, :zip, :country, :email, :phone, :fax, :addrnum],
79
+ # :shipping => [:name, :address1, :address2, :city, :state, :zip, :country, :weight, :items, :carrier, :total],
80
+ # :creditcard => [:cardnumber, :cardexpmonth, :cardexpyear, :cvmvalue, :track],
81
+ # :telecheck => [:routing, :account, :checknumber, :bankname, :bankstate, :dl, :dlstate, :void, :accounttype, :ssn],
82
+ # :transactiondetails => [:transactionorigin, :oid, :ponumber, :taxexempt, :terminaltype, :ip, :reference_number, :recurring, :tdate],
83
+ # :periodic => [:action, :installments, :threshold, :startdate, :periodicity, :comments],
84
+ # :notes => [:comments, :referred]
85
+ # :items => [:item => [:price, :quantity, :description, :id, :options => [:option => [:name, :value]]]]
86
+ # }
87
+ #
88
+ #
89
+ # LinkPoint's Items entity is an optional entity that can be attached to orders.
90
+ # It is entered as :line_items to be consistent with the CyberSource implementation
91
+ #
92
+ # The line_item hash goes in the options hash and should look like
93
+ #
94
+ # :line_items => [
95
+ # {
96
+ # :id => '123456',
97
+ # :description => 'Logo T-Shirt',
98
+ # :price => '12.00',
99
+ # :quantity => '1',
100
+ # :options => [
101
+ # {
102
+ # :name => 'Color',
103
+ # :value => 'Red'
104
+ # },
105
+ # {
106
+ # :name => 'Size',
107
+ # :value => 'XL'
108
+ # }
109
+ # ]
110
+ # },
111
+ # {
112
+ # :id => '111',
113
+ # :description => 'keychain',
114
+ # :price => '3.00',
115
+ # :quantity => '1'
116
+ # }
117
+ # ]
118
+ # This functionality is only supported by this particular gateway may
119
+ # be changed at any time
120
+ #
121
+ class LinkpointGateway < Gateway
122
+ # Your global PEM file. This will be assigned to you by linkpoint
123
+ #
124
+ # Example:
125
+ #
126
+ # ActiveMerchant::Billing::LinkpointGateway.pem_file = File.read( File.dirname(__FILE__) + '/../mycert.pem' )
127
+ #
128
+ cattr_accessor :pem_file
129
+
130
+ self.test_url = 'https://staging.linkpt.net:1129/'
131
+ self.live_url = 'https://secure.linkpt.net:1129/'
132
+
133
+ self.supported_countries = ['US']
134
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club]
135
+ self.homepage_url = 'http://www.linkpoint.com/'
136
+ self.display_name = 'LinkPoint'
137
+
138
+ def initialize(options = {})
139
+ requires!(options, :login)
140
+
141
+ @options = {
142
+ :result => 'LIVE',
143
+ :pem => LinkpointGateway.pem_file
144
+ }.update(options)
145
+
146
+ raise ArgumentError, "You need to pass in your pem file using the :pem parameter or set it globally using ActiveMerchant::Billing::LinkpointGateway.pem_file = File.read( File.dirname(__FILE__) + '/../mycert.pem' ) or similar" if @options[:pem].blank?
147
+ end
148
+
149
+ # Send a purchase request with periodic options
150
+ # Recurring Options
151
+ # :action =>
152
+ # SUBMIT
153
+ # MODIFY
154
+ # CANCEL
155
+ #
156
+ # :installments Identifies how many recurring payments to charge the customer
157
+ # :startdate Date to begin charging the recurring payments. Format: YYYYMMDD or "immediate"
158
+ # :periodicity =>
159
+ # :monthly
160
+ # :bimonthly
161
+ # :weekly
162
+ # :biweekly
163
+ # :yearly
164
+ # :daily
165
+ # :threshold Tells how many times to retry the transaction (if it fails) before contacting the merchant.
166
+ # :comments Uh... comments
167
+ #
168
+ def recurring(money, creditcard, options={})
169
+ ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
170
+
171
+ requires!(options, [:periodicity, :bimonthly, :monthly, :biweekly, :weekly, :yearly, :daily], :installments, :order_id )
172
+
173
+ options.update(
174
+ :ordertype => "SALE",
175
+ :action => options[:action] || "SUBMIT",
176
+ :installments => options[:installments] || 12,
177
+ :startdate => options[:startdate] || "immediate",
178
+ :periodicity => options[:periodicity].to_s || "monthly",
179
+ :comments => options[:comments] || nil,
180
+ :threshold => options[:threshold] || 3
181
+ )
182
+ commit(money, creditcard, options)
183
+ end
184
+
185
+ # Buy the thing
186
+ def purchase(money, creditcard, options={})
187
+ requires!(options, :order_id)
188
+ options.update(
189
+ :ordertype => "SALE"
190
+ )
191
+ commit(money, creditcard, options)
192
+ end
193
+
194
+ #
195
+ # Authorize the transaction
196
+ #
197
+ # Reserves the funds on the customer's credit card, but does not charge the card.
198
+ #
199
+ def authorize(money, creditcard, options = {})
200
+ requires!(options, :order_id)
201
+ options.update(
202
+ :ordertype => "PREAUTH"
203
+ )
204
+ commit(money, creditcard, options)
205
+ end
206
+
207
+ #
208
+ # Post an authorization.
209
+ #
210
+ # Captures the funds from an authorized transaction.
211
+ # Order_id must be a valid order id from a prior authorized transaction.
212
+ #
213
+ def capture(money, authorization, options = {})
214
+ options.update(
215
+ :order_id => authorization,
216
+ :ordertype => "POSTAUTH"
217
+ )
218
+ commit(money, nil, options)
219
+ end
220
+
221
+ # Void a previous transaction
222
+ def void(identification, options = {})
223
+ options.update(
224
+ :order_id => identification,
225
+ :ordertype => "VOID"
226
+ )
227
+ commit(nil, nil, options)
228
+ end
229
+
230
+ #
231
+ # Refund an order
232
+ #
233
+ # identification must be a valid order id previously submitted by SALE
234
+ #
235
+ def refund(money, identification, options = {})
236
+ options.update(
237
+ :ordertype => "CREDIT",
238
+ :order_id => identification
239
+ )
240
+ commit(money, nil, options)
241
+ end
242
+
243
+ def credit(money, identification, options = {})
244
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
245
+ refund(money, identification, options)
246
+ end
247
+
248
+ private
249
+ # Commit the transaction by posting the XML file to the LinkPoint server
250
+ def commit(money, creditcard, options = {})
251
+ response = parse(ssl_post(test? ? self.test_url : self.live_url, post_data(money, creditcard, options)))
252
+
253
+ Response.new(successful?(response), response[:message], response,
254
+ :test => test?,
255
+ :authorization => response[:ordernum],
256
+ :avs_result => { :code => response[:avs].to_s[2,1] },
257
+ :cvv_result => response[:avs].to_s[3,1]
258
+ )
259
+ end
260
+
261
+ def successful?(response)
262
+ response[:approved] == "APPROVED"
263
+ end
264
+
265
+ # Build the XML file
266
+ def post_data(money, creditcard, options)
267
+ params = parameters(money, creditcard, options)
268
+
269
+ xml = REXML::Document.new
270
+ order = xml.add_element("order")
271
+
272
+ # Merchant Info
273
+ merchantinfo = order.add_element("merchantinfo")
274
+ merchantinfo.add_element("configfile").text = @options[:login]
275
+
276
+ # Loop over the params hash to construct the XML string
277
+ for key, value in params
278
+ elem = order.add_element(key.to_s)
279
+ if key == :items
280
+ build_items(elem, value)
281
+ else
282
+ for k, _ in params[key]
283
+ elem.add_element(k.to_s).text = params[key][k].to_s if params[key][k]
284
+ end
285
+ end
286
+ # Linkpoint doesn't understand empty elements:
287
+ order.delete(elem) if elem.size == 0
288
+ end
289
+ return xml.to_s
290
+ end
291
+
292
+ # adds LinkPoint's Items entity to the XML. Called from post_data
293
+ def build_items(element, items)
294
+ for item in items
295
+ item_element = element.add_element("item")
296
+ for key, value in item
297
+ if key == :options
298
+ options_element = item_element.add_element("options")
299
+ for option in value
300
+ opt_element = options_element.add_element("option")
301
+ opt_element.add_element("name").text = option[:name] unless option[:name].blank?
302
+ opt_element.add_element("value").text = option[:value] unless option[:value].blank?
303
+ end
304
+ else
305
+ item_element.add_element(key.to_s).text = item[key].to_s unless item[key].blank?
306
+ end
307
+ end
308
+ end
309
+ end
310
+
311
+ # Set up the parameters hash just once so we don't have to do it
312
+ # for every action.
313
+ def parameters(money, creditcard, options = {})
314
+
315
+ params = {
316
+ :payment => {
317
+ :subtotal => amount(options[:subtotal]),
318
+ :tax => amount(options[:tax]),
319
+ :vattax => amount(options[:vattax]),
320
+ :shipping => amount(options[:shipping]),
321
+ :chargetotal => amount(money)
322
+ },
323
+ :transactiondetails => {
324
+ :transactionorigin => options[:transactionorigin] || "ECI",
325
+ :oid => options[:order_id],
326
+ :ponumber => options[:ponumber],
327
+ :taxexempt => options[:taxexempt],
328
+ :terminaltype => options[:terminaltype],
329
+ :ip => options[:ip],
330
+ :reference_number => options[:reference_number],
331
+ :recurring => options[:recurring] || "NO", #DO NOT USE if you are using the periodic billing option.
332
+ :tdate => options[:tdate]
333
+ },
334
+ :orderoptions => {
335
+ :ordertype => options[:ordertype],
336
+ :result => @options[:result]
337
+ },
338
+ :periodic => {
339
+ :action => options[:action],
340
+ :installments => options[:installments],
341
+ :threshold => options[:threshold],
342
+ :startdate => options[:startdate],
343
+ :periodicity => options[:periodicity],
344
+ :comments => options[:comments]
345
+ },
346
+ :telecheck => {
347
+ :routing => options[:telecheck_routing],
348
+ :account => options[:telecheck_account],
349
+ :checknumber => options[:telecheck_checknumber],
350
+ :bankname => options[:telecheck_bankname],
351
+ :dl => options[:telecheck_dl],
352
+ :dlstate => options[:telecheck_dlstate],
353
+ :void => options[:telecheck_void],
354
+ :accounttype => options[:telecheck_accounttype],
355
+ :ssn => options[:telecheck_ssn],
356
+ }
357
+ }
358
+
359
+ if creditcard
360
+ params[:creditcard] = {
361
+ :cardnumber => creditcard.number,
362
+ :cardexpmonth => creditcard.month,
363
+ :cardexpyear => format_creditcard_expiry_year(creditcard.year),
364
+ :track => nil
365
+ }
366
+
367
+ if creditcard.verification_value?
368
+ params[:creditcard][:cvmvalue] = creditcard.verification_value
369
+ params[:creditcard][:cvmindicator] = 'provided'
370
+ else
371
+ params[:creditcard][:cvmindicator] = 'not_provided'
372
+ end
373
+ end
374
+
375
+ if billing_address = options[:billing_address] || options[:address]
376
+
377
+ params[:billing] = {}
378
+ params[:billing][:name] = billing_address[:name] || (creditcard ? creditcard.name : nil)
379
+ params[:billing][:address1] = billing_address[:address1] unless billing_address[:address1].blank?
380
+ params[:billing][:address2] = billing_address[:address2] unless billing_address[:address2].blank?
381
+ params[:billing][:city] = billing_address[:city] unless billing_address[:city].blank?
382
+ params[:billing][:state] = billing_address[:state] unless billing_address[:state].blank?
383
+ params[:billing][:zip] = billing_address[:zip] unless billing_address[:zip].blank?
384
+ params[:billing][:country] = billing_address[:country] unless billing_address[:country].blank?
385
+ params[:billing][:company] = billing_address[:company] unless billing_address[:company].blank?
386
+ params[:billing][:phone] = billing_address[:phone] unless billing_address[:phone].blank?
387
+ params[:billing][:email] = options[:email] unless options[:email].blank?
388
+ end
389
+
390
+ if shipping_address = options[:shipping_address]
391
+
392
+ params[:shipping] = {}
393
+ params[:shipping][:name] = shipping_address[:name] || (creditcard ? creditcard.name : nil)
394
+ params[:shipping][:address1] = shipping_address[:address1] unless shipping_address[:address1].blank?
395
+ params[:shipping][:address2] = shipping_address[:address2] unless shipping_address[:address2].blank?
396
+ params[:shipping][:city] = shipping_address[:city] unless shipping_address[:city].blank?
397
+ params[:shipping][:state] = shipping_address[:state] unless shipping_address[:state].blank?
398
+ params[:shipping][:zip] = shipping_address[:zip] unless shipping_address[:zip].blank?
399
+ params[:shipping][:country] = shipping_address[:country] unless shipping_address[:country].blank?
400
+ end
401
+
402
+ params[:items] = options[:line_items] if options[:line_items]
403
+
404
+ return params
405
+ end
406
+
407
+ def parse(xml)
408
+
409
+ # For reference, a typical response...
410
+ # <r_csp></r_csp>
411
+ # <r_time></r_time>
412
+ # <r_ref></r_ref>
413
+ # <r_error></r_error>
414
+ # <r_ordernum></r_ordernum>
415
+ # <r_message>This is a test transaction and will not show up in the Reports</r_message>
416
+ # <r_code></r_code>
417
+ # <r_tdate>Thu Feb 2 15:40:21 2006</r_tdate>
418
+ # <r_score></r_score>
419
+ # <r_authresponse></r_authresponse>
420
+ # <r_approved>APPROVED</r_approved>
421
+ # <r_avs></r_avs>
422
+
423
+ response = {:message => "Global Error Receipt", :complete => false}
424
+
425
+ xml = REXML::Document.new("<response>#{xml}</response>")
426
+ xml.root.elements.each do |node|
427
+ response[node.name.downcase.sub(/^r_/, '').to_sym] = normalize(node.text)
428
+ end unless xml.root.nil?
429
+
430
+ response
431
+ end
432
+
433
+ def format_creditcard_expiry_year(year)
434
+ sprintf("%.4i", year)[-2..-1]
435
+ end
436
+ end
437
+ end
438
+ end
@@ -0,0 +1,346 @@
1
+ require 'nokogiri'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class LitleGateway < Gateway
6
+ SCHEMA_VERSION = '8.18'
7
+
8
+ self.test_url = 'https://www.testlitle.com/sandbox/communicator/online'
9
+ self.live_url = 'https://payments.litle.com/vap/communicator/online'
10
+
11
+ self.supported_countries = ['US']
12
+ self.default_currency = 'USD'
13
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
14
+
15
+ self.homepage_url = 'http://www.litle.com/'
16
+ self.display_name = 'Litle & Co.'
17
+
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
28
+
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
35
+ end
36
+
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
46
+ end
47
+
48
+ commit(:authorization, request)
49
+ end
50
+
51
+ def capture(money, authorization, options={})
52
+ transaction_id, _ = split_authorization(authorization)
53
+
54
+ request = build_xml_request do |doc|
55
+ add_authentication(doc)
56
+ add_descriptor(doc, options)
57
+ doc.capture_(transaction_attributes(options)) do
58
+ doc.litleTxnId(transaction_id)
59
+ doc.amount(money) if money
60
+ end
61
+ end
62
+
63
+ commit(:capture, request)
64
+ end
65
+
66
+ def credit(money, authorization, options = {})
67
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
68
+ refund(money, authorization, options)
69
+ end
70
+
71
+ def refund(money, authorization, options={})
72
+ transaction_id, _ = split_authorization(authorization)
73
+
74
+ request = build_xml_request do |doc|
75
+ add_authentication(doc)
76
+ add_descriptor(doc, options)
77
+ doc.credit(transaction_attributes(options)) do
78
+ doc.litleTxnId(transaction_id)
79
+ doc.amount(money) if money
80
+ end
81
+ end
82
+
83
+ commit(:credit, request)
84
+ end
85
+
86
+ def verify(creditcard, options = {})
87
+ MultiResponse.run(:use_first_response) do |r|
88
+ r.process { authorize(0, creditcard, options) }
89
+ r.process(:ignore_result) { void(r.authorization, options) }
90
+ end
91
+ end
92
+
93
+ def void(authorization, options={})
94
+ transaction_id, kind = split_authorization(authorization)
95
+
96
+ request = build_xml_request do |doc|
97
+ add_authentication(doc)
98
+ doc.send(void_type(kind), transaction_attributes(options)) do
99
+ doc.litleTxnId(transaction_id)
100
+ end
101
+ end
102
+
103
+ commit(void_type(kind), request)
104
+ end
105
+
106
+ def store(creditcard, options = {})
107
+ request = build_xml_request do |doc|
108
+ add_authentication(doc)
109
+ doc.registerTokenRequest(transaction_attributes(options)) do
110
+ doc.orderId(truncated(options[:order_id]))
111
+ doc.accountNumber(creditcard.number)
112
+ end
113
+ end
114
+
115
+ commit(:registerToken, request)
116
+ end
117
+
118
+ private
119
+ CARD_TYPE = {
120
+ 'visa' => 'VI',
121
+ 'master' => 'MC',
122
+ 'american_express' => 'AX',
123
+ 'discover' => 'DI',
124
+ 'jcb' => 'JC',
125
+ 'diners_club' => 'DC'
126
+ }
127
+
128
+ AVS_RESPONSE_CODE = {
129
+ '00' => 'Y',
130
+ '01' => 'X',
131
+ '02' => 'D',
132
+ '10' => 'Z',
133
+ '11' => 'W',
134
+ '12' => 'A',
135
+ '13' => 'A',
136
+ '14' => 'P',
137
+ '20' => 'N',
138
+ '30' => 'S',
139
+ '31' => 'R',
140
+ '32' => 'U',
141
+ '33' => 'R',
142
+ '34' => 'I',
143
+ '40' => 'E'
144
+ }
145
+
146
+ def void_type(kind)
147
+ (kind == 'authorization') ? :authReversal : :void
148
+ end
149
+
150
+ def add_authentication(doc)
151
+ doc.authentication do
152
+ doc.user(@options[:login])
153
+ doc.password(@options[:password])
154
+ end
155
+ end
156
+
157
+ def add_auth_purchase_params(doc, money, payment_method, options)
158
+ doc.orderId(truncated(options[:order_id]))
159
+ doc.amount(money)
160
+ add_order_source(doc, payment_method)
161
+ add_billing_address(doc, payment_method, options)
162
+ add_shipping_address(doc, payment_method, options)
163
+ add_payment_method(doc, payment_method)
164
+ add_pos(doc, payment_method)
165
+ add_descriptor(doc, options)
166
+ end
167
+
168
+ def add_descriptor(doc, options)
169
+ if options[:descriptor_name] || options[:descriptor_phone]
170
+ doc.customBilling do
171
+ doc.phone(options[:descriptor_phone]) if options[:descriptor_phone]
172
+ doc.descriptor(options[:descriptor_name]) if options[:descriptor_name]
173
+ end
174
+ end
175
+ end
176
+
177
+ def add_payment_method(doc, payment_method)
178
+ if payment_method.is_a?(String)
179
+ doc.token do
180
+ doc.litleToken(payment_method)
181
+ end
182
+ elsif payment_method.respond_to?(:track_data) && payment_method.track_data.present?
183
+ doc.card do
184
+ doc.track(payment_method.track_data)
185
+ end
186
+ else
187
+ doc.card do
188
+ doc.type_(CARD_TYPE[payment_method.brand])
189
+ doc.number(payment_method.number)
190
+ doc.expDate(exp_date(payment_method))
191
+ doc.cardValidationNum(payment_method.verification_value)
192
+ end
193
+ end
194
+ end
195
+
196
+ def add_billing_address(doc, payment_method, options)
197
+ return if payment_method.is_a?(String)
198
+
199
+ doc.billToAddress do
200
+ doc.name(payment_method.name)
201
+ doc.email(options[:email]) if options[:email]
202
+
203
+ add_address(doc, options[:billing_address])
204
+ end
205
+ end
206
+
207
+ def add_shipping_address(doc, payment_method, options)
208
+ return if payment_method.is_a?(String)
209
+
210
+ doc.shipToAddress do
211
+ add_address(doc, options[:shipping_address])
212
+ end
213
+ end
214
+
215
+ def add_address(doc, address)
216
+ return unless address
217
+
218
+ doc.companyName(address[:company]) unless address[:company].blank?
219
+ doc.addressLine1(address[:address1]) unless address[:address1].blank?
220
+ doc.addressLine2(address[:address2]) unless address[:address2].blank?
221
+ doc.city(address[:city]) unless address[:city].blank?
222
+ doc.state(address[:state]) unless address[:state].blank?
223
+ doc.zip(address[:zip]) unless address[:zip].blank?
224
+ doc.country(address[:country]) unless address[:country].blank?
225
+ doc.phone(address[:phone]) unless address[:phone].blank?
226
+ end
227
+
228
+ def add_order_source(doc, payment_method)
229
+ if payment_method.respond_to?(:track_data) && payment_method.track_data.present?
230
+ doc.orderSource('retail')
231
+ else
232
+ doc.orderSource('ecommerce')
233
+ end
234
+ end
235
+
236
+ def add_pos(doc, payment_method)
237
+ return unless payment_method.respond_to?(:track_data) && payment_method.track_data.present?
238
+
239
+ doc.pos do
240
+ doc.capability('magstripe')
241
+ doc.entryMode('completeread')
242
+ doc.cardholderId('signature')
243
+ end
244
+ end
245
+
246
+ def exp_date(payment_method)
247
+ "#{format(payment_method.month, :two_digits)}#{format(payment_method.year, :two_digits)}"
248
+ end
249
+
250
+ def parse(kind, xml)
251
+ parsed = {}
252
+
253
+ doc = Nokogiri::XML(xml).remove_namespaces!
254
+ doc.xpath("//litleOnlineResponse/#{kind}Response/*").each do |node|
255
+ if (node.elements.empty?)
256
+ parsed[node.name.to_sym] = node.text
257
+ else
258
+ node.elements.each do |childnode|
259
+ name = "#{node.name}_#{childnode.name}"
260
+ parsed[name.to_sym] = childnode.text
261
+ end
262
+ end
263
+ end
264
+
265
+ parsed
266
+ end
267
+
268
+ def commit(kind, request)
269
+ parsed = parse(kind, ssl_post(url, request, headers))
270
+
271
+ options = {
272
+ authorization: authorization_from(kind, parsed),
273
+ test: test?,
274
+ :avs_result => { :code => AVS_RESPONSE_CODE[parsed[:fraudResult_avsResult]] },
275
+ :cvv_result => parsed[:fraudResult_cardValidationResult]
276
+ }
277
+
278
+ Response.new(success_from(kind, parsed), parsed[:message], parsed, options)
279
+ end
280
+
281
+ def success_from(kind, parsed)
282
+ return (parsed[:response] == '000') unless kind == :registerToken
283
+ %w(000 801 802).include?(parsed[:response])
284
+ end
285
+
286
+ def authorization_from(kind, parsed)
287
+ (kind == :registerToken) ? parsed[:litleToken] : "#{parsed[:litleTxnId]};#{kind}"
288
+ end
289
+
290
+ def split_authorization(authorization)
291
+ transaction_id, kind = authorization.to_s.split(';')
292
+ [transaction_id, kind]
293
+ end
294
+
295
+ def transaction_attributes(options)
296
+ attributes = {}
297
+ attributes[:id] = truncated(options[:id] || options[:order_id])
298
+ attributes[:reportGroup] = options[:merchant] || 'Default Report Group'
299
+ attributes[:customerId] = options[:customer]
300
+ attributes.delete_if { |key, value| value == nil }
301
+ attributes
302
+ end
303
+
304
+ def root_attributes
305
+ {
306
+ merchantId: @options[:merchant_id],
307
+ version: SCHEMA_VERSION,
308
+ xmlns: "http://www.litle.com/schema"
309
+ }
310
+ end
311
+
312
+ def build_xml_request
313
+ builder = Nokogiri::XML::Builder.new
314
+ builder.__send__('litleOnlineRequest', root_attributes) do |doc|
315
+ yield(doc)
316
+ end
317
+ builder.doc.root.to_xml
318
+ end
319
+
320
+ def url
321
+ test? ? test_url : live_url
322
+ end
323
+
324
+ def truncated(value)
325
+ return unless value
326
+ value[0..24]
327
+ end
328
+
329
+ def truncated_order_id(options)
330
+ return unless options[:order_id]
331
+ options[:order_id][0..24]
332
+ end
333
+
334
+ def truncated_id(options)
335
+ return unless options[:id]
336
+ options[:id][0..24]
337
+ end
338
+
339
+ def headers
340
+ {
341
+ 'Content-Type' => 'text/xml'
342
+ }
343
+ end
344
+ end
345
+ end
346
+ end