aktivemerchant 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,803 @@
1
+ require File.dirname(__FILE__) + '/orbital/orbital_soft_descriptors'
2
+ require "rexml/document"
3
+
4
+ module ActiveMerchant #:nodoc:
5
+ module Billing #:nodoc:
6
+ # For more information on Orbital, visit the {integration center}[http://download.chasepaymentech.com]
7
+ #
8
+ # ==== Authentication Options
9
+ #
10
+ # The Orbital Gateway supports two methods of authenticating incoming requests:
11
+ # Source IP authentication and Connection Username/Password authentication
12
+ #
13
+ # In addition, these IP addresses/Connection Usernames must be affiliated with the Merchant IDs
14
+ # for which the client should be submitting transactions.
15
+ #
16
+ # This does allow Third Party Hosting service organizations presenting on behalf of other
17
+ # merchants to submit transactions. However, each time a new customer is added, the
18
+ # merchant or Third-Party hosting organization needs to ensure that the new Merchant IDs
19
+ # or Chain IDs are affiliated with the hosting companies IPs or Connection Usernames.
20
+ #
21
+ # If the merchant expects to have more than one merchant account with the Orbital
22
+ # Gateway, it should have its IP addresses/Connection Usernames affiliated at the Chain
23
+ # level hierarchy within the Orbital Gateway. Each time a new merchant ID is added, as
24
+ # long as it is placed within the same Chain, it will simply work. Otherwise, the additional
25
+ # MIDs will need to be affiliated with the merchant IPs or Connection Usernames respectively.
26
+ # For example, we generally affiliate all Salem accounts [BIN 000001] with
27
+ # their Company Number [formerly called MA #] number so all MIDs or Divisions under that
28
+ # Company will automatically be affiliated.
29
+
30
+ class OrbitalGateway < Gateway
31
+ API_VERSION = "5.6"
32
+
33
+ POST_HEADERS = {
34
+ "MIME-Version" => "1.1",
35
+ "Content-Type" => "application/PTI56",
36
+ "Content-transfer-encoding" => "text",
37
+ "Request-number" => '1',
38
+ "Document-type" => "Request",
39
+ "Interface-Version" => "Ruby|ActiveMerchant|Proprietary Gateway"
40
+ }
41
+
42
+ SUCCESS = '0'
43
+
44
+ APPROVED = [
45
+ '00', # Approved
46
+ '08', # Approved authorization, honor with ID
47
+ '11', # Approved authorization, VIP approval
48
+ '24', # Validated
49
+ '26', # Pre-noted
50
+ '27', # No reason to decline
51
+ '28', # Received and stored
52
+ '29', # Provided authorization
53
+ '31', # Request received
54
+ '32', # BIN alert
55
+ '34', # Approved for partial
56
+ '91', # Approved low fraud
57
+ '92', # Approved medium fraud
58
+ '93', # Approved high fraud
59
+ '94', # Approved fraud service unavailable
60
+ 'E7', # Stored
61
+ 'PA' # Partial approval
62
+ ]
63
+
64
+ class_attribute :secondary_test_url, :secondary_live_url
65
+
66
+ self.test_url = "https://orbitalvar1.paymentech.net/authorize"
67
+ self.secondary_test_url = "https://orbitalvar2.paymentech.net/authorize"
68
+
69
+ self.live_url = "https://orbital1.paymentech.net/authorize"
70
+ self.secondary_live_url = "https://orbital2.paymentech.net/authorize"
71
+
72
+ self.supported_countries = ["US", "CA"]
73
+ self.default_currency = "CAD"
74
+ self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
75
+
76
+ self.display_name = 'Orbital Paymentech'
77
+ self.homepage_url = 'http://chasepaymentech.com/'
78
+
79
+ self.money_format = :cents
80
+
81
+ AVS_SUPPORTED_COUNTRIES = ['US', 'CA', 'UK', 'GB']
82
+
83
+ CURRENCY_CODES = {
84
+ "AUD" => '036',
85
+ "CAD" => '124',
86
+ "CZK" => '203',
87
+ "DKK" => '208',
88
+ "HKD" => '344',
89
+ "ICK" => '352',
90
+ "JPY" => '392',
91
+ "MXN" => '484',
92
+ "NZD" => '554',
93
+ "NOK" => '578',
94
+ "SGD" => '702',
95
+ "SEK" => '752',
96
+ "CHF" => '756',
97
+ "GBP" => '826',
98
+ "USD" => '840',
99
+ "EUR" => '978'
100
+ }
101
+
102
+ CURRENCY_EXPONENTS = {
103
+ "AUD" => '2',
104
+ "CAD" => '2',
105
+ "CZK" => '2',
106
+ "DKK" => '2',
107
+ "HKD" => '2',
108
+ "ICK" => '2',
109
+ "JPY" => '0',
110
+ "MXN" => '2',
111
+ "NZD" => '2',
112
+ "NOK" => '2',
113
+ "SGD" => '2',
114
+ "SEK" => '2',
115
+ "CHF" => '2',
116
+ "GBP" => '2',
117
+ "USD" => '2',
118
+ "EUR" => '2'
119
+ }
120
+
121
+ # INDUSTRY TYPES
122
+ ECOMMERCE_TRANSACTION = 'EC'
123
+ RECURRING_PAYMENT_TRANSACTION = 'RC'
124
+ MAIL_ORDER_TELEPHONE_ORDER_TRANSACTION = 'MO'
125
+ INTERACTIVE_VOICE_RESPONSE = 'IV'
126
+ # INTERACTIVE_VOICE_RESPONSE = 'IN'
127
+
128
+ # Auth Only No Capture
129
+ AUTH_ONLY = 'A'
130
+ # AC - Auth and Capture = 'AC'
131
+ AUTH_AND_CAPTURE = 'AC'
132
+ # F - Force Auth No Capture and no online authorization = 'F'
133
+ FORCE_AUTH_ONLY = 'F'
134
+ # FR - Force Auth No Capture and no online authorization = 'FR'
135
+ # FC - Force Auth and Capture no online authorization = 'FC'
136
+ FORCE_AUTH_AND_CAPTURE = 'FC'
137
+ # Refund and Capture no online authorization
138
+ REFUND = 'R'
139
+
140
+ # Tax Inds
141
+ TAX_NOT_PROVIDED = 0
142
+ TAX_INCLUDED = 1
143
+ NON_TAXABLE_TRANSACTION = 2
144
+
145
+ # Customer Profile Actions
146
+ CREATE = 'C'
147
+ RETRIEVE = 'R'
148
+ UPDATE = 'U'
149
+ DELETE = 'D'
150
+
151
+ RECURRING = 'R'
152
+ DEFERRED = 'D'
153
+
154
+ # Status
155
+ # Profile Status Flag
156
+ # This field is used to set the status of a Customer Profile.
157
+ ACTIVE = 'A'
158
+ INACTIVE = 'I'
159
+ MANUAL_SUSPEND = 'MS'
160
+
161
+ # CustomerProfileOrderOverrideInd
162
+ # Defines if any Order Data can be pre-populated from
163
+ # the Customer Reference Number (CustomerRefNum)
164
+ NO_MAPPING_TO_ORDER_DATA = 'NO'
165
+ USE_CRN_FOR_ORDER_ID = 'OI'
166
+ USE_CRN_FOR_COMMENTS = 'OD'
167
+ USE_CRN_FOR_ORDER_ID_AND_COMMENTS = 'OA'
168
+
169
+ # CustomerProfileFromOrderInd
170
+ # Method to use to Generate the Customer Profile Number
171
+ # When Customer Profile Action Type = Create, defines
172
+ # what the Customer Profile Number will be:
173
+ AUTO_GENERATE = 'A' # Auto-Generate the CustomerRefNum
174
+ USE_CUSTOMER_REF_NUM = 'S' # Use CustomerRefNum field
175
+ USE_ORDER_ID = 'O' # Use OrderID field
176
+ USE_COMMENTS = 'D' # Use Comments field
177
+
178
+ SENSITIVE_FIELDS = [:account_num]
179
+
180
+ def initialize(options = {})
181
+ requires!(options, :merchant_id)
182
+ requires!(options, :login, :password) unless options[:ip_authentication]
183
+ super
184
+ end
185
+
186
+ # A – Authorization request
187
+ def authorize(money, creditcard, options = {})
188
+ order = build_new_order_xml(AUTH_ONLY, money, options) do |xml|
189
+ add_creditcard(xml, creditcard, options[:currency])
190
+ add_address(xml, creditcard, options)
191
+ if @options[:customer_profiles]
192
+ add_customer_data(xml, creditcard, options)
193
+ add_managed_billing(xml, options)
194
+ end
195
+ end
196
+ commit(order, :authorize, options[:trace_number])
197
+ end
198
+
199
+ # AC – Authorization and Capture
200
+ def purchase(money, creditcard, options = {})
201
+ order = build_new_order_xml(AUTH_AND_CAPTURE, money, options) do |xml|
202
+ add_creditcard(xml, creditcard, options[:currency])
203
+ add_address(xml, creditcard, options)
204
+ if @options[:customer_profiles]
205
+ add_customer_data(xml, creditcard, options)
206
+ add_managed_billing(xml, options)
207
+ end
208
+ end
209
+ commit(order, :purchase, options[:trace_number])
210
+ end
211
+
212
+ # MFC - Mark For Capture
213
+ def capture(money, authorization, options = {})
214
+ commit(build_mark_for_capture_xml(money, authorization, options), :capture)
215
+ end
216
+
217
+ # R – Refund request
218
+ def refund(money, authorization, options = {})
219
+ order = build_new_order_xml(REFUND, money, options.merge(:authorization => authorization)) do |xml|
220
+ add_refund(xml, options[:currency])
221
+ xml.tag! :CustomerRefNum, options[:customer_ref_num] if @options[:customer_profiles] && options[:profile_txn]
222
+ end
223
+ commit(order, :refund, options[:trace_number])
224
+ end
225
+
226
+ def credit(money, authorization, options= {})
227
+ ActiveMerchant.deprecated CREDIT_DEPRECATION_MESSAGE
228
+ refund(money, authorization, options)
229
+ end
230
+
231
+ def void(authorization, options = {}, deprecated = {})
232
+ if(!options.kind_of?(Hash))
233
+ ActiveMerchant.deprecated("Calling the void method with an amount parameter is deprecated and will be removed in a future version.")
234
+ return void(options, deprecated.merge(:amount => authorization))
235
+ end
236
+
237
+ order = build_void_request_xml(authorization, options)
238
+ commit(order, :void, options[:trace_number])
239
+ end
240
+
241
+
242
+ # ==== Customer Profiles
243
+ # :customer_ref_num should be set unless your happy with Orbital providing one
244
+ #
245
+ # :customer_profile_order_override_ind can be set to map
246
+ # the CustomerRefNum to OrderID or Comments. Defaults to 'NO' - no mapping
247
+ #
248
+ # 'NO' - No mapping to order data
249
+ # 'OI' - Use <CustomerRefNum> for <OrderID>
250
+ # 'OD' - Use <CustomerRefNum> for <Comments>
251
+ # 'OA' - Use <CustomerRefNum> for <OrderID> and <Comments>
252
+ #
253
+ # :order_default_description can be set optionally. 64 char max.
254
+ #
255
+ # :order_default_amount can be set optionally. integer as cents.
256
+ #
257
+ # :status defaults to Active
258
+ #
259
+ # 'A' - Active
260
+ # 'I' - Inactive
261
+ # 'MS' - Manual Suspend
262
+
263
+ def add_customer_profile(creditcard, options = {})
264
+ options.merge!(:customer_profile_action => CREATE)
265
+ order = build_customer_request_xml(creditcard, options)
266
+ commit(order, :add_customer_profile)
267
+ end
268
+
269
+ def update_customer_profile(creditcard, options = {})
270
+ options.merge!(:customer_profile_action => UPDATE)
271
+ order = build_customer_request_xml(creditcard, options)
272
+ commit(order, :update_customer_profile)
273
+ end
274
+
275
+ def retrieve_customer_profile(customer_ref_num)
276
+ options = {:customer_profile_action => RETRIEVE, :customer_ref_num => customer_ref_num}
277
+ order = build_customer_request_xml(nil, options)
278
+ commit(order, :retrieve_customer_profile)
279
+ end
280
+
281
+ def delete_customer_profile(customer_ref_num)
282
+ options = {:customer_profile_action => DELETE, :customer_ref_num => customer_ref_num}
283
+ order = build_customer_request_xml(nil, options)
284
+ commit(order, :delete_customer_profile)
285
+ end
286
+
287
+ private
288
+
289
+ def authorization_string(*args)
290
+ args.compact.join(";")
291
+ end
292
+
293
+ def split_authorization(authorization)
294
+ authorization.split(';')
295
+ end
296
+
297
+ def add_customer_data(xml, creditcard, options)
298
+ if options[:profile_txn]
299
+ xml.tag! :CustomerRefNum, options[:customer_ref_num]
300
+ else
301
+ if options[:customer_ref_num]
302
+ if creditcard
303
+ xml.tag! :CustomerProfileFromOrderInd, USE_CUSTOMER_REF_NUM
304
+ end
305
+ xml.tag! :CustomerRefNum, options[:customer_ref_num]
306
+ else
307
+ xml.tag! :CustomerProfileFromOrderInd, AUTO_GENERATE
308
+ end
309
+ xml.tag! :CustomerProfileOrderOverrideInd, options[:customer_profile_order_override_ind] || NO_MAPPING_TO_ORDER_DATA
310
+ end
311
+ end
312
+
313
+ def add_soft_descriptors(xml, soft_desc)
314
+ xml.tag! :SDMerchantName, soft_desc.merchant_name if soft_desc.merchant_name
315
+ xml.tag! :SDProductDescription, soft_desc.product_description if soft_desc.product_description
316
+ xml.tag! :SDMerchantCity, soft_desc.merchant_city if soft_desc.merchant_city
317
+ xml.tag! :SDMerchantPhone, soft_desc.merchant_phone if soft_desc.merchant_phone
318
+ xml.tag! :SDMerchantURL, soft_desc.merchant_url if soft_desc.merchant_url
319
+ xml.tag! :SDMerchantEmail, soft_desc.merchant_email if soft_desc.merchant_email
320
+ end
321
+
322
+ def add_address(xml, creditcard, options)
323
+ if(address = (options[:billing_address] || options[:address]))
324
+ avs_supported = AVS_SUPPORTED_COUNTRIES.include?(address[:country].to_s)
325
+
326
+ if avs_supported
327
+ xml.tag! :AVSzip, (address[:zip] ? address[:zip].to_s[0..9] : nil)
328
+ xml.tag! :AVSaddress1, (address[:address1] ? address[:address1][0..29] : nil)
329
+ xml.tag! :AVSaddress2, (address[:address2] ? address[:address2][0..29] : nil)
330
+ xml.tag! :AVScity, (address[:city] ? address[:city][0..19] : nil)
331
+ xml.tag! :AVSstate, address[:state]
332
+ xml.tag! :AVSphoneNum, (address[:phone] ? address[:phone].scan(/\d/).join.to_s[0..13] : nil)
333
+ end
334
+ # can't look in billing address?
335
+ xml.tag! :AVSname, ((creditcard && creditcard.name) ? creditcard.name[0..29] : nil)
336
+ xml.tag! :AVScountryCode, (avs_supported ? address[:country] : '')
337
+
338
+ # Needs to come after AVScountryCode
339
+ add_destination_address(xml, address) if avs_supported
340
+ end
341
+ end
342
+
343
+ def add_destination_address(xml, address)
344
+ if address[:dest_zip]
345
+ xml.tag! :AVSDestzip, (address[:dest_zip] ? address[:dest_zip].to_s[0..9] : nil)
346
+ xml.tag! :AVSDestaddress1, (address[:dest_address1] ? address[:dest_address1][0..29] : nil)
347
+ xml.tag! :AVSDestaddress2, (address[:dest_address2] ? address[:dest_address2][0..29] : nil)
348
+ xml.tag! :AVSDestcity, (address[:dest_city] ? address[:dest_city][0..19] : nil)
349
+ xml.tag! :AVSDeststate, address[:dest_state]
350
+ xml.tag! :AVSDestphoneNum, (address[:dest_phone] ? address[:dest_phone].scan(/\d/).join.to_s[0..13] : nil)
351
+
352
+ xml.tag! :AVSDestname, (address[:dest_name] ? address[:dest_name][0..29] : nil)
353
+ xml.tag! :AVSDestcountryCode, address[:dest_country]
354
+ end
355
+ end
356
+
357
+ # For Profile requests
358
+ def add_customer_address(xml, options)
359
+ if(address = (options[:billing_address] || options[:address]))
360
+ xml.tag! :CustomerAddress1, (address[:address1] ? address[:address1][0..29] : nil)
361
+ xml.tag! :CustomerAddress2, (address[:address2] ? address[:address2][0..29] : nil)
362
+ xml.tag! :CustomerCity, (address[:city] ? address[:city][0..19] : nil)
363
+ xml.tag! :CustomerState, address[:state]
364
+ xml.tag! :CustomerZIP, (address[:zip] ? address[:zip].to_s[0..9] : nil)
365
+ xml.tag! :CustomerEmail, address[:email].to_s[0..49] if address[:email]
366
+ xml.tag! :CustomerPhone, (address[:phone] ? address[:phone].scan(/\d/).join.to_s : nil)
367
+ xml.tag! :CustomerCountryCode, (address[:country] ? address[:country][0..1] : nil)
368
+ end
369
+ end
370
+
371
+ def add_creditcard(xml, creditcard, currency=nil)
372
+ unless creditcard.nil?
373
+ xml.tag! :AccountNum, creditcard.number
374
+ xml.tag! :Exp, expiry_date(creditcard)
375
+ end
376
+
377
+ xml.tag! :CurrencyCode, currency_code(currency)
378
+ xml.tag! :CurrencyExponent, currency_exponents(currency)
379
+
380
+ # If you are trying to collect a Card Verification Number
381
+ # (CardSecVal) for a Visa or Discover transaction, pass one of these values:
382
+ # 1 Value is Present
383
+ # 2 Value on card but illegible
384
+ # 9 Cardholder states data not available
385
+ # If the transaction is not a Visa or Discover transaction:
386
+ # Null-fill this attribute OR
387
+ # Do not submit the attribute at all.
388
+ # - http://download.chasepaymentech.com/docs/orbital/orbital_gateway_xml_specification.pdf
389
+ unless creditcard.nil?
390
+ if %w( visa discover ).include?(creditcard.brand)
391
+ xml.tag! :CardSecValInd, (creditcard.verification_value? ? '1' : '9')
392
+ end
393
+ xml.tag! :CardSecVal, creditcard.verification_value if creditcard.verification_value?
394
+ end
395
+ end
396
+
397
+ def add_refund(xml, currency=nil)
398
+ xml.tag! :AccountNum, nil
399
+
400
+ xml.tag! :CurrencyCode, currency_code(currency)
401
+ xml.tag! :CurrencyExponent, currency_exponents(currency)
402
+ end
403
+
404
+ def add_managed_billing(xml, options)
405
+ if mb = options[:managed_billing]
406
+ ActiveMerchant.deprecated RECURRING_DEPRECATION_MESSAGE
407
+
408
+ # default to recurring (R). Other option is deferred (D).
409
+ xml.tag! :MBType, mb[:type] || RECURRING
410
+ # default to Customer Reference Number
411
+ xml.tag! :MBOrderIdGenerationMethod, mb[:order_id_generation_method] || 'IO'
412
+ # By default use MBRecurringEndDate, set to N.
413
+ # MMDDYYYY
414
+ xml.tag! :MBRecurringStartDate, mb[:start_date].scan(/\d/).join.to_s if mb[:start_date]
415
+ # MMDDYYYY
416
+ xml.tag! :MBRecurringEndDate, mb[:end_date].scan(/\d/).join.to_s if mb[:end_date]
417
+ # By default listen to any value set in MBRecurringEndDate.
418
+ xml.tag! :MBRecurringNoEndDateFlag, mb[:no_end_date_flag] || 'N' # 'Y' || 'N' (Yes or No).
419
+ xml.tag! :MBRecurringMaxBillings, mb[:max_billings] if mb[:max_billings]
420
+ xml.tag! :MBRecurringFrequency, mb[:frequency] if mb[:frequency]
421
+ xml.tag! :MBDeferredBillDate, mb[:deferred_bill_date] if mb[:deferred_bill_date]
422
+ xml.tag! :MBMicroPaymentMaxDollarValue, mb[:max_dollar_value] if mb[:max_dollar_value]
423
+ xml.tag! :MBMicroPaymentMaxBillingDays, mb[:max_billing_days] if mb[:max_billing_days]
424
+ xml.tag! :MBMicroPaymentMaxTransactions, mb[:max_transactions] if mb[:max_transactions]
425
+ end
426
+ end
427
+
428
+ def parse(body)
429
+ response = {}
430
+ xml = REXML::Document.new(body)
431
+ root = REXML::XPath.first(xml, "//Response") ||
432
+ REXML::XPath.first(xml, "//ErrorResponse")
433
+ if root
434
+ root.elements.to_a.each do |node|
435
+ recurring_parse_element(response, node)
436
+ end
437
+ end
438
+
439
+ response.delete_if { |k,_| SENSITIVE_FIELDS.include?(k) }
440
+ end
441
+
442
+ def recurring_parse_element(response, node)
443
+ if node.has_elements?
444
+ node.elements.each{|e| recurring_parse_element(response, e) }
445
+ else
446
+ response[node.name.underscore.to_sym] = node.text
447
+ end
448
+ end
449
+
450
+ def commit(order, message_type, trace_number=nil)
451
+ headers = POST_HEADERS.merge("Content-length" => order.size.to_s)
452
+ headers.merge!( "Trace-number" => trace_number.to_s,
453
+ "Merchant-Id" => @options[:merchant_id] ) if @options[:retry_logic] && trace_number
454
+ request = lambda{|url| parse(ssl_post(url, order, headers))}
455
+
456
+ # Failover URL will be attempted in the event of a connection error
457
+ response = begin
458
+ request.call(remote_url)
459
+ rescue ConnectionError
460
+ request.call(remote_url(:secondary))
461
+ end
462
+
463
+ Response.new(success?(response, message_type), message_from(response), response,
464
+ {
465
+ :authorization => authorization_string(response[:tx_ref_num], response[:order_id]),
466
+ :test => self.test?,
467
+ :avs_result => OrbitalGateway::AVSResult.new(response[:avs_resp_code]),
468
+ :cvv_result => OrbitalGateway::CVVResult.new(response[:cvv2_resp_code])
469
+ }
470
+ )
471
+ end
472
+
473
+ def remote_url(url=:primary)
474
+ if url == :primary
475
+ (self.test? ? self.test_url : self.live_url)
476
+ else
477
+ (self.test? ? self.secondary_test_url : self.secondary_live_url)
478
+ end
479
+ end
480
+
481
+ def success?(response, message_type)
482
+ if [:refund, :void].include?(message_type)
483
+ response[:proc_status] == SUCCESS
484
+ elsif response[:customer_profile_action]
485
+ response[:profile_proc_status] == SUCCESS
486
+ else
487
+ response[:proc_status] == SUCCESS &&
488
+ APPROVED.include?(response[:resp_code])
489
+ end
490
+ end
491
+
492
+ def message_from(response)
493
+ response[:resp_msg] || response[:status_msg] || response[:customer_profile_message]
494
+ end
495
+
496
+ def ip_authentication?
497
+ @options[:ip_authentication] == true
498
+ end
499
+
500
+ def build_new_order_xml(action, money, parameters = {})
501
+ requires!(parameters, :order_id)
502
+ xml = xml_envelope
503
+ xml.tag! :Request do
504
+ xml.tag! :NewOrder do
505
+ add_xml_credentials(xml)
506
+ # EC - Ecommerce transaction
507
+ # RC - Recurring Payment transaction
508
+ # MO - Mail Order Telephone Order transaction
509
+ # IV - Interactive Voice Response
510
+ # IN - Interactive Voice Response
511
+ xml.tag! :IndustryType, parameters[:industry_type] || ECOMMERCE_TRANSACTION
512
+ # A - Auth Only No Capture
513
+ # AC - Auth and Capture
514
+ # F - Force Auth No Capture and no online authorization
515
+ # FR - Force Auth No Capture and no online authorization
516
+ # FC - Force Auth and Capture no online authorization
517
+ # R - Refund and Capture no online authorization
518
+ xml.tag! :MessageType, action
519
+ add_bin_merchant_and_terminal(xml, parameters)
520
+
521
+ yield xml if block_given?
522
+
523
+ xml.tag! :OrderID, format_order_id(parameters[:order_id])
524
+ xml.tag! :Amount, amount(money)
525
+ xml.tag! :Comments, parameters[:comments] if parameters[:comments]
526
+
527
+ # CustomerAni, AVSPhoneType and AVSDestPhoneType could be added here.
528
+
529
+ if parameters[:soft_descriptors].is_a?(OrbitalSoftDescriptors)
530
+ add_soft_descriptors(xml, parameters[:soft_descriptors])
531
+ end
532
+
533
+ set_recurring_ind(xml, parameters)
534
+
535
+ # Append Transaction Reference Number at the end for Refund transactions
536
+ if action == REFUND
537
+ tx_ref_num, _ = split_authorization(parameters[:authorization])
538
+ xml.tag! :TxRefNum, tx_ref_num
539
+ end
540
+ end
541
+ end
542
+ xml.target!
543
+ end
544
+
545
+ # For Canadian transactions on PNS Tampa on New Order
546
+ # RF - First Recurring Transaction
547
+ # RS - Subsequent Recurring Transactions
548
+ def set_recurring_ind(xml, parameters)
549
+ if parameters[:recurring_ind]
550
+ raise "RecurringInd must be set to either \"RF\" or \"RS\"" unless %w(RF RS).include?(parameters[:recurring_ind])
551
+ xml.tag! :RecurringInd, parameters[:recurring_ind]
552
+ end
553
+ end
554
+
555
+ def build_mark_for_capture_xml(money, authorization, parameters = {})
556
+ tx_ref_num, order_id = split_authorization(authorization)
557
+ xml = xml_envelope
558
+ xml.tag! :Request do
559
+ xml.tag! :MarkForCapture do
560
+ add_xml_credentials(xml)
561
+ xml.tag! :OrderID, format_order_id(order_id)
562
+ xml.tag! :Amount, amount(money)
563
+ add_bin_merchant_and_terminal(xml, parameters)
564
+ xml.tag! :TxRefNum, tx_ref_num
565
+ end
566
+ end
567
+ xml.target!
568
+ end
569
+
570
+ def build_void_request_xml(authorization, parameters = {})
571
+ tx_ref_num, order_id = split_authorization(authorization)
572
+ xml = xml_envelope
573
+ xml.tag! :Request do
574
+ xml.tag! :Reversal do
575
+ add_xml_credentials(xml)
576
+ xml.tag! :TxRefNum, tx_ref_num
577
+ xml.tag! :TxRefIdx, parameters[:transaction_index]
578
+ xml.tag! :AdjustedAmt, parameters[:amount] # setting adjusted amount to nil will void entire amount
579
+ xml.tag! :OrderID, format_order_id(order_id || parameters[:order_id])
580
+ add_bin_merchant_and_terminal(xml, parameters)
581
+ xml.tag! :ReversalRetryNumber, parameters[:reversal_retry_number] if parameters[:reversal_retry_number]
582
+ xml.tag! :OnlineReversalInd, parameters[:online_reversal_ind] if parameters[:online_reversal_ind]
583
+ end
584
+ end
585
+ xml.target!
586
+ end
587
+
588
+ def currency_code(currency)
589
+ CURRENCY_CODES[(currency || self.default_currency)].to_s
590
+ end
591
+
592
+ def currency_exponents(currency)
593
+ CURRENCY_EXPONENTS[(currency || self.default_currency)].to_s
594
+ end
595
+
596
+ def expiry_date(credit_card)
597
+ "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
598
+ end
599
+
600
+ def bin
601
+ @options[:bin] || (salem_mid? ? '000001' : '000002')
602
+ end
603
+
604
+ def xml_envelope
605
+ xml = Builder::XmlMarkup.new(:indent => 2)
606
+ xml.instruct!(:xml, :version => '1.0', :encoding => 'UTF-8')
607
+ xml
608
+ end
609
+
610
+ def add_xml_credentials(xml)
611
+ unless ip_authentication?
612
+ xml.tag! :OrbitalConnectionUsername, @options[:login]
613
+ xml.tag! :OrbitalConnectionPassword, @options[:password]
614
+ end
615
+ end
616
+
617
+ def add_bin_merchant_and_terminal(xml, parameters)
618
+ xml.tag! :BIN, bin
619
+ xml.tag! :MerchantID, @options[:merchant_id]
620
+ xml.tag! :TerminalID, parameters[:terminal_id] || '001'
621
+ end
622
+
623
+ def salem_mid?
624
+ @options[:merchant_id].length == 6
625
+ end
626
+
627
+ # The valid characters include:
628
+ #
629
+ # 1. all letters and digits
630
+ # 2. - , $ @ & and a space character, though the space character cannot be the leading character
631
+ # 3. PINless Debit transactions can only use uppercase and lowercase alpha (A-Z, a-z) and numeric (0-9)
632
+ def format_order_id(order_id)
633
+ illegal_characters = /[^,$@\- \w]/
634
+ order_id = order_id.to_s.gsub(/\./, '-')
635
+ order_id.gsub!(illegal_characters, '')
636
+ order_id[0...22]
637
+ end
638
+
639
+ def build_customer_request_xml(creditcard, options = {})
640
+ xml = xml_envelope
641
+ xml.tag! :Request do
642
+ xml.tag! :Profile do
643
+ xml.tag! :OrbitalConnectionUsername, @options[:login] unless ip_authentication?
644
+ xml.tag! :OrbitalConnectionPassword, @options[:password] unless ip_authentication?
645
+ xml.tag! :CustomerBin, bin
646
+ xml.tag! :CustomerMerchantID, @options[:merchant_id]
647
+ xml.tag! :CustomerName, creditcard.name if creditcard
648
+ xml.tag! :CustomerRefNum, options[:customer_ref_num] if options[:customer_ref_num]
649
+
650
+ add_customer_address(xml, options)
651
+
652
+ xml.tag! :CustomerProfileAction, options[:customer_profile_action] # C, R, U, D
653
+ # NO No mapping to order data
654
+ # OI Use <CustomerRefNum> for <OrderID>
655
+ # OD Use <CustomerReferNum> for <Comments>
656
+ # OA Use <CustomerRefNum> for <OrderID> and <Comments>
657
+ xml.tag! :CustomerProfileOrderOverrideInd, options[:customer_profile_order_override_ind] || NO_MAPPING_TO_ORDER_DATA
658
+
659
+ if options[:customer_profile_action] == CREATE
660
+ # A Auto-Generate the CustomerRefNum
661
+ # S Use CustomerRefNum field
662
+ # O Use OrderID field
663
+ # D Use Comments field
664
+ xml.tag! :CustomerProfileFromOrderInd, (options[:customer_ref_num] ? USE_CUSTOMER_REF_NUM : AUTO_GENERATE)
665
+ end
666
+
667
+ xml.tag! :OrderDefaultDescription, options[:order_default_description][0..63] if options[:order_default_description]
668
+ xml.tag! :OrderDefaultAmount, options[:order_default_amount] if options[:order_default_amount]
669
+
670
+ if [CREATE, UPDATE].include? options[:customer_profile_action]
671
+ xml.tag! :CustomerAccountType, 'CC' # Only credit card supported
672
+ xml.tag! :Status, options[:status] || ACTIVE # Active
673
+ end
674
+
675
+ xml.tag! :CCAccountNum, creditcard.number if creditcard
676
+ xml.tag! :CCExpireDate, creditcard.expiry_date.expiration.strftime("%m%y") if creditcard
677
+
678
+ # This has to come after CCExpireDate.
679
+ add_managed_billing(xml, options)
680
+ end
681
+ end
682
+ xml.target!
683
+ end
684
+
685
+ # Unfortunately, Orbital uses their own special codes for AVS responses
686
+ # that are different than the standard codes defined in
687
+ # <tt>ActiveMerchant::Billing::AVSResult</tt>.
688
+ #
689
+ # This class encapsulates the response codes shown on page 240 of their spec:
690
+ # http://download.chasepaymentech.com/docs/orbital/orbital_gateway_xml_specification.pdf
691
+ #
692
+ class AVSResult < ActiveMerchant::Billing::AVSResult
693
+ CODES = {
694
+ '1' => 'No address supplied',
695
+ '2' => 'Bill-to address did not pass Auth Host edit checks',
696
+ '3' => 'AVS not performed',
697
+ '4' => 'Issuer does not participate in AVS',
698
+ '5' => 'Edit-error - AVS data is invalid',
699
+ '6' => 'System unavailable or time-out',
700
+ '7' => 'Address information unavailable',
701
+ '8' => 'Transaction Ineligible for AVS',
702
+ '9' => 'Zip Match/Zip 4 Match/Locale match',
703
+ 'A' => 'Zip Match/Zip 4 Match/Locale no match',
704
+ 'B' => 'Zip Match/Zip 4 no Match/Locale match',
705
+ 'C' => 'Zip Match/Zip 4 no Match/Locale no match',
706
+ 'D' => 'Zip No Match/Zip 4 Match/Locale match',
707
+ 'E' => 'Zip No Match/Zip 4 Match/Locale no match',
708
+ 'F' => 'Zip No Match/Zip 4 No Match/Locale match',
709
+ 'G' => 'No match at all',
710
+ 'H' => 'Zip Match/Locale match',
711
+ 'J' => 'Issuer does not participate in Global AVS',
712
+ 'JA' => 'International street address and postal match',
713
+ 'JB' => 'International street address match. Postal code not verified',
714
+ 'JC' => 'International street address and postal code not verified',
715
+ 'JD' => 'International postal code match. Street address not verified',
716
+ 'M1' => 'Cardholder name matches',
717
+ 'M2' => 'Cardholder name, billing address, and postal code matches',
718
+ 'M3' => 'Cardholder name and billing code matches',
719
+ 'M4' => 'Cardholder name and billing address match',
720
+ 'M5' => 'Cardholder name incorrect, billing address and postal code match',
721
+ 'M6' => 'Cardholder name incorrect, billing postal code matches',
722
+ 'M7' => 'Cardholder name incorrect, billing address matches',
723
+ 'M8' => 'Cardholder name, billing address and postal code are all incorrect',
724
+ 'N3' => 'Address matches, ZIP not verified',
725
+ 'N4' => 'Address and ZIP code not verified due to incompatible formats',
726
+ 'N5' => 'Address and ZIP code match (International only)',
727
+ 'N6' => 'Address not verified (International only)',
728
+ 'N7' => 'ZIP matches, address not verified',
729
+ 'N8' => 'Address and ZIP code match (International only)',
730
+ 'N9' => 'Address and ZIP code match (UK only)',
731
+ 'R' => 'Issuer does not participate in AVS',
732
+ 'UK' => 'Unknown',
733
+ 'X' => 'Zip Match/Zip 4 Match/Address Match',
734
+ 'Z' => 'Zip Match/Locale no match',
735
+ }
736
+
737
+ # Map vendor's AVS result code to a postal match code
738
+ ORBITAL_POSTAL_MATCH_CODE = {
739
+ 'Y' => %w( 9 A B C H JA JD M2 M3 M5 N5 N8 N9 X Z ),
740
+ 'N' => %w( D E F G M8 ),
741
+ 'X' => %w( 4 J R ),
742
+ nil => %w( 1 2 3 5 6 7 8 JB JC M1 M4 M6 M7 N3 N4 N6 N7 UK )
743
+ }.inject({}) do |map, (type, codes)|
744
+ codes.each { |code| map[code] = type }
745
+ map
746
+ end
747
+
748
+ # Map vendor's AVS result code to a street match code
749
+ ORBITAL_STREET_MATCH_CODE = {
750
+ 'Y' => %w( 9 B D F H JA JB M2 M4 M5 M6 M7 N3 N5 N7 N8 N9 X ),
751
+ 'N' => %w( A C E G M8 Z ),
752
+ 'X' => %w( 4 J R ),
753
+ nil => %w( 1 2 3 5 6 7 8 JC JD M1 M3 N4 N6 UK )
754
+ }.inject({}) do |map, (type, codes)|
755
+ codes.each { |code| map[code] = type }
756
+ map
757
+ end
758
+
759
+ def self.messages
760
+ CODES
761
+ end
762
+
763
+ def initialize(code)
764
+ @code = (code.blank? ? nil : code.to_s.strip.upcase)
765
+ if @code
766
+ @message = CODES[@code]
767
+ @postal_match = ORBITAL_POSTAL_MATCH_CODE[@code]
768
+ @street_match = ORBITAL_STREET_MATCH_CODE[@code]
769
+ end
770
+ end
771
+ end
772
+
773
+ # Unfortunately, Orbital uses their own special codes for CVV responses
774
+ # that are different than the standard codes defined in
775
+ # <tt>ActiveMerchant::Billing::CVVResult</tt>.
776
+ #
777
+ # This class encapsulates the response codes shown on page 255 of their spec:
778
+ # http://download.chasepaymentech.com/docs/orbital/orbital_gateway_xml_specification.pdf
779
+ #
780
+ class CVVResult < ActiveMerchant::Billing::CVVResult
781
+ MESSAGES = {
782
+ 'M' => 'Match',
783
+ 'N' => 'No match',
784
+ 'P' => 'Not processed',
785
+ 'S' => 'Should have been present',
786
+ 'U' => 'Unsupported by issuer/Issuer unable to process request',
787
+ 'I' => 'Invalid',
788
+ 'Y' => 'Invalid',
789
+ '' => 'Not applicable'
790
+ }
791
+
792
+ def self.messages
793
+ MESSAGES
794
+ end
795
+
796
+ def initialize(code)
797
+ @code = code.blank? ? '' : code.upcase
798
+ @message = MESSAGES[@code]
799
+ end
800
+ end
801
+ end
802
+ end
803
+ end