am_credit_card 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,34 @@
1
+ require 'date'
2
+
3
+ module ActiveMerchant
4
+ module Billing
5
+ class CreditCard
6
+ class ExpiryDate #:nodoc:
7
+ attr_reader :month, :year
8
+ def initialize(month, year)
9
+ @month = month.to_i
10
+ @year = year.to_i
11
+ end
12
+
13
+ def expired? #:nodoc:
14
+ Time.now.utc > expiration
15
+ end
16
+
17
+ def expiration #:nodoc:
18
+ begin
19
+ Time.utc(year, month, month_days, 23, 59, 59)
20
+ rescue ArgumentError
21
+ Time.at(0).utc
22
+ end
23
+ end
24
+
25
+ private
26
+ def month_days
27
+ mdays = [nil,31,28,31,30,31,30,31,31,30,31,30,31]
28
+ mdays[2] = 29 if Date.leap?(year)
29
+ mdays[month]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,81 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Validateable #:nodoc:
3
+ def valid?
4
+ errors.clear
5
+
6
+ before_validate if respond_to?(:before_validate, true)
7
+ validate if respond_to?(:validate, true)
8
+
9
+ errors.empty?
10
+ end
11
+
12
+ def initialize(attributes = {})
13
+ self.attributes = attributes
14
+ end
15
+
16
+ def errors
17
+ @errors ||= Errors.new(self)
18
+ end
19
+
20
+ private
21
+
22
+ def attributes=(attributes)
23
+ unless attributes.nil?
24
+ for key, value in attributes
25
+ send("#{key}=", value )
26
+ end
27
+ end
28
+ end
29
+
30
+ # This hash keeps the errors of the object
31
+ class Errors < HashWithIndifferentAccess
32
+
33
+ def initialize(base)
34
+ super() { |h, k| h[k] = [] ; h[k] }
35
+ @base = base
36
+ end
37
+
38
+ def count
39
+ size
40
+ end
41
+
42
+ def empty?
43
+ all? { |k, v| v && v.empty? }
44
+ end
45
+
46
+ # returns a specific fields error message.
47
+ # if more than one error is available we will only return the first. If no error is available
48
+ # we return an empty string
49
+ def on(field)
50
+ self[field].to_a.first
51
+ end
52
+
53
+ def add(field, error)
54
+ self[field] << error
55
+ end
56
+
57
+ def add_to_base(error)
58
+ add(:base, error)
59
+ end
60
+
61
+ def each_full
62
+ full_messages.each { |msg| yield msg }
63
+ end
64
+
65
+ def full_messages
66
+ result = []
67
+
68
+ self.each do |key, messages|
69
+ next if messages.blank?
70
+ if key == 'base'
71
+ result << "#{messages.first}"
72
+ else
73
+ result << "#{key.to_s.humanize} #{messages.first}"
74
+ end
75
+ end
76
+
77
+ result
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,32 @@
1
+ #--
2
+ # Copyright (c) 2005-2010 Tobias Luetke
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #++
23
+
24
+ require 'active_support/core_ext/class/attribute_accessors'
25
+ require 'active_support/core_ext/hash/indifferent_access'
26
+ require 'active_support/core_ext/object/conversions'
27
+ require 'active_support/core_ext/object/blank'
28
+
29
+ require 'active_merchant/validateable'
30
+ require 'active_merchant/billing/base'
31
+ require 'active_merchant/billing/credit_card_methods'
32
+ require 'active_merchant/billing/credit_card'
@@ -0,0 +1,3 @@
1
+ module AmCreditCard
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.expand_path('../../lib', __FILE__)
3
+
4
+ begin
5
+ require 'rubygems'
6
+ require 'bundler'
7
+ Bundler.setup
8
+ rescue LoadError => e
9
+ puts "Error loading bundler (#{e.message}): \"gem install bundler\" for bundler support."
10
+ end
11
+
12
+ require 'test/unit'
13
+ require "am_credit_card"
14
+
15
+ module ActiveMerchant
16
+ module Assertions
17
+ AssertionClass = RUBY_VERSION > '1.9' ? MiniTest::Assertion : Test::Unit::AssertionFailedError
18
+
19
+ def assert_field(field, value)
20
+ clean_backtrace do
21
+ assert_equal value, @helper.fields[field]
22
+ end
23
+ end
24
+
25
+ # Allows the testing of you to check for negative assertions:
26
+ #
27
+ # # Instead of
28
+ # assert !something_that_is_false
29
+ #
30
+ # # Do this
31
+ # assert_false something_that_should_be_false
32
+ #
33
+ # An optional +msg+ parameter is available to help you debug.
34
+ def assert_false(boolean, message = nil)
35
+ message = build_message message, '<?> is not false or nil.', boolean
36
+
37
+ clean_backtrace do
38
+ assert_block message do
39
+ not boolean
40
+ end
41
+ end
42
+ end
43
+
44
+ # A handy little assertion to check for a successful response:
45
+ #
46
+ # # Instead of
47
+ # assert_success response
48
+ #
49
+ # # DRY that up with
50
+ # assert_success response
51
+ #
52
+ # A message will automatically show the inspection of the response
53
+ # object if things go afoul.
54
+ def assert_success(response)
55
+ clean_backtrace do
56
+ assert response.success?, "Response failed: #{response.inspect}"
57
+ end
58
+ end
59
+
60
+ # The negative of +assert_success+
61
+ def assert_failure(response)
62
+ clean_backtrace do
63
+ assert_false response.success?, "Response expected to fail: #{response.inspect}"
64
+ end
65
+ end
66
+
67
+ def assert_valid(validateable)
68
+ clean_backtrace do
69
+ assert validateable.valid?, "Expected to be valid"
70
+ end
71
+ end
72
+
73
+ def assert_not_valid(validateable)
74
+ clean_backtrace do
75
+ assert_false validateable.valid?, "Expected to not be valid"
76
+ end
77
+ end
78
+
79
+ def assert_deprecation_warning(message, target)
80
+ target.expects(:deprecated).with(message)
81
+ yield
82
+ end
83
+
84
+ private
85
+ def clean_backtrace(&block)
86
+ yield
87
+ rescue AssertionClass => e
88
+ path = File.expand_path(__FILE__)
89
+ raise AssertionClass, e.message, e.backtrace.reject { |line| File.expand_path(line) =~ /#{path}/ }
90
+ end
91
+ end
92
+
93
+ module Fixtures
94
+ HOME_DIR = RUBY_PLATFORM =~ /mswin32/ ? ENV['HOMEPATH'] : ENV['HOME'] unless defined?(HOME_DIR)
95
+ LOCAL_CREDENTIALS = File.join(HOME_DIR.to_s, '.active_merchant/fixtures.yml') unless defined?(LOCAL_CREDENTIALS)
96
+ DEFAULT_CREDENTIALS = File.join(File.dirname(__FILE__), 'fixtures.yml') unless defined?(DEFAULT_CREDENTIALS)
97
+
98
+ private
99
+ def credit_card(number = '4242424242424242', options = {})
100
+ defaults = {
101
+ :number => number,
102
+ :month => 9,
103
+ :year => Time.now.year + 1,
104
+ :first_name => 'Longbob',
105
+ :last_name => 'Longsen',
106
+ :verification_value => '123',
107
+ :type => 'visa'
108
+ }.update(options)
109
+
110
+ Billing::CreditCard.new(defaults)
111
+ end
112
+
113
+ def check(options = {})
114
+ defaults = {
115
+ :name => 'Jim Smith',
116
+ :routing_number => '244183602',
117
+ :account_number => '15378535',
118
+ :account_holder_type => 'personal',
119
+ :account_type => 'checking',
120
+ :number => '1'
121
+ }.update(options)
122
+
123
+ Billing::Check.new(defaults)
124
+ end
125
+
126
+ def address(options = {})
127
+ {
128
+ :name => 'Jim Smith',
129
+ :address1 => '1234 My Street',
130
+ :address2 => 'Apt 1',
131
+ :company => 'Widgets Inc',
132
+ :city => 'Ottawa',
133
+ :state => 'ON',
134
+ :zip => 'K1C2N6',
135
+ :country => 'CA',
136
+ :phone => '(555)555-5555',
137
+ :fax => '(555)555-6666'
138
+ }.update(options)
139
+ end
140
+
141
+ def all_fixtures
142
+ @@fixtures ||= load_fixtures
143
+ end
144
+
145
+ def fixtures(key)
146
+ data = all_fixtures[key] || raise(StandardError, "No fixture data was found for '#{key}'")
147
+
148
+ data.dup
149
+ end
150
+
151
+ def load_fixtures
152
+ file = File.exists?(LOCAL_CREDENTIALS) ? LOCAL_CREDENTIALS : DEFAULT_CREDENTIALS
153
+ yaml_data = YAML.load(File.read(file))
154
+ symbolize_keys(yaml_data)
155
+
156
+ yaml_data
157
+ end
158
+
159
+ def symbolize_keys(hash)
160
+ return unless hash.is_a?(Hash)
161
+
162
+ hash.symbolize_keys!
163
+ hash.each{|k,v| symbolize_keys(v)}
164
+ end
165
+ end
166
+ end
167
+
168
+ ActiveMerchant::Billing::Base.mode = :test
169
+
170
+ Test::Unit::TestCase.class_eval do
171
+ include ActiveMerchant::Billing
172
+ include ActiveMerchant::Assertions
173
+ include ActiveMerchant::Fixtures
174
+ end
@@ -0,0 +1,195 @@
1
+ require 'test_helper'
2
+
3
+ class CreditCardMethodsTest < Test::Unit::TestCase
4
+ include ActiveMerchant::Billing::CreditCardMethods
5
+
6
+ class CreditCard
7
+ include ActiveMerchant::Billing::CreditCardMethods
8
+ end
9
+
10
+ def maestro_card_numbers
11
+ %w[
12
+ 5000000000000000 5099999999999999 5600000000000000
13
+ 5899999999999999 6000000000000000 6999999999999999
14
+ 6761999999999999 6763000000000000 5038999999999999
15
+ ]
16
+ end
17
+
18
+ def non_maestro_card_numbers
19
+ %w[
20
+ 4999999999999999 5100000000000000 5599999999999999
21
+ 5900000000000000 5999999999999999 7000000000000000
22
+ ]
23
+ end
24
+
25
+ def test_should_be_able_to_identify_valid_expiry_months
26
+ assert_false valid_month?(-1)
27
+ assert_false valid_month?(13)
28
+ assert_false valid_month?(nil)
29
+ assert_false valid_month?('')
30
+
31
+ 1.upto(12) { |m| assert valid_month?(m) }
32
+ end
33
+
34
+ def test_should_be_able_to_identify_valid_expiry_years
35
+ assert_false valid_expiry_year?(-1)
36
+ assert_false valid_expiry_year?(Time.now.year + 21)
37
+
38
+ 0.upto(20) { |n| assert valid_expiry_year?(Time.now.year + n) }
39
+ end
40
+
41
+ def test_should_be_able_to_identify_valid_start_years
42
+ assert valid_start_year?(1988)
43
+ assert valid_start_year?(2007)
44
+ assert valid_start_year?(3000)
45
+
46
+ assert_false valid_start_year?(1987)
47
+ end
48
+
49
+ def test_valid_start_year_can_handle_strings
50
+ assert valid_start_year?("2009")
51
+ end
52
+
53
+ def test_valid_month_can_handle_strings
54
+ assert valid_month?("1")
55
+ end
56
+
57
+ def test_valid_expiry_year_can_handle_strings
58
+ year = Time.now.year + 1
59
+ assert valid_expiry_year?(year.to_s)
60
+ end
61
+
62
+ def test_should_be_able_to_identify_valid_issue_numbers
63
+ assert valid_issue_number?(1)
64
+ assert valid_issue_number?(10)
65
+ assert valid_issue_number?('12')
66
+ assert valid_issue_number?(0)
67
+
68
+ assert_false valid_issue_number?(-1)
69
+ assert_false valid_issue_number?(123)
70
+ assert_false valid_issue_number?('CAT')
71
+ end
72
+
73
+ def test_should_ensure_type_from_credit_card_class_is_not_frozen
74
+ assert_false CreditCard.type?('4242424242424242').frozen?
75
+ end
76
+
77
+ def test_should_be_dankort_card_type
78
+ assert_equal 'dankort', CreditCard.type?('5019717010103742')
79
+ end
80
+
81
+ def test_should_detect_visa_dankort_as_visa
82
+ assert_equal 'visa', CreditCard.type?('4571100000000000')
83
+ end
84
+
85
+ def test_should_detect_electron_dk_as_visa
86
+ assert_equal 'visa', CreditCard.type?('4175001000000000')
87
+ end
88
+
89
+ def test_should_detect_diners_club
90
+ assert_equal 'diners_club', CreditCard.type?('36148010000000')
91
+ end
92
+
93
+ def test_should_detect_diners_club_dk
94
+ assert_equal 'diners_club', CreditCard.type?('30401000000000')
95
+ end
96
+
97
+ def test_should_detect_maestro_dk_as_maestro
98
+ assert_equal 'maestro', CreditCard.type?('6769271000000000')
99
+ end
100
+
101
+ def test_should_detect_maestro_cards
102
+ assert_equal 'maestro', CreditCard.type?('5020100000000000')
103
+
104
+ maestro_card_numbers.each { |number| assert_equal 'maestro', CreditCard.type?(number) }
105
+ non_maestro_card_numbers.each { |number| assert_not_equal 'maestro', CreditCard.type?(number) }
106
+ end
107
+
108
+ def test_should_detect_mastercard
109
+ assert_equal 'master', CreditCard.type?('6771890000000000')
110
+ assert_equal 'master', CreditCard.type?('5413031000000000')
111
+ end
112
+
113
+ def test_should_detect_forbrugsforeningen
114
+ assert_equal 'forbrugsforeningen', CreditCard.type?('6007221000000000')
115
+ end
116
+
117
+ def test_should_detect_laser_card
118
+ # 16 digits
119
+ assert_equal 'laser', CreditCard.type?('6304985028090561')
120
+
121
+ # 18 digits
122
+ assert_equal 'laser', CreditCard.type?('630498502809056151')
123
+
124
+ # 19 digits
125
+ assert_equal 'laser', CreditCard.type?('6304985028090561515')
126
+
127
+ # 17 digits
128
+ assert_not_equal 'laser', CreditCard.type?('63049850280905615')
129
+
130
+ # 15 digits
131
+ assert_not_equal 'laser', CreditCard.type?('630498502809056')
132
+
133
+ # Alternate format
134
+ assert_equal 'laser', CreditCard.type?('6706950000000000000')
135
+
136
+ # Alternate format (16 digits)
137
+ assert_equal 'laser', CreditCard.type?('6706123456789012')
138
+
139
+ # New format (16 digits)
140
+ assert_equal 'laser', CreditCard.type?('6709123456789012')
141
+
142
+ # Ulster bank (Ireland) with 12 digits
143
+ assert_equal 'laser', CreditCard.type?('677117111234')
144
+ end
145
+
146
+ def test_should_detect_when_an_argument_type_does_not_match_calculated_type
147
+ assert CreditCard.matching_type?('4175001000000000', 'visa')
148
+ assert_false CreditCard.matching_type?('4175001000000000', 'master')
149
+ end
150
+
151
+ def test_detecting_full_range_of_maestro_card_numbers
152
+ maestro = '50000000000'
153
+
154
+ assert_equal 11, maestro.length
155
+ assert_not_equal 'maestro', CreditCard.type?(maestro)
156
+
157
+ while maestro.length < 19
158
+ maestro << '0'
159
+ assert_equal 'maestro', CreditCard.type?(maestro)
160
+ end
161
+
162
+ assert_equal 19, maestro.length
163
+
164
+ maestro << '0'
165
+ assert_not_equal 'maestro', CreditCard.type?(maestro)
166
+ end
167
+
168
+ def test_matching_discover_card
169
+ assert_equal 'discover', CreditCard.type?('6011000000000000')
170
+ assert_equal 'discover', CreditCard.type?('6500000000000000')
171
+ assert_equal 'discover', CreditCard.type?('6221260000000000')
172
+ assert_equal 'discover', CreditCard.type?('6450000000000000')
173
+
174
+ assert_not_equal 'discover', CreditCard.type?('6010000000000000')
175
+ assert_not_equal 'discover', CreditCard.type?('6600000000000000')
176
+ end
177
+
178
+ def test_16_digit_maestro_uk
179
+ number = '6759000000000000'
180
+ assert_equal 16, number.length
181
+ assert_equal 'switch', CreditCard.type?(number)
182
+ end
183
+
184
+ def test_18_digit_maestro_uk
185
+ number = '675900000000000000'
186
+ assert_equal 18, number.length
187
+ assert_equal 'switch', CreditCard.type?(number)
188
+ end
189
+
190
+ def test_19_digit_maestro_uk
191
+ number = '6759000000000000000'
192
+ assert_equal 19, number.length
193
+ assert_equal 'switch', CreditCard.type?(number)
194
+ end
195
+ end