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,352 @@
1
+ require 'time'
2
+ require 'date'
3
+ require "active_merchant/billing/model"
4
+
5
+ module ActiveMerchant #:nodoc:
6
+ module Billing #:nodoc:
7
+ # A +CreditCard+ object represents a physical credit card, and is capable of validating the various
8
+ # data associated with these.
9
+ #
10
+ # At the moment, the following credit card types are supported:
11
+ #
12
+ # * Visa
13
+ # * MasterCard
14
+ # * Discover
15
+ # * American Express
16
+ # * Diner's Club
17
+ # * JCB
18
+ # * Switch
19
+ # * Solo
20
+ # * Dankort
21
+ # * Maestro
22
+ # * Forbrugsforeningen
23
+ # * Laser
24
+ #
25
+ # For testing purposes, use the 'bogus' credit card brand. This skips the vast majority of
26
+ # validations, allowing you to focus on your core concerns until you're ready to be more concerned
27
+ # with the details of particular credit cards or your gateway.
28
+ #
29
+ # == Testing With CreditCard
30
+ # Often when testing we don't care about the particulars of a given card brand. When using the 'test'
31
+ # mode in your {Gateway}, there are six different valid card numbers: 1, 2, 3, 'success', 'fail',
32
+ # and 'error'.
33
+ #
34
+ # For details, see {CreditCardMethods::ClassMethods#valid_number?}
35
+ #
36
+ # == Example Usage
37
+ # cc = CreditCard.new(
38
+ # :first_name => 'Steve',
39
+ # :last_name => 'Smith',
40
+ # :month => '9',
41
+ # :year => '2010',
42
+ # :brand => 'visa',
43
+ # :number => '4242424242424242'
44
+ # )
45
+ #
46
+ # cc.validate # => {}
47
+ # cc.display_number # => XXXX-XXXX-XXXX-4242
48
+ #
49
+ class CreditCard < Model
50
+ include CreditCardMethods
51
+
52
+ cattr_accessor :require_verification_value
53
+ self.require_verification_value = true
54
+
55
+ # Returns or sets the credit card number.
56
+ #
57
+ # @return [String]
58
+ attr_reader :number
59
+
60
+ def number=(value)
61
+ @number = (empty?(value) ? value : value.to_s.gsub(/[^\d]/, ""))
62
+ end
63
+
64
+ # Returns or sets the expiry month for the card.
65
+ #
66
+ # @return [Integer]
67
+ attr_reader :month
68
+
69
+ # Returns or sets the expiry year for the card.
70
+ #
71
+ # @return [Integer]
72
+ attr_reader :year
73
+
74
+ # Returns or sets the credit card brand.
75
+ #
76
+ # Valid card types are
77
+ #
78
+ # * +'visa'+
79
+ # * +'master'+
80
+ # * +'discover'+
81
+ # * +'american_express'+
82
+ # * +'diners_club'+
83
+ # * +'jcb'+
84
+ # * +'switch'+
85
+ # * +'solo'+
86
+ # * +'dankort'+
87
+ # * +'maestro'+
88
+ # * +'forbrugsforeningen'+
89
+ # * +'laser'+
90
+ #
91
+ # Or, if you wish to test your implementation, +'bogus'+.
92
+ #
93
+ # @return (String) the credit card brand
94
+ def brand
95
+ if !defined?(@brand) || empty?(@brand)
96
+ self.class.brand?(number)
97
+ else
98
+ @brand
99
+ end
100
+ end
101
+
102
+ def brand=(value)
103
+ value = value && value.to_s.dup
104
+ @brand = (value.respond_to?(:downcase) ? value.downcase : value)
105
+ end
106
+
107
+ # Returns or sets the first name of the card holder.
108
+ #
109
+ # @return [String]
110
+ attr_accessor :first_name
111
+
112
+ # Returns or sets the last name of the card holder.
113
+ #
114
+ # @return [String]
115
+ attr_accessor :last_name
116
+
117
+ # Required for Switch / Solo cards
118
+ attr_reader :start_month, :start_year
119
+ attr_accessor :issue_number
120
+
121
+ # Returns or sets the card verification value.
122
+ #
123
+ # This attribute is optional but recommended. The verification value is
124
+ # a {card security code}[http://en.wikipedia.org/wiki/Card_security_code]. If provided,
125
+ # the gateway will attempt to validate the value.
126
+ #
127
+ # @return [String] the verification value
128
+ attr_accessor :verification_value
129
+
130
+ # Returns or sets the track data for the card
131
+ #
132
+ # @return [String]
133
+ attr_accessor :track_data
134
+
135
+ def type
136
+ ActiveMerchant.deprecated "CreditCard#type is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand instead."
137
+ brand
138
+ end
139
+
140
+ def type=(value)
141
+ ActiveMerchant.deprecated "CreditCard#type is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand instead."
142
+ self.brand = value
143
+ end
144
+
145
+ # Provides proxy access to an expiry date object
146
+ #
147
+ # @return [ExpiryDate]
148
+ def expiry_date
149
+ ExpiryDate.new(@month, @year)
150
+ end
151
+
152
+ # Returns whether the credit card has expired.
153
+ #
154
+ # @return +true+ if the card has expired, +false+ otherwise
155
+ def expired?
156
+ expiry_date.expired?
157
+ end
158
+
159
+ # Returns whether either the +first_name+ or the +last_name+ attributes has been set.
160
+ def name?
161
+ first_name? || last_name?
162
+ end
163
+
164
+ # Returns whether the +first_name+ attribute has been set.
165
+ def first_name?
166
+ first_name.present?
167
+ end
168
+
169
+ # Returns whether the +last_name+ attribute has been set.
170
+ def last_name?
171
+ last_name.present?
172
+ end
173
+
174
+ # Returns the full name of the card holder.
175
+ #
176
+ # @return [String] the full name of the card holder
177
+ def name
178
+ [first_name, last_name].compact.join(' ')
179
+ end
180
+
181
+ def name=(full_name)
182
+ names = full_name.split
183
+ self.last_name = names.pop
184
+ self.first_name = names.join(" ")
185
+ end
186
+
187
+ %w(month year start_month start_year).each do |m|
188
+ class_eval %(
189
+ def #{m}=(v)
190
+ @#{m} = case v
191
+ when "", nil, 0
192
+ nil
193
+ else
194
+ v.to_i
195
+ end
196
+ end
197
+ )
198
+ end
199
+
200
+ def verification_value?
201
+ !verification_value.blank?
202
+ end
203
+
204
+ # Returns a display-friendly version of the card number.
205
+ #
206
+ # All but the last 4 numbers are replaced with an "X", and hyphens are
207
+ # inserted in order to improve legibility.
208
+ #
209
+ # @example
210
+ # credit_card = CreditCard.new(:number => "2132542376824338")
211
+ # credit_card.display_number # "XXXX-XXXX-XXXX-4338"
212
+ #
213
+ # @return [String] a display-friendly version of the card number
214
+ def display_number
215
+ self.class.mask(number)
216
+ end
217
+
218
+ def first_digits
219
+ self.class.first_digits(number)
220
+ end
221
+
222
+ def last_digits
223
+ self.class.last_digits(number)
224
+ end
225
+
226
+ # Validates the credit card details.
227
+ #
228
+ # Any validation errors are added to the {#errors} attribute.
229
+ def validate
230
+ errors = validate_essential_attributes + validate_verification_value
231
+
232
+ # Bogus card is pretty much for testing purposes. Lets just skip these extra tests if its used
233
+ return errors_hash(errors) if brand == 'bogus'
234
+
235
+ errors_hash(
236
+ errors +
237
+ validate_card_brand_and_number +
238
+ validate_switch_or_solo_attributes
239
+ )
240
+ end
241
+
242
+ def self.requires_verification_value?
243
+ require_verification_value
244
+ end
245
+
246
+ private
247
+
248
+ def validate_essential_attributes #:nodoc:
249
+ errors = []
250
+
251
+ errors << [:first_name, "cannot be empty"] if first_name.blank?
252
+ errors << [:last_name, "cannot be empty"] if last_name.blank?
253
+
254
+ if(empty?(month) || empty?(year))
255
+ errors << [:month, "is required"] if empty?(month)
256
+ errors << [:year, "is required"] if empty?(year)
257
+ else
258
+ errors << [:month, "is not a valid month"] if !valid_month?(month)
259
+
260
+ if expired?
261
+ errors << [:year, "expired"]
262
+ else
263
+ errors << [:year, "is not a valid year"] if !valid_expiry_year?(year)
264
+ end
265
+ end
266
+
267
+ errors
268
+ end
269
+
270
+ def validate_card_brand_and_number #:nodoc:
271
+ errors = []
272
+
273
+ if !empty?(brand)
274
+ errors << [:brand, "is invalid"] if !CreditCard.card_companies.keys.include?(brand)
275
+ end
276
+
277
+ if empty?(number)
278
+ errors << [:number, "is required"]
279
+ elsif !CreditCard.valid_number?(number)
280
+ errors << [:number, "is not a valid credit card number"]
281
+ end
282
+
283
+ if errors.empty?
284
+ errors << [:brand, "does not match the card number"] if !CreditCard.matching_brand?(number, brand)
285
+ end
286
+
287
+ errors
288
+ end
289
+
290
+ def validate_verification_value #:nodoc:
291
+ errors = []
292
+
293
+ if verification_value?
294
+ unless valid_card_verification_value?(verification_value, brand)
295
+ errors << [:verification_value, "should be #{card_verification_value_length(brand)} digits"]
296
+ end
297
+ elsif CreditCard.requires_verification_value?
298
+ errors << [:verification_value, "is required"]
299
+ end
300
+ errors
301
+ end
302
+
303
+ def validate_switch_or_solo_attributes #:nodoc:
304
+ errors = []
305
+
306
+ if %w[switch solo].include?(brand)
307
+ valid_start_month = valid_month?(start_month)
308
+ valid_start_year = valid_start_year?(start_year)
309
+
310
+ if((!valid_start_month || !valid_start_year) && !valid_issue_number?(issue_number))
311
+ if empty?(issue_number)
312
+ errors << [:issue_number, "cannot be empty"]
313
+ errors << [:start_month, "is invalid"] if !valid_start_month
314
+ errors << [:start_year, "is invalid"] if !valid_start_year
315
+ else
316
+ errors << [:issue_number, "is invalid"] if !valid_issue_number?(issue_number)
317
+ end
318
+ end
319
+ end
320
+
321
+ errors
322
+ end
323
+
324
+ class ExpiryDate #:nodoc:
325
+ attr_reader :month, :year
326
+ def initialize(month, year)
327
+ @month = month.to_i
328
+ @year = year.to_i
329
+ end
330
+
331
+ def expired? #:nodoc:
332
+ Time.now.utc > expiration
333
+ end
334
+
335
+ def expiration #:nodoc:
336
+ begin
337
+ Time.utc(year, month, month_days, 23, 59, 59)
338
+ rescue ArgumentError
339
+ Time.at(0).utc
340
+ end
341
+ end
342
+
343
+ private
344
+ def month_days
345
+ mdays = [nil,31,28,31,30,31,30,31,31,30,31,30,31]
346
+ mdays[2] = 29 if Date.leap?(year)
347
+ mdays[month]
348
+ end
349
+ end
350
+ end
351
+ end
352
+ end
@@ -0,0 +1,24 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ module CreditCardFormatting
4
+
5
+ def expdate(credit_card)
6
+ "#{format(credit_card.month, :two_digits)}#{format(credit_card.year, :two_digits)}"
7
+ end
8
+
9
+ # This method is used to format numerical information pertaining to credit cards.
10
+ #
11
+ # format(2005, :two_digits) # => "05"
12
+ # format(05, :four_digits) # => "0005"
13
+ def format(number, option)
14
+ return '' if number.blank?
15
+
16
+ case option
17
+ when :two_digits ; sprintf("%.2i", number.to_i)[-2..-1]
18
+ when :four_digits ; sprintf("%.4i", number.to_i)[-4..-1]
19
+ else number
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,160 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ # Convenience methods that can be included into a custom Credit Card object, such as an ActiveRecord based Credit Card object.
4
+ module CreditCardMethods
5
+ CARD_COMPANIES = {
6
+ 'visa' => /^4\d{12}(\d{3})?$/,
7
+ 'master' => /^(5[1-5]\d{4}|677189)\d{10}$/,
8
+ 'discover' => /^(6011|65\d{2}|64[4-9]\d)\d{12}|(62\d{14})$/,
9
+ 'american_express' => /^3[47]\d{13}$/,
10
+ 'diners_club' => /^3(0[0-5]|[68]\d)\d{11}$/,
11
+ 'jcb' => /^35(28|29|[3-8]\d)\d{12}$/,
12
+ 'switch' => /^6759\d{12}(\d{2,3})?$/,
13
+ 'solo' => /^6767\d{12}(\d{2,3})?$/,
14
+ 'dankort' => /^5019\d{12}$/,
15
+ 'maestro' => /^(5[06-8]|6\d)\d{10,17}$/,
16
+ 'forbrugsforeningen' => /^600722\d{10}$/,
17
+ 'laser' => /^(6304|6706|6709|6771(?!89))\d{8}(\d{4}|\d{6,7})?$/
18
+ }
19
+
20
+ def self.included(base)
21
+ base.extend(ClassMethods)
22
+ end
23
+
24
+ def valid_month?(month)
25
+ (1..12).include?(month.to_i)
26
+ end
27
+
28
+ def valid_expiry_year?(year)
29
+ (Time.now.year..Time.now.year + 20).include?(year.to_i)
30
+ end
31
+
32
+ def valid_start_year?(year)
33
+ ((year.to_s =~ /^\d{4}$/) && (year.to_i > 1987))
34
+ end
35
+
36
+ # Credit card providers have 3 digit verification values
37
+ # This isn't standardised, these are called various names such as
38
+ # CVC, CVV, CID, CSC and more
39
+ # See: http://en.wikipedia.org/wiki/Card_security_code
40
+ # American Express is the exception with 4 digits
41
+ #
42
+ # Below are links from the card providers with their requirements
43
+ # visa: http://usa.visa.com/personal/security/3-digit-security-code.jsp
44
+ # master: http://www.mastercard.com/ca/merchant/en/getstarted/Anatomy_MasterCard.html
45
+ # jcb: http://www.jcbcard.com/security/info.html
46
+ # diners_club: http://www.dinersclub.com/assets/DinersClub_card_ID_features.pdf
47
+ # discover: https://www.discover.com/credit-cards/help-center/glossary.html
48
+ # american_express: https://online.americanexpress.com/myca/fuidfyp/us/action?request_type=un_fuid&Face=en_US
49
+ def valid_card_verification_value?(cvv, brand)
50
+ cvv.to_s =~ /^\d{#{card_verification_value_length(brand)}}$/
51
+ end
52
+
53
+ def card_verification_value_length(brand)
54
+ brand == 'american_express' ? 4 : 3
55
+ end
56
+
57
+ def valid_issue_number?(number)
58
+ (number.to_s =~ /^\d{1,2}$/)
59
+ end
60
+
61
+ module ClassMethods
62
+ # Returns true if it validates. Optionally, you can pass a card brand as an argument and
63
+ # make sure it is of the correct brand.
64
+ #
65
+ # References:
66
+ # - http://perl.about.com/compute/perl/library/nosearch/P073000.htm
67
+ # - http://www.beachnet.com/~hstiles/cardtype.html
68
+ def valid_number?(number)
69
+ valid_test_mode_card_number?(number) ||
70
+ valid_card_number_length?(number) &&
71
+ valid_checksum?(number)
72
+ end
73
+
74
+ # Regular expressions for the known card companies.
75
+ #
76
+ # References:
77
+ # - http://en.wikipedia.org/wiki/Credit_card_number
78
+ # - http://www.barclaycardbusiness.co.uk/information_zone/processing/bin_rules.html
79
+ def card_companies
80
+ CARD_COMPANIES
81
+ end
82
+
83
+ # Returns a string containing the brand of card from the list of known information below.
84
+ # Need to check the cards in a particular order, as there is some overlap of the allowable ranges
85
+ #--
86
+ # TODO Refactor this method. We basically need to tighten up the Maestro Regexp.
87
+ #
88
+ # Right now the Maestro regexp overlaps with the MasterCard regexp (IIRC). If we can tighten
89
+ # things up, we can boil this whole thing down to something like...
90
+ #
91
+ # def brand?(number)
92
+ # return 'visa' if valid_test_mode_card_number?(number)
93
+ # card_companies.find([nil]) { |brand, regexp| number =~ regexp }.first.dup
94
+ # end
95
+ #
96
+ def brand?(number)
97
+ return 'bogus' if valid_test_mode_card_number?(number)
98
+
99
+ card_companies.reject { |c,p| c == 'maestro' }.each do |company, pattern|
100
+ return company.dup if number =~ pattern
101
+ end
102
+
103
+ return 'maestro' if number =~ card_companies['maestro']
104
+
105
+ return nil
106
+ end
107
+
108
+ def type?(number)
109
+ ActiveMerchant.deprecated "CreditCard#type? is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#brand? instead."
110
+ brand?(number)
111
+ end
112
+
113
+ def first_digits(number)
114
+ number.to_s.slice(0,6)
115
+ end
116
+
117
+ def last_digits(number)
118
+ number.to_s.length <= 4 ? number : number.to_s.slice(-4..-1)
119
+ end
120
+
121
+ def mask(number)
122
+ "XXXX-XXXX-XXXX-#{last_digits(number)}"
123
+ end
124
+
125
+ # Checks to see if the calculated brand matches the specified brand
126
+ def matching_brand?(number, brand)
127
+ brand?(number) == brand
128
+ end
129
+
130
+ def matching_type?(number, brand)
131
+ ActiveMerchant.deprecated "CreditCard#matching_type? is deprecated and will be removed from a future release of ActiveMerchant. Please use CreditCard#matching_brand? instead."
132
+ matching_brand?(number, brand)
133
+ end
134
+
135
+ private
136
+
137
+ def valid_card_number_length?(number) #:nodoc:
138
+ number.to_s.length >= 12
139
+ end
140
+
141
+ def valid_test_mode_card_number?(number) #:nodoc:
142
+ ActiveMerchant::Billing::Base.test? &&
143
+ %w[1 2 3 success failure error].include?(number.to_s)
144
+ end
145
+
146
+ # Checks the validity of a card number by use of the Luhn Algorithm.
147
+ # Please see http://en.wikipedia.org/wiki/Luhn_algorithm for details.
148
+ def valid_checksum?(number) #:nodoc:
149
+ sum = 0
150
+ for i in 0..number.length
151
+ weight = number[-1 * (i + 2), 1].to_i * (2 - (i % 2))
152
+ sum += (weight < 10) ? weight : weight - 9
153
+ end
154
+
155
+ (number[-1,1].to_i == (10 - sum % 10) % 10)
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end