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