credit_officer 0.1.0 → 0.2.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.
- data/README.rdoc +26 -3
- data/VERSION +1 -1
- data/credit_officer.gemspec +109 -0
- data/lib/credit_officer/credit_card.rb +37 -5
- data/spec/credit_officer/credit_card_spec.rb +53 -2
- data/spec/support/factories.rb +0 -1
- metadata +4 -3
data/README.rdoc
CHANGED
@@ -11,7 +11,7 @@ Use this library so that you can validate credit card information before sending
|
|
11
11
|
Checks credit card number formats, checksums, and other required details. Supports i18n for better message
|
12
12
|
customization
|
13
13
|
|
14
|
-
cc = CreditOfficer::CreditCard.new(
|
14
|
+
cc = CreditOfficer::CreditCard.new({
|
15
15
|
:number => "411111111111111",
|
16
16
|
:provider_name => "visa",
|
17
17
|
:name_on_card => "John Doe",
|
@@ -29,7 +29,7 @@ customization
|
|
29
29
|
If you want to turn requiring verification values off, make it so:
|
30
30
|
|
31
31
|
CreditOfficer::CreditCard.require_verification_value = false
|
32
|
-
cc = CreditOfficer::CreditCard.new(
|
32
|
+
cc = CreditOfficer::CreditCard.new({
|
33
33
|
:number => "411111111111111",
|
34
34
|
:provider_name => "visa",
|
35
35
|
:name_on_card => "John Doe",
|
@@ -48,7 +48,7 @@ Want to only support certain credit cards and card number formats? Make it so:
|
|
48
48
|
'amex'
|
49
49
|
]
|
50
50
|
|
51
|
-
cc = CreditOfficer::CreditCard.new(
|
51
|
+
cc = CreditOfficer::CreditCard.new({
|
52
52
|
:number => "411111111111111",
|
53
53
|
:provider_name => "visa",
|
54
54
|
:name_on_card => "John Doe",
|
@@ -57,6 +57,29 @@ Want to only support certain credit cards and card number formats? Make it so:
|
|
57
57
|
:verification_value => ""
|
58
58
|
}).valid? => false
|
59
59
|
|
60
|
+
== Deriving provider names
|
61
|
+
|
62
|
+
Most of the time, you can derive the credit card provider (Mastercard, AMEX, Visa, etc) based on the format
|
63
|
+
of the card number. By default, credit officer attempts to derive this provider name automatically
|
64
|
+
|
65
|
+
cc = CreditOfficer::CreditCard.new({
|
66
|
+
:number => "411111111111111",
|
67
|
+
:name_on_card => "John Doe",
|
68
|
+
:expiration_year => 2010,
|
69
|
+
:expiration_month => 1,
|
70
|
+
}).valid? => true
|
71
|
+
|
72
|
+
cc.provider_name => visa
|
73
|
+
|
74
|
+
|
75
|
+
You can toggle this so that the user must provide a valid provider name like so:
|
76
|
+
|
77
|
+
CreditOfficer::CreditCard.automatically_derive_provider_name = false
|
78
|
+
|
79
|
+
You can manually attempt the provider name like so (this will set the provider name according to your number):
|
80
|
+
|
81
|
+
cc.derive_provider_name
|
82
|
+
|
60
83
|
== i18n
|
61
84
|
|
62
85
|
Error messages can be customized with i18n translations
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{credit_officer}
|
8
|
+
s.version = "0.2.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Dan Pickett"]
|
12
|
+
s.date = %q{2010-12-22}
|
13
|
+
s.description = %q{An upgrade/port of ActiveMerchant's credit card class}
|
14
|
+
s.email = %q{dpickett@enlightsolutions.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
".rvmrc",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE.txt",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"credit_officer.gemspec",
|
30
|
+
"lib/credit_officer.rb",
|
31
|
+
"lib/credit_officer/base.rb",
|
32
|
+
"lib/credit_officer/credit_card.rb",
|
33
|
+
"lib/credit_officer/month_year_pair.rb",
|
34
|
+
"spec/credit_officer/base_spec.rb",
|
35
|
+
"spec/credit_officer/credit_card_spec.rb",
|
36
|
+
"spec/credit_officer/month_year_pair_spec.rb",
|
37
|
+
"spec/credit_officer_spec.rb",
|
38
|
+
"spec/spec_helper.rb",
|
39
|
+
"spec/support/active_model_shared_examples.rb",
|
40
|
+
"spec/support/factories.rb"
|
41
|
+
]
|
42
|
+
s.homepage = %q{http://github.com/dpickett/credit_officer}
|
43
|
+
s.licenses = ["MIT"]
|
44
|
+
s.require_paths = ["lib"]
|
45
|
+
s.rubygems_version = %q{1.3.7}
|
46
|
+
s.summary = %q{An activemodel compliant credit card validator}
|
47
|
+
s.test_files = [
|
48
|
+
"spec/credit_officer/base_spec.rb",
|
49
|
+
"spec/credit_officer/credit_card_spec.rb",
|
50
|
+
"spec/credit_officer/month_year_pair_spec.rb",
|
51
|
+
"spec/credit_officer_spec.rb",
|
52
|
+
"spec/spec_helper.rb",
|
53
|
+
"spec/support/active_model_shared_examples.rb",
|
54
|
+
"spec/support/factories.rb"
|
55
|
+
]
|
56
|
+
|
57
|
+
if s.respond_to? :specification_version then
|
58
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
59
|
+
s.specification_version = 3
|
60
|
+
|
61
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
62
|
+
s.add_runtime_dependency(%q<activemodel>, [">= 3.0.3"])
|
63
|
+
s.add_runtime_dependency(%q<luhney_bin>, [">= 0"])
|
64
|
+
s.add_development_dependency(%q<timecop>, ["= 0.3.5"])
|
65
|
+
s.add_development_dependency(%q<ruby-debug>, [">= 0"])
|
66
|
+
s.add_development_dependency(%q<factory_girl>, [">= 0"])
|
67
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
|
68
|
+
s.add_development_dependency(%q<remarkable_activemodel>, [">= 4.0.0.alpha4"])
|
69
|
+
s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
|
70
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
71
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
|
72
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
73
|
+
s.add_development_dependency(%q<reek>, ["~> 1.2.8"])
|
74
|
+
s.add_development_dependency(%q<roodi>, ["~> 2.1.0"])
|
75
|
+
s.add_development_dependency(%q<fuubar>, [">= 0"])
|
76
|
+
else
|
77
|
+
s.add_dependency(%q<activemodel>, [">= 3.0.3"])
|
78
|
+
s.add_dependency(%q<luhney_bin>, [">= 0"])
|
79
|
+
s.add_dependency(%q<timecop>, ["= 0.3.5"])
|
80
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
81
|
+
s.add_dependency(%q<factory_girl>, [">= 0"])
|
82
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
83
|
+
s.add_dependency(%q<remarkable_activemodel>, [">= 4.0.0.alpha4"])
|
84
|
+
s.add_dependency(%q<yard>, ["~> 0.6.0"])
|
85
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
86
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
87
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
88
|
+
s.add_dependency(%q<reek>, ["~> 1.2.8"])
|
89
|
+
s.add_dependency(%q<roodi>, ["~> 2.1.0"])
|
90
|
+
s.add_dependency(%q<fuubar>, [">= 0"])
|
91
|
+
end
|
92
|
+
else
|
93
|
+
s.add_dependency(%q<activemodel>, [">= 3.0.3"])
|
94
|
+
s.add_dependency(%q<luhney_bin>, [">= 0"])
|
95
|
+
s.add_dependency(%q<timecop>, ["= 0.3.5"])
|
96
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
97
|
+
s.add_dependency(%q<factory_girl>, [">= 0"])
|
98
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
99
|
+
s.add_dependency(%q<remarkable_activemodel>, [">= 4.0.0.alpha4"])
|
100
|
+
s.add_dependency(%q<yard>, ["~> 0.6.0"])
|
101
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
102
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
103
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
104
|
+
s.add_dependency(%q<reek>, ["~> 1.2.8"])
|
105
|
+
s.add_dependency(%q<roodi>, ["~> 2.1.0"])
|
106
|
+
s.add_dependency(%q<fuubar>, [">= 0"])
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
@@ -11,7 +11,7 @@ module CreditOfficer
|
|
11
11
|
#store this private information
|
12
12
|
#
|
13
13
|
#@example
|
14
|
-
# cc = CreditOfficer::CreditCard.new(
|
14
|
+
# cc = CreditOfficer::CreditCard.new({
|
15
15
|
# :number => "411111111111111",
|
16
16
|
# :provider_name => "visa",
|
17
17
|
# :name_on_card => "John Doe",
|
@@ -91,7 +91,8 @@ module CreditOfficer
|
|
91
91
|
|
92
92
|
validate :expiration_date_is_in_future
|
93
93
|
validate :expiration_date_is_in_recent_future
|
94
|
-
validate :number_is_valid
|
94
|
+
validate :number_is_valid
|
95
|
+
|
95
96
|
validate :provider_name_is_supported
|
96
97
|
|
97
98
|
#SOLO or Switch validations
|
@@ -107,9 +108,17 @@ module CreditOfficer
|
|
107
108
|
validate :start_date_is_in_the_past,
|
108
109
|
:if => proc{|cc| cc.switch_or_solo? }
|
109
110
|
|
110
|
-
#set this flag accordingly to enable/disable validating verification codes
|
111
|
+
#set this flag accordingly to enable/disable validating verification codes
|
112
|
+
#(CVV/CVV2)
|
113
|
+
#@note defaults to true
|
111
114
|
cattr_accessor :require_verification_value
|
112
115
|
self.require_verification_value = true
|
116
|
+
|
117
|
+
#set this flag accordingly if you want CreditOfficer to attempt to derive
|
118
|
+
#the provider name before validation takes place
|
119
|
+
#@note defaults to true
|
120
|
+
cattr_accessor :automatically_derive_provider_name
|
121
|
+
self.automatically_derive_provider_name = true
|
113
122
|
|
114
123
|
#checks the configuration setting require_verification_value to see if
|
115
124
|
#verification is required
|
@@ -161,7 +170,27 @@ module CreditOfficer
|
|
161
170
|
SWITCH_OR_SOLO_PROVIDERS.include?(provider_name)
|
162
171
|
end
|
163
172
|
|
173
|
+
def derive_provider_name
|
174
|
+
self.class.supported_providers_and_formats.each do |name, format|
|
175
|
+
if number =~ format
|
176
|
+
self.provider_name = name
|
177
|
+
return
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def masked_number
|
183
|
+
if number.present? && number.size >= 4
|
184
|
+
"X" * (number.size - 4) + number[-4..-1]
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
164
188
|
protected
|
189
|
+
def run_validations!
|
190
|
+
derive_provider_name if self.class.automatically_derive_provider_name
|
191
|
+
super
|
192
|
+
end
|
193
|
+
|
165
194
|
I18N_ERROR_SCOPE = [:credit_officer, :errors, :messages]
|
166
195
|
|
167
196
|
def expiration_date_is_in_future
|
@@ -182,7 +211,8 @@ module CreditOfficer
|
|
182
211
|
end
|
183
212
|
|
184
213
|
def number_is_valid
|
185
|
-
if provider_name.present?
|
214
|
+
if (provider_name.present? || self.class.automatically_derive_provider_name) &&
|
215
|
+
number.present?
|
186
216
|
if self.class.supported_providers_and_formats[provider_name].nil? ||
|
187
217
|
!(number =~ self.class.supported_providers_and_formats[provider_name]) ||
|
188
218
|
!checksum_valid?
|
@@ -195,7 +225,9 @@ module CreditOfficer
|
|
195
225
|
end
|
196
226
|
|
197
227
|
def provider_name_is_supported
|
198
|
-
|
228
|
+
if !self.class.automatically_derive_provider_name &&
|
229
|
+
!self.class.supported_providers.include?(provider_name.try(:downcase))
|
230
|
+
|
199
231
|
errors.add(:provider_name, translate(:unsupported_provider,
|
200
232
|
:scope => I18N_ERROR_SCOPE,
|
201
233
|
:default => "is not supported"))
|
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe CreditOfficer::CreditCard do
|
4
|
+
TEST_AMEX = "378282246310005"
|
5
|
+
TEST_MASTER = "5555555555554444"
|
6
|
+
|
4
7
|
subject { Factory.build(:credit_card) }
|
5
8
|
it_should_behave_like "ActiveModel"
|
6
9
|
|
@@ -65,14 +68,14 @@ describe CreditOfficer::CreditCard do
|
|
65
68
|
old_supported_providers = subject.class.supported_providers.dup
|
66
69
|
subject.class.supported_providers = ['master']
|
67
70
|
subject.should_not be_valid
|
68
|
-
subject.errors[:
|
71
|
+
subject.errors[:number].should_not be_blank
|
69
72
|
|
70
73
|
#reset supported providers
|
71
74
|
subject.class.supported_providers = old_supported_providers
|
72
75
|
end
|
73
76
|
|
74
77
|
it "rejects a provider that is not in the whitelist" do
|
75
|
-
old_supported_providers = subject.class.supported_providers
|
78
|
+
old_supported_providers = subject.class.supported_providers.dup
|
76
79
|
subject.class.supported_providers = ["gaga", "ohlala"]
|
77
80
|
subject.class.supported_providers.should be_empty
|
78
81
|
|
@@ -124,4 +127,52 @@ describe CreditOfficer::CreditCard do
|
|
124
127
|
subject.errors[:start_year].should_not be_blank
|
125
128
|
end
|
126
129
|
end
|
130
|
+
|
131
|
+
it "reveals the last 4 digits in your masked card number" do
|
132
|
+
subject.masked_number.should =~ /#{subject.number[-4..-1]}$/
|
133
|
+
end
|
134
|
+
|
135
|
+
it "obfuscates all the digits except the last for in your masked card numbers" do
|
136
|
+
subject.masked_number.should =~ /^#{"X" * (subject.number.size - 4)}/
|
137
|
+
end
|
138
|
+
|
139
|
+
it "returns a nil masked number if I don't have more than 4 digits in my credit card number" do
|
140
|
+
subject.number = ""
|
141
|
+
subject.masked_number.should be_nil
|
142
|
+
end
|
143
|
+
|
144
|
+
context "deriving provider name" do
|
145
|
+
it "derives visa from a visa formatted card number" do
|
146
|
+
subject.provider_name = ""
|
147
|
+
subject.derive_provider_name
|
148
|
+
subject.provider_name.should eql("visa")
|
149
|
+
end
|
150
|
+
|
151
|
+
it "derives master from a mastercard formatted number" do
|
152
|
+
subject.provider_name = ""
|
153
|
+
subject.number = TEST_MASTER
|
154
|
+
subject.derive_provider_name
|
155
|
+
subject.provider_name.should eql('master')
|
156
|
+
end
|
157
|
+
|
158
|
+
it "derives american express from an amex formatted number" do
|
159
|
+
subject.provider_name = ""
|
160
|
+
subject.number = TEST_AMEX
|
161
|
+
subject.derive_provider_name
|
162
|
+
subject.provider_name.should eql('american_express')
|
163
|
+
end
|
164
|
+
|
165
|
+
it "does not validate the provider name if provider name derivation is on" do
|
166
|
+
subject.provider_name = ""
|
167
|
+
subject.number = TEST_AMEX
|
168
|
+
subject.should be_valid
|
169
|
+
subject.provider_name.should eql('american_express')
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should not set an error on provider name if the credit card number is invalid" do
|
173
|
+
subject.number = "fasdfas"
|
174
|
+
subject.should_not be_valid
|
175
|
+
subject.errors[:provider_name].should be_blank
|
176
|
+
end
|
177
|
+
end
|
127
178
|
end
|
data/spec/support/factories.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: credit_officer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 2
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Dan Pickett
|
@@ -252,6 +252,7 @@ files:
|
|
252
252
|
- README.rdoc
|
253
253
|
- Rakefile
|
254
254
|
- VERSION
|
255
|
+
- credit_officer.gemspec
|
255
256
|
- lib/credit_officer.rb
|
256
257
|
- lib/credit_officer/base.rb
|
257
258
|
- lib/credit_officer/credit_card.rb
|