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.
Files changed (218) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +1769 -0
  3. data/CONTRIBUTORS +540 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +226 -0
  6. data/lib/active_merchant.rb +67 -0
  7. data/lib/active_merchant/billing.rb +15 -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 +404 -0
  14. data/lib/active_merchant/billing/credit_card_formatting.rb +24 -0
  15. data/lib/active_merchant/billing/credit_card_methods.rb +195 -0
  16. data/lib/active_merchant/billing/cvv_result.rb +38 -0
  17. data/lib/active_merchant/billing/gateway.rb +291 -0
  18. data/lib/active_merchant/billing/gateways.rb +14 -0
  19. data/lib/active_merchant/billing/gateways/allied_wallet.rb +203 -0
  20. data/lib/active_merchant/billing/gateways/app55.rb +176 -0
  21. data/lib/active_merchant/billing/gateways/authorize_net.rb +510 -0
  22. data/lib/active_merchant/billing/gateways/authorize_net_arb.rb +417 -0
  23. data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +976 -0
  24. data/lib/active_merchant/billing/gateways/axcessms.rb +181 -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 +192 -0
  32. data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +389 -0
  33. data/lib/active_merchant/billing/gateways/beanstream_interac.rb +58 -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 +211 -0
  37. data/lib/active_merchant/billing/gateways/bpoint.rb +277 -0
  38. data/lib/active_merchant/billing/gateways/braintree.rb +19 -0
  39. data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +9 -0
  40. data/lib/active_merchant/billing/gateways/braintree_blue.rb +574 -0
  41. data/lib/active_merchant/billing/gateways/braintree_orange.rb +20 -0
  42. data/lib/active_merchant/billing/gateways/bridge_pay.rb +189 -0
  43. data/lib/active_merchant/billing/gateways/card_save.rb +23 -0
  44. data/lib/active_merchant/billing/gateways/card_stream.rb +238 -0
  45. data/lib/active_merchant/billing/gateways/cashnet.rb +202 -0
  46. data/lib/active_merchant/billing/gateways/cc5.rb +201 -0
  47. data/lib/active_merchant/billing/gateways/cecabank.rb +229 -0
  48. data/lib/active_merchant/billing/gateways/cenpos.rb +262 -0
  49. data/lib/active_merchant/billing/gateways/certo_direct.rb +278 -0
  50. data/lib/active_merchant/billing/gateways/checkout.rb +216 -0
  51. data/lib/active_merchant/billing/gateways/checkout_v2.rb +200 -0
  52. data/lib/active_merchant/billing/gateways/commercegate.rb +143 -0
  53. data/lib/active_merchant/billing/gateways/conekta.rb +210 -0
  54. data/lib/active_merchant/billing/gateways/cyber_source.rb +720 -0
  55. data/lib/active_merchant/billing/gateways/data_cash.rb +600 -0
  56. data/lib/active_merchant/billing/gateways/dibs.rb +206 -0
  57. data/lib/active_merchant/billing/gateways/efsnet.rb +219 -0
  58. data/lib/active_merchant/billing/gateways/elavon.rb +348 -0
  59. data/lib/active_merchant/billing/gateways/epay.rb +274 -0
  60. data/lib/active_merchant/billing/gateways/evo_ca.rb +308 -0
  61. data/lib/active_merchant/billing/gateways/eway.rb +214 -0
  62. data/lib/active_merchant/billing/gateways/eway_managed.rb +291 -0
  63. data/lib/active_merchant/billing/gateways/eway_rapid.rb +522 -0
  64. data/lib/active_merchant/billing/gateways/exact.rb +227 -0
  65. data/lib/active_merchant/billing/gateways/ezic.rb +206 -0
  66. data/lib/active_merchant/billing/gateways/fat_zebra.rb +213 -0
  67. data/lib/active_merchant/billing/gateways/federated_canada.rb +160 -0
  68. data/lib/active_merchant/billing/gateways/finansbank.rb +23 -0
  69. data/lib/active_merchant/billing/gateways/first_giving.rb +143 -0
  70. data/lib/active_merchant/billing/gateways/first_pay.rb +160 -0
  71. data/lib/active_merchant/billing/gateways/firstdata_e4.rb +413 -0
  72. data/lib/active_merchant/billing/gateways/flo2cash.rb +215 -0
  73. data/lib/active_merchant/billing/gateways/flo2cash_simple.rb +20 -0
  74. data/lib/active_merchant/billing/gateways/garanti.rb +261 -0
  75. data/lib/active_merchant/billing/gateways/global_transport.rb +179 -0
  76. data/lib/active_merchant/billing/gateways/hdfc.rb +207 -0
  77. data/lib/active_merchant/billing/gateways/hps.rb +287 -0
  78. data/lib/active_merchant/billing/gateways/iats_payments.rb +277 -0
  79. data/lib/active_merchant/billing/gateways/ideal/ideal_base.rb +246 -0
  80. data/lib/active_merchant/billing/gateways/ideal/ideal_rabobank.pem +13 -0
  81. data/lib/active_merchant/billing/gateways/ideal/ideal_response.rb +29 -0
  82. data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +66 -0
  83. data/lib/active_merchant/billing/gateways/inspire.rb +219 -0
  84. data/lib/active_merchant/billing/gateways/instapay.rb +163 -0
  85. data/lib/active_merchant/billing/gateways/ipp.rb +175 -0
  86. data/lib/active_merchant/billing/gateways/iridium.rb +457 -0
  87. data/lib/active_merchant/billing/gateways/itransact.rb +448 -0
  88. data/lib/active_merchant/billing/gateways/jetpay.rb +275 -0
  89. data/lib/active_merchant/billing/gateways/linkpoint.rb +438 -0
  90. data/lib/active_merchant/billing/gateways/litle.rb +345 -0
  91. data/lib/active_merchant/billing/gateways/maxipago.rb +197 -0
  92. data/lib/active_merchant/billing/gateways/merchant_e_solutions.rb +170 -0
  93. data/lib/active_merchant/billing/gateways/merchant_one.rb +114 -0
  94. data/lib/active_merchant/billing/gateways/merchant_partners.rb +245 -0
  95. data/lib/active_merchant/billing/gateways/merchant_ware.rb +319 -0
  96. data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +268 -0
  97. data/lib/active_merchant/billing/gateways/merchant_warrior.rb +195 -0
  98. data/lib/active_merchant/billing/gateways/mercury.rb +326 -0
  99. data/lib/active_merchant/billing/gateways/metrics_global.rb +303 -0
  100. data/lib/active_merchant/billing/gateways/migs.rb +280 -0
  101. data/lib/active_merchant/billing/gateways/migs/migs_codes.rb +100 -0
  102. data/lib/active_merchant/billing/gateways/modern_payments.rb +37 -0
  103. data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +219 -0
  104. data/lib/active_merchant/billing/gateways/monei.rb +307 -0
  105. data/lib/active_merchant/billing/gateways/moneris.rb +309 -0
  106. data/lib/active_merchant/billing/gateways/moneris_us.rb +298 -0
  107. data/lib/active_merchant/billing/gateways/money_movers.rb +152 -0
  108. data/lib/active_merchant/billing/gateways/nab_transact.rb +290 -0
  109. data/lib/active_merchant/billing/gateways/net_registry.rb +198 -0
  110. data/lib/active_merchant/billing/gateways/netaxept.rb +181 -0
  111. data/lib/active_merchant/billing/gateways/netbilling.rb +224 -0
  112. data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
  113. data/lib/active_merchant/billing/gateways/network_merchants.rb +242 -0
  114. data/lib/active_merchant/billing/gateways/nmi.rb +256 -0
  115. data/lib/active_merchant/billing/gateways/ogone.rb +435 -0
  116. data/lib/active_merchant/billing/gateways/omise.rb +319 -0
  117. data/lib/active_merchant/billing/gateways/openpay.rb +194 -0
  118. data/lib/active_merchant/billing/gateways/optimal_payment.rb +314 -0
  119. data/lib/active_merchant/billing/gateways/orbital.rb +834 -0
  120. data/lib/active_merchant/billing/gateways/orbital/orbital_soft_descriptors.rb +47 -0
  121. data/lib/active_merchant/billing/gateways/pac_net_raven.rb +207 -0
  122. data/lib/active_merchant/billing/gateways/pago_facil.rb +122 -0
  123. data/lib/active_merchant/billing/gateways/pay_conex.rb +246 -0
  124. data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +277 -0
  125. data/lib/active_merchant/billing/gateways/pay_hub.rb +213 -0
  126. data/lib/active_merchant/billing/gateways/pay_junction.rb +390 -0
  127. data/lib/active_merchant/billing/gateways/pay_secure.rb +112 -0
  128. data/lib/active_merchant/billing/gateways/paybox_direct.rb +188 -0
  129. data/lib/active_merchant/billing/gateways/payex.rb +412 -0
  130. data/lib/active_merchant/billing/gateways/payflow.rb +308 -0
  131. data/lib/active_merchant/billing/gateways/payflow/payflow_common_api.rb +220 -0
  132. data/lib/active_merchant/billing/gateways/payflow/payflow_express_response.rb +39 -0
  133. data/lib/active_merchant/billing/gateways/payflow/payflow_response.rb +13 -0
  134. data/lib/active_merchant/billing/gateways/payflow_express.rb +224 -0
  135. data/lib/active_merchant/billing/gateways/payflow_express_uk.rb +15 -0
  136. data/lib/active_merchant/billing/gateways/payflow_uk.rb +21 -0
  137. data/lib/active_merchant/billing/gateways/payment_express.rb +353 -0
  138. data/lib/active_merchant/billing/gateways/paymill.rb +282 -0
  139. data/lib/active_merchant/billing/gateways/paypal.rb +129 -0
  140. data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +679 -0
  141. data/lib/active_merchant/billing/gateways/paypal/paypal_express_response.rb +65 -0
  142. data/lib/active_merchant/billing/gateways/paypal/paypal_recurring_api.rb +262 -0
  143. data/lib/active_merchant/billing/gateways/paypal_ca.rb +13 -0
  144. data/lib/active_merchant/billing/gateways/paypal_digital_goods.rb +44 -0
  145. data/lib/active_merchant/billing/gateways/paypal_express.rb +264 -0
  146. data/lib/active_merchant/billing/gateways/paypal_express_common.rb +30 -0
  147. data/lib/active_merchant/billing/gateways/payscout.rb +162 -0
  148. data/lib/active_merchant/billing/gateways/paystation.rb +199 -0
  149. data/lib/active_merchant/billing/gateways/payu_in.rb +247 -0
  150. data/lib/active_merchant/billing/gateways/payway.rb +207 -0
  151. data/lib/active_merchant/billing/gateways/pin.rb +207 -0
  152. data/lib/active_merchant/billing/gateways/plugnpay.rb +283 -0
  153. data/lib/active_merchant/billing/gateways/psigate.rb +216 -0
  154. data/lib/active_merchant/billing/gateways/psl_card.rb +303 -0
  155. data/lib/active_merchant/billing/gateways/qbms.rb +292 -0
  156. data/lib/active_merchant/billing/gateways/quantum.rb +276 -0
  157. data/lib/active_merchant/billing/gateways/quickbooks.rb +280 -0
  158. data/lib/active_merchant/billing/gateways/quickpay.rb +26 -0
  159. data/lib/active_merchant/billing/gateways/quickpay/quickpay_common.rb +188 -0
  160. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +240 -0
  161. data/lib/active_merchant/billing/gateways/quickpay/quickpay_v4to7.rb +227 -0
  162. data/lib/active_merchant/billing/gateways/qvalent.rb +179 -0
  163. data/lib/active_merchant/billing/gateways/realex.rb +298 -0
  164. data/lib/active_merchant/billing/gateways/redsys.rb +406 -0
  165. data/lib/active_merchant/billing/gateways/s5.rb +226 -0
  166. data/lib/active_merchant/billing/gateways/sage.rb +173 -0
  167. data/lib/active_merchant/billing/gateways/sage/sage_bankcard.rb +89 -0
  168. data/lib/active_merchant/billing/gateways/sage/sage_core.rb +115 -0
  169. data/lib/active_merchant/billing/gateways/sage/sage_vault.rb +149 -0
  170. data/lib/active_merchant/billing/gateways/sage/sage_virtual_check.rb +97 -0
  171. data/lib/active_merchant/billing/gateways/sage_pay.rb +399 -0
  172. data/lib/active_merchant/billing/gateways/sallie_mae.rb +143 -0
  173. data/lib/active_merchant/billing/gateways/secure_net.rb +263 -0
  174. data/lib/active_merchant/billing/gateways/secure_pay.rb +201 -0
  175. data/lib/active_merchant/billing/gateways/secure_pay_au.rb +281 -0
  176. data/lib/active_merchant/billing/gateways/secure_pay_tech.rb +105 -0
  177. data/lib/active_merchant/billing/gateways/skip_jack.rb +451 -0
  178. data/lib/active_merchant/billing/gateways/smart_ps.rb +283 -0
  179. data/lib/active_merchant/billing/gateways/so_easy_pay.rb +194 -0
  180. data/lib/active_merchant/billing/gateways/spreedly_core.rb +247 -0
  181. data/lib/active_merchant/billing/gateways/stripe.rb +489 -0
  182. data/lib/active_merchant/billing/gateways/swipe_checkout.rb +157 -0
  183. data/lib/active_merchant/billing/gateways/tns.rb +227 -0
  184. data/lib/active_merchant/billing/gateways/trans_first.rb +126 -0
  185. data/lib/active_merchant/billing/gateways/transax.rb +23 -0
  186. data/lib/active_merchant/billing/gateways/transnational.rb +10 -0
  187. data/lib/active_merchant/billing/gateways/trust_commerce.rb +416 -0
  188. data/lib/active_merchant/billing/gateways/usa_epay.rb +25 -0
  189. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +1516 -0
  190. data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +259 -0
  191. data/lib/active_merchant/billing/gateways/vanco.rb +280 -0
  192. data/lib/active_merchant/billing/gateways/verifi.rb +225 -0
  193. data/lib/active_merchant/billing/gateways/viaklix.rb +183 -0
  194. data/lib/active_merchant/billing/gateways/webpay.rb +97 -0
  195. data/lib/active_merchant/billing/gateways/wepay.rb +205 -0
  196. data/lib/active_merchant/billing/gateways/wirecard.rb +420 -0
  197. data/lib/active_merchant/billing/gateways/worldpay.rb +331 -0
  198. data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +204 -0
  199. data/lib/active_merchant/billing/gateways/worldpay_us.rb +181 -0
  200. data/lib/active_merchant/billing/model.rb +30 -0
  201. data/lib/active_merchant/billing/network_tokenization_credit_card.rb +24 -0
  202. data/lib/active_merchant/billing/payment_token.rb +21 -0
  203. data/lib/active_merchant/billing/rails.rb +3 -0
  204. data/lib/active_merchant/billing/response.rb +92 -0
  205. data/lib/active_merchant/connection.rb +172 -0
  206. data/lib/active_merchant/country.rb +332 -0
  207. data/lib/active_merchant/empty.rb +20 -0
  208. data/lib/active_merchant/errors.rb +35 -0
  209. data/lib/active_merchant/network_connection_retries.rb +79 -0
  210. data/lib/active_merchant/post_data.rb +24 -0
  211. data/lib/active_merchant/posts_data.rb +84 -0
  212. data/lib/active_merchant/version.rb +3 -0
  213. data/lib/activemerchant.rb +1 -0
  214. data/lib/certs/cacert.pem +3866 -0
  215. data/lib/support/gateway_support.rb +71 -0
  216. data/lib/support/outbound_hosts.rb +28 -0
  217. data/lib/support/ssl_verify.rb +93 -0
  218. metadata +387 -0
