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,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