@@ -0,0 +1,413 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class FirstdataE4Gateway < Gateway
4
+ # TransArmor support requires v11 or lower
5
+ self.test_url = "https://api.demo.globalgatewaye4.firstdata.com/transaction/v11"
6
+ self.live_url = "https://api.globalgatewaye4.firstdata.com/transaction/v11"
7
+
8
+ TRANSACTIONS = {
9
+ sale: "00",
10
+ authorization: "01",
11
+ verify: "05",
12
+ capture: "32",
13
+ void: "33",
14
+ credit: "34",
15
+ store: "05"
16
+ }
17
+
18
+ POST_HEADERS = {
19
+ "Accepts" => "application/xml",
20
+ "Content-Type" => "application/xml"
21
+ }
22
+
23
+ SUCCESS = "true"
24
+
25
+ SENSITIVE_FIELDS = [:verification_str2, :expiry_date, :card_number]
26
+
27
+ BRANDS = {
28
+ :visa => 'Visa',
29
+ :master => "Mastercard",
30
+ :american_express => "American Express",
31
+ :jcb => "JCB",
32
+ :discover => "Discover"
33
+ }
34
+
35
+ E4_BRANDS = BRANDS.merge({:mastercard => "Mastercard"})
36
+
37
+ self.supported_cardtypes = BRANDS.keys
38
+ self.supported_countries = ["CA", "US"]
39
+ self.default_currency = "USD"
40
+ self.homepage_url = "http://www.firstdata.com"
41
+ self.display_name = "FirstData Global Gateway e4"
42
+
43
+ STANDARD_ERROR_CODE_MAPPING = {
44
+ # Bank error codes: https://firstdata.zendesk.com/entries/471297-First-Data-Global-Gateway-e4-Bank-Response-Codes
45
+ '201' => STANDARD_ERROR_CODE[:incorrect_number],
46
+ '531' => STANDARD_ERROR_CODE[:invalid_cvc],
47
+ '503' => STANDARD_ERROR_CODE[:invalid_cvc],
48
+ '811' => STANDARD_ERROR_CODE[:invalid_cvc],
49
+ '605' => STANDARD_ERROR_CODE[:invalid_expiry_date],
50
+ '522' => STANDARD_ERROR_CODE[:expired_card],
51
+ '303' => STANDARD_ERROR_CODE[:card_declined],
52
+ '530' => STANDARD_ERROR_CODE[:card_declined],
53
+ '401' => STANDARD_ERROR_CODE[:call_issuer],
54
+ '402' => STANDARD_ERROR_CODE[:call_issuer],
55
+ '501' => STANDARD_ERROR_CODE[:pickup_card],
56
+ # Ecommerce error codes -- https://firstdata.zendesk.com/entries/451980-ecommerce-response-codes-etg-codes
57
+ '22' => STANDARD_ERROR_CODE[:invalid_number],
58
+ '25' => STANDARD_ERROR_CODE[:invalid_expiry_date],
59
+ '31' => STANDARD_ERROR_CODE[:incorrect_cvc],
60
+ '44' => STANDARD_ERROR_CODE[:incorrect_zip],
61
+ '42' => STANDARD_ERROR_CODE[:processing_error]
62
+ }
63
+
64
+ # Create a new FirstdataE4Gateway
65
+ #
66
+ # The gateway requires that a valid login and password be passed
67
+ # in the +options+ hash.
68
+ #
69
+ # ==== Options
70
+ #
71
+ # * <tt>:login</tt> -- The EXACT ID. Also known as the Gateway ID.
72
+ # (Found in your administration terminal settings)
73
+ # * <tt>:password</tt> -- The terminal password (not your account password)
74
+ def initialize(options = {})
75
+ requires!(options, :login, :password)
76
+ @options = options
77
+
78
+ super
79
+ end
80
+
81
+ def authorize(money, credit_card_or_store_authorization, options = {})
82
+ commit(:authorization, build_sale_or_authorization_request(money, credit_card_or_store_authorization, options))
83
+ end
84
+
85
+ def purchase(money, credit_card_or_store_authorization, options = {})
86
+ commit(:sale, build_sale_or_authorization_request(money, credit_card_or_store_authorization, options))
87
+ end
88
+
89
+ def capture(money, authorization, options = {})
90
+ commit(:capture, build_capture_or_credit_request(money, authorization, options))
91
+ end
92
+
93
+ def void(authorization, options = {})
94
+ commit(:void, build_capture_or_credit_request(money_from_authorization(authorization), authorization, options))
95
+ end
96
+
97
+ def refund(money, authorization, options = {})
98
+ commit(:credit, build_capture_or_credit_request(money, authorization, options))
99
+ end
100
+
101
+ def verify(credit_card, options = {})
102
+ commit(:verify, build_sale_or_authorization_request(0, credit_card, options))
103
+ end
104
+
105
+ # Tokenize a credit card with TransArmor
106
+ #
107
+ # The TransArmor token and other card data necessary for subsequent
108
+ # transactions is stored in the response's +authorization+ attribute.
109
+ # The authorization string may be passed to +authorize+ and +purchase+
110
+ # instead of a +ActiveMerchant::Billing::CreditCard+ instance.
111
+ #
112
+ # TransArmor support must be explicitly activated on your gateway
113
+ # account by FirstData. If your authorization string is empty, contact
114
+ # FirstData support for account setup assistance.
115
+ #
116
+ # === Example
117
+ #
118
+ # # Generate token
119
+ # result = gateway.store(credit_card)
120
+ # if result.success?
121
+ # my_record.update_attributes(:authorization => result.authorization)
122
+ # end
123
+ #
124
+ # # Use token
125
+ # result = gateway.purchase(1000, my_record.authorization)
126
+ #
127
+ # https://firstdata.zendesk.com/entries/21303361-transarmor-tokenization
128
+ def store(credit_card, options = {})
129
+ commit(:store, build_store_request(credit_card, options), credit_card)
130
+ end
131
+
132
+ def supports_scrubbing?
133
+ true
134
+ end
135
+
136
+ def scrub(transcript)
137
+ transcript.
138
+ gsub(%r((<Card_Number>).+(</Card_Number>)), '\1[FILTERED]\2').
139
+ gsub(%r((<VerificationStr2>).+(</VerificationStr2>)), '\1[FILTERED]\2')
140
+ end
141
+
142
+ private
143
+
144
+ def build_request(action, body)
145
+ xml = Builder::XmlMarkup.new
146
+
147
+ xml.instruct!
148
+ xml.tag! "Transaction" do
149
+ add_credentials(xml)
150
+ add_transaction_type(xml, action)
151
+ xml << body
152
+ end
153
+
154
+ xml.target!
155
+ end
156
+
157
+ def build_sale_or_authorization_request(money, credit_card_or_store_authorization, options)
158
+ xml = Builder::XmlMarkup.new
159
+
160
+ add_amount(xml, money)
161
+
162
+ if credit_card_or_store_authorization.is_a? String
163
+ add_credit_card_token(xml, credit_card_or_store_authorization)
164
+ else
165
+ add_credit_card(xml, credit_card_or_store_authorization, options)
166
+ end
167
+
168
+ add_customer_data(xml, options)
169
+ add_invoice(xml, options)
170
+ add_card_authentication_data(xml, options)
171
+
172
+ xml.target!
173
+ end
174
+
175
+ def build_capture_or_credit_request(money, identification, options)
176
+ xml = Builder::XmlMarkup.new
177
+
178
+ add_identification(xml, identification)
179
+ add_amount(xml, money)
180
+ add_customer_data(xml, options)
181
+ add_card_authentication_data(xml, options)
182
+
183
+ xml.target!
184
+ end
185
+
186
+ def build_store_request(credit_card, options)
187
+ xml = Builder::XmlMarkup.new
188
+
189
+ add_credit_card(xml, credit_card, options)
190
+ add_customer_data(xml, options)
191
+
192
+ xml.target!
193
+ end
194
+
195
+ def add_credentials(xml)
196
+ xml.tag! "ExactID", @options[:login]
197
+ xml.tag! "Password", @options[:password]
198
+ end
199
+
200
+ def add_transaction_type(xml, action)
201
+ xml.tag! "Transaction_Type", TRANSACTIONS[action]
202
+ end
203
+
204
+ def add_identification(xml, identification)
205
+ authorization_num, transaction_tag, _ = identification.split(";")
206
+
207
+ xml.tag! "Authorization_Num", authorization_num
208
+ xml.tag! "Transaction_Tag", transaction_tag
209
+ end
210
+
211
+ def add_amount(xml, money)
212
+ xml.tag! "DollarAmount", amount(money)
213
+ end
214
+
215
+ def add_credit_card(xml, credit_card, options)
216
+
217
+ if credit_card.respond_to?(:track_data) && credit_card.track_data.present?
218
+ xml.tag! "Track1", credit_card.track_data
219
+ else
220
+ xml.tag! "Card_Number", credit_card.number
221
+ xml.tag! "Expiry_Date", expdate(credit_card)
222
+ xml.tag! "CardHoldersName", credit_card.name
223
+ xml.tag! "CardType", card_type(credit_card.brand)
224
+
225
+ add_credit_card_verification_strings(xml, credit_card, options)
226
+ end
227
+ end
228
+
229
+ def add_credit_card_verification_strings(xml, credit_card, options)
230
+ address = options[:billing_address] || options[:address]
231
+ if address
232
+ address_values = []
233
+ [:address1, :zip, :city, :state, :country].each { |part| address_values << address[part].to_s }
234
+ xml.tag! "VerificationStr1", address_values.join("|")
235
+ end
236
+
237
+ if credit_card.is_a?(NetworkTokenizationCreditCard)
238
+ add_network_tokenization_credit_card(xml, credit_card)
239
+ elsif credit_card.verification_value?
240
+ xml.tag! "CVD_Presence_Ind", "1"
241
+ xml.tag! "VerificationStr2", credit_card.verification_value
242
+ end
243
+ end
244
+
245
+ def add_network_tokenization_credit_card(xml, credit_card)
246
+ xml.tag!("Ecommerce_Flag", credit_card.eci)
247
+
248
+ case card_brand(credit_card).to_sym
249
+ when :visa
250
+ xml.tag!("XID", credit_card.transaction_id) if credit_card.transaction_id
251
+ xml.tag!("CAVV", credit_card.payment_cryptogram)
252
+ when :mastercard
253
+ xml.tag!("XID", credit_card.transaction_id) if credit_card.transaction_id
254
+ xml.tag!("CAVV", credit_card.payment_cryptogram)
255
+ when :american_express
256
+ cryptogram = Base64.decode64(credit_card.payment_cryptogram)
257
+ xml.tag!("XID", Base64.encode64(cryptogram[20...40]))
258
+ xml.tag!("CAVV", Base64.encode64(cryptogram[0...20]))
259
+ end
260
+ end
261
+
262
+ def add_card_authentication_data(xml, options)
263
+ xml.tag! "CAVV", options[:cavv]
264
+ xml.tag! "XID", options[:xid]
265
+ xml.tag! "Ecommerce_Flag", options[:eci]
266
+ end
267
+
268
+ def add_credit_card_token(xml, store_authorization)
269
+ params = store_authorization.split(";")
270
+ credit_card = CreditCard.new(
271
+ :brand => params[1],
272
+ :first_name => params[2],
273
+ :last_name => params[3],
274
+ :month => params[4],
275
+ :year => params[5])
276
+
277
+ xml.tag! "TransarmorToken", params[0]
278
+ xml.tag! "Expiry_Date", expdate(credit_card)
279
+ xml.tag! "CardHoldersName", credit_card.name
280
+ xml.tag! "CardType", card_type(credit_card.brand)
281
+ end
282
+
283
+ def add_customer_data(xml, options)
284
+ xml.tag! "Customer_Ref", options[:customer] if options[:customer]
285
+ xml.tag! "Client_IP", options[:ip] if options[:ip]
286
+ xml.tag! "Client_Email", options[:email] if options[:email]
287
+ end
288
+
289
+ def add_address(xml, options)
290
+ if address = (options[:billing_address] || options[:address])
291
+ xml.tag! "ZipCode", address[:zip]
292
+ end
293
+ end
294
+
295
+ def add_invoice(xml, options)
296
+ xml.tag! "Reference_No", options[:order_id]
297
+ xml.tag! "Reference_3", options[:description] if options[:description]
298
+ end
299
+
300
+ def expdate(credit_card)
301
+ "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
302
+ end
303
+
304
+ def card_type(credit_card_brand)
305
+ E4_BRANDS[credit_card_brand.to_sym] if credit_card_brand
306
+ end
307
+
308
+ def commit(action, request, credit_card = nil)
309
+ url = (test? ? self.test_url : self.live_url)
310
+ begin
311
+ response = parse(ssl_post(url, build_request(action, request), POST_HEADERS))
312
+ rescue ResponseError => e
313
+ response = parse_error(e.response)
314
+ end
315
+
316
+ Response.new(successful?(response), message_from(response), response,
317
+ :test => test?,
318
+ :authorization => successful?(response) ? response_authorization(action, response, credit_card) : '',
319
+ :avs_result => {:code => response[:avs]},
320
+ :cvv_result => response[:cvv2],
321
+ :error_code => standard_error_code(response)
322
+ )
323
+ end
324
+
325
+ def successful?(response)
326
+ response[:transaction_approved] == SUCCESS
327
+ end
328
+
329
+ def response_authorization(action, response, credit_card)
330
+ if action == :store
331
+ store_authorization_from(response, credit_card)
332
+ else
333
+ authorization_from(response)
334
+ end
335
+ end
336
+
337
+ def authorization_from(response)
338
+ if response[:authorization_num] && response[:transaction_tag]
339
+ [
340
+ response[:authorization_num],
341
+ response[:transaction_tag],
342
+ (response[:dollar_amount].to_f * 100).to_i
343
+ ].join(";")
344
+ else
345
+ ""
346
+ end
347
+ end
348
+
349
+ def store_authorization_from(response, credit_card)
350
+ if response[:transarmor_token].present?
351
+ [
352
+ response[:transarmor_token],
353
+ credit_card.brand,
354
+ credit_card.first_name,
355
+ credit_card.last_name,
356
+ credit_card.month,
357
+ credit_card.year
358
+ ].map { |value| value.to_s.gsub(/;/, "") }.join(";")
359
+ else
360
+ raise StandardError, "TransArmor support is not enabled on your #{display_name} account"
361
+ end
362
+ end
363
+
364
+ def money_from_authorization(auth)
365
+ _, _, amount = auth.split(/;/, 3)
366
+ amount.to_i # return the # of cents, no need to divide
367
+ end
368
+
369
+ def message_from(response)
370
+ if(response[:faultcode] && response[:faultstring])
371
+ response[:faultstring]
372
+ elsif(response[:error_number] && response[:error_number] != "0")
373
+ response[:error_description]
374
+ else
375
+ result = (response[:exact_message] || "")
376
+ result << " - #{response[:bank_message]}" if response[:bank_message].present?
377
+ result
378
+ end
379
+ end
380
+
381
+ def parse_error(error)
382
+ {
383
+ :transaction_approved => "false",
384
+ :error_number => error.code,
385
+ :error_description => error.body,
386
+ :ecommerce_error_code => error.body.gsub(/[^\d]/, '')
387
+ }
388
+ end
389
+
390
+ def standard_error_code(response)
391
+ STANDARD_ERROR_CODE_MAPPING[response[:bank_resp_code] || response[:ecommerce_error_code]]
392
+ end
393
+
394
+ def parse(xml)
395
+ response = {}
396
+ xml = REXML::Document.new(xml)
397
+
398
+ if root = REXML::XPath.first(xml, "//TransactionResult")
399
+ parse_elements(response, root)
400
+ end
401
+
402
+ response.delete_if{ |k,v| SENSITIVE_FIELDS.include?(k) }
403
+ end
404
+
405
+ def parse_elements(response, root)
406
+ root.elements.to_a.each do |node|
407
+ response[node.name.gsub(/EXact/, "Exact").underscore.to_sym] = (node.text || "").strip
408
+ end
409
+ end
410
+ end
411
+ end
412
+ end
413
+
@@ -0,0 +1,215 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class Flo2cashGateway < Gateway
4
+ self.display_name = 'Flo2Cash'
5
+ self.homepage_url = 'http://www.flo2cash.co.nz/'
6
+
7
+ self.test_url = 'https://demo.flo2cash.co.nz/ws/paymentws.asmx'
8
+ self.live_url = 'https://secure.flo2cash.co.nz/ws/paymentws.asmx'
9
+
10
+ self.supported_countries = ['NZ']
11
+ self.default_currency = 'NZD'
12
+ self.money_format = :dollars
13
+ self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
14
+
15
+ BRAND_MAP = {
16
+ "visa" => "VISA",
17
+ "master" => "MC",
18
+ "american_express" => "AMEX",
19
+ "diners_club" => "DINERS"
20
+ }
21
+
22
+ def initialize(options={})
23
+ requires!(options, :username, :password, :account_id)
24
+ super
25
+ end
26
+
27
+ def purchase(amount, payment_method, options={})
28
+ MultiResponse.run do |r|
29
+ r.process { authorize(amount, payment_method, options) }
30
+ r.process { capture(amount, r.authorization, options) }
31
+ end
32
+ end
33
+
34
+ def authorize(amount, payment_method, options={})
35
+ post = {}
36
+ add_invoice(post, amount, options)
37
+ add_payment_method(post, payment_method)
38
+ add_customer_data(post, options)
39
+
40
+ commit("ProcessAuthorise", post)
41
+ end
42
+
43
+ def capture(amount, authorization, options={})
44
+ post = {}
45
+ add_invoice(post, amount, options)
46
+ add_reference(post, authorization)
47
+ add_customer_data(post, options)
48
+
49
+ commit("ProcessCapture", post)
50
+ end
51
+
52
+ def refund(amount, authorization, options={})
53
+ post = {}
54
+ add_invoice(post, amount, options)
55
+ add_reference(post, authorization)
56
+ add_customer_data(post, options)
57
+
58
+ commit("ProcessRefund", post)
59
+ end
60
+
61
+ def supports_scrubbing?
62
+ true
63
+ end
64
+
65
+ def scrub(transcript)
66
+ transcript.
67
+ gsub(%r((<Password>)[^<]+(<))i, '\1[FILTERED]\2').
68
+ gsub(%r((<CardNumber>)[^<]+(<))i, '\1[FILTERED]\2').
69
+ gsub(%r((<CardCSC>)[^<]+(<))i, '\1[FILTERED]\2')
70
+ end
71
+
72
+ private
73
+
74
+ CURRENCY_CODES = Hash.new{|h,k| raise ArgumentError.new("Unsupported currency: #{k}")}
75
+ CURRENCY_CODES["NZD"] = "554"
76
+
77
+ def add_invoice(post, money, options)
78
+ post[:Amount] = amount(money)
79
+ post[:Reference] = options[:order_id]
80
+ post[:Particular] = options[:description]
81
+ end
82
+
83
+ def add_payment_method(post, payment_method)
84
+ post[:CardNumber] = payment_method.number
85
+ post[:CardType] = BRAND_MAP[payment_method.brand.to_s]
86
+ post[:CardExpiry] = format(payment_method.month, :two_digits) + format(payment_method.year, :two_digits)
87
+ post[:CardHolderName] = payment_method.name
88
+ post[:CardCSC] = payment_method.verification_value
89
+ end
90
+
91
+ def add_customer_data(post, options)
92
+ if(billing_address = (options[:billing_address] || options[:address]))
93
+ post[:Email] = billing_address[:email]
94
+ end
95
+ end
96
+
97
+ def add_reference(post, authorization)
98
+ post[:OriginalTransactionId] = authorization
99
+ end
100
+
101
+ def commit(action, post)
102
+ post[:Username] = @options[:username]
103
+ post[:Password] = @options[:password]
104
+ post[:AccountId] = @options[:account_id]
105
+
106
+ data = build_request(action, post)
107
+ begin
108
+ raw = parse(ssl_post(url, data, headers(action)), action)
109
+ rescue ActiveMerchant::ResponseError => e
110
+ if(e.response.code == "500" && e.response.body.start_with?("<?xml"))
111
+ raw = parse(e.response.body, action)
112
+ else
113
+ raise
114
+ end
115
+ end
116
+
117
+ succeeded = success_from(raw[:status])
118
+ Response.new(
119
+ succeeded,
120
+ message_from(succeeded, raw),
121
+ raw,
122
+ :authorization => authorization_from(action, raw[:transaction_id], post[:OriginalTransactionId]),
123
+ :error_code => error_code_from(succeeded, raw),
124
+ :test => test?
125
+ )
126
+ end
127
+
128
+ def headers(action)
129
+ {
130
+ 'Content-Type' => 'application/soap+xml; charset=utf-8',
131
+ 'SOAPAction' => %{"http://www.flo2cash.co.nz/webservices/paymentwebservice/#{action}"}
132
+ }
133
+ end
134
+
135
+ def build_request(action, post)
136
+ xml = Builder::XmlMarkup.new :indent => 2
137
+ post.each do |field, value|
138
+ xml.tag!(field, value)
139
+ end
140
+ body = xml.target!
141
+ envelope_wrap(action, body)
142
+ end
143
+
144
+ def envelope_wrap(action, body)
145
+ <<-EOS
146
+ <?xml version="1.0" encoding="utf-8"?>
147
+ <soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
148
+ <soap12:Body>
149
+ <#{action} xmlns="http://www.flo2cash.co.nz/webservices/paymentwebservice">
150
+ #{body}
151
+ </#{action}>
152
+ </soap12:Body>
153
+ </soap12:Envelope>
154
+ EOS
155
+ end
156
+
157
+ def url
158
+ (test? ? test_url : live_url)
159
+ end
160
+
161
+ def parse(body, action)
162
+ response = {}
163
+ xml = REXML::Document.new(body)
164
+ root = (REXML::XPath.first(xml, "//#{action}Response") || REXML::XPath.first(xml, "//detail"))
165
+
166
+ root.elements.to_a.each do |node|
167
+ parse_element(response, node)
168
+ end if root
169
+
170
+ response
171
+ end
172
+
173
+ def parse_element(response, node)
174
+ if node.has_elements?
175
+ node.elements.each{|element| parse_element(response, element) }
176
+ else
177
+ response[node.name.underscore.to_sym] = node.text
178
+ end
179
+ end
180
+
181
+ def success_from(response)
182
+ response == 'SUCCESSFUL'
183
+ end
184
+
185
+ def message_from(succeeded, response)
186
+ if succeeded
187
+ "Succeeded"
188
+ else
189
+ response[:message] || response[:errormessage] || "Unable to read error message"
190
+ end
191
+ end
192
+
193
+ def authorization_from(action, current, original)
194
+ # Refunds require the authorization from the authorize() of the MultiResponse.
195
+ if action == 'ProcessCapture'
196
+ original
197
+ else
198
+ current
199
+ end
200
+ end
201
+
202
+ STANDARD_ERROR_CODE_MAPPING = {
203
+ 'Transaction Declined - Expired Card' => STANDARD_ERROR_CODE[:expired_card],
204
+ 'Bank Declined Transaction' => STANDARD_ERROR_CODE[:card_declined],
205
+ 'Insufficient Funds' => STANDARD_ERROR_CODE[:card_declined],
206
+ 'Transaction Declined - Bank Error' => STANDARD_ERROR_CODE[:processing_error],
207
+ 'No Reply from Bank' => STANDARD_ERROR_CODE[:processing_error],
208
+ }
209
+
210
+ def error_code_from(succeeded, response)
211
+ succeeded ? nil : STANDARD_ERROR_CODE_MAPPING[response[:message]]
212
+ end
213
+ end
214
+ end
215
+ end