tracking_number 1.0.3 → 1.0.4
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.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/README.md +4 -3
- data/lib/tracking_number.rb +3 -62
- data/lib/tracking_number/base.rb +17 -5
- data/lib/tracking_number/checksum_validations.rb +65 -0
- data/lib/tracking_number/info.rb +8 -0
- data/lib/tracking_number/loader.rb +73 -0
- data/lib/tracking_number/version.rb +1 -1
- data/test/tracking_number_meta_test.rb +39 -40
- data/test/tracking_number_test.rb +15 -0
- metadata +9 -4
- data/lib/checksum_validations.rb +0 -63
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c982bd19b169cb2d7c3451f310d0408185e3ca3da9056dfd7f08f6d70194d9f1
|
4
|
+
data.tar.gz: ead95abd691ee8572fd295b3e8aed206b44cbb791437c8d40c90702c1e8cd5e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '086856f2923929118bd32f6e6ccd9725c0099c9d274273a9ac5ff072fb2f561460cd940d6b95506ca3ea2685b998310cba8534ef3404732353bdb8a2452094e4'
|
7
|
+
data.tar.gz: 2280018d8645ce2181819c7cc35a53e8ea857ef7e785a335ed03c6bac6b813e47f6bcb5ac6831e251e77b7f17ffc5451680fea15d69cbaec84bb753dacef3f1e
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -9,6 +9,10 @@ It detects tracking numbers from UPS, FedEx, DHL, USPS, OnTrac, Amazon Logistics
|
|
9
9
|
|
10
10
|
This gem does not do tracking. That is left up to you.
|
11
11
|
|
12
|
+
#### New in 1.0
|
13
|
+
|
14
|
+
Starting with the 1.0 release the specifications for detecting tracking numbers have been moved into a separate repository ([tracking_number_data](http://github.com/jkeen/tracking_number_data)) that this gem relies on. I did this so a) we can have a single place to document all tracking number types and it can be more of a crowdsourced effort, and b) so clients can be written in other languages easier.
|
15
|
+
|
12
16
|
## Usage
|
13
17
|
|
14
18
|
#### Checking an individual tracking number
|
@@ -119,9 +123,6 @@ class Shipment < ActiveRecord::Base
|
|
119
123
|
end
|
120
124
|
```
|
121
125
|
|
122
|
-
## Where the data comes from
|
123
|
-
Starting with the 1.0 release of this gem the data for tracking numbers has been extracted into a separate repository ([tracking_number_data](http://github.com/jkeen/tracking_number_data)) so non-ruby clients can benefit from the detection/documentation that used to be contained deep in the code of this gem. If you want to write a client in some other language, that's the stuff you want.
|
124
|
-
|
125
126
|
## Contributing to tracking_number
|
126
127
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
127
128
|
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
data/lib/tracking_number.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# Identify if tracking numbers are valid, and which service they belong to
|
2
2
|
|
3
3
|
require 'json'
|
4
|
+
require 'tracking_number/checksum_validations'
|
5
|
+
require 'tracking_number/loader'
|
4
6
|
require 'tracking_number/base'
|
5
7
|
require 'tracking_number/info'
|
6
8
|
require 'tracking_number/unknown'
|
7
|
-
require 'checksum_validations'
|
8
9
|
require 'active_support/core_ext/string'
|
9
10
|
require 'active_support/core_ext/hash'
|
10
11
|
|
@@ -12,67 +13,7 @@ if defined?(ActiveModel::EachValidator)
|
|
12
13
|
require 'tracking_number/active_model_validator'
|
13
14
|
end
|
14
15
|
|
15
|
-
|
16
|
-
return tracking[:test_numbers] && tracking[:test_numbers][:valid]
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_numbers_return_required_groups?(tracking, regex)
|
20
|
-
test_number = tracking[:test_numbers][:valid][0]
|
21
|
-
matches = test_number.match(regex)
|
22
|
-
|
23
|
-
return matches["SerialNumber"]
|
24
|
-
end
|
25
|
-
|
26
|
-
def read_courier_info(file)
|
27
|
-
return JSON.parse(File.read(file)).deep_symbolize_keys!
|
28
|
-
end
|
29
|
-
|
30
|
-
def create_class(klass, courier_info, tracking_info)
|
31
|
-
klass = Class.new(TrackingNumber::Base)
|
32
|
-
klass.const_set("COURIER_CODE", courier_info[:courier_code])
|
33
|
-
info = courier_info.dup
|
34
|
-
info.delete(:tracking_numbers)
|
35
|
-
klass.const_set("COURIER_INFO", info)
|
36
|
-
|
37
|
-
pattern = tracking_info[:regex]
|
38
|
-
pattern = tracking_info[:regex].join if tracking_info[:regex].is_a?(Array)
|
39
|
-
|
40
|
-
verify_pattern = "^#{pattern}$"
|
41
|
-
search_pattern = "\\b#{pattern}\\b"
|
42
|
-
|
43
|
-
klass.const_set("SEARCH_PATTERN", Regexp.new(search_pattern))
|
44
|
-
klass.const_set("VERIFY_PATTERN", Regexp.new(verify_pattern))
|
45
|
-
|
46
|
-
klass.const_set("VALIDATION", tracking_info[:validation])
|
47
|
-
klass.const_set("ADDITIONAL", tracking_info[:additional])
|
48
|
-
|
49
|
-
return klass
|
50
|
-
end
|
51
|
-
|
52
|
-
def register_class(klass, tracking_name)
|
53
|
-
klass_name = tracking_name.gsub(/[^0-9A-Za-z]/, '')
|
54
|
-
return TrackingNumber.const_set(klass_name, klass)
|
55
|
-
end
|
56
|
-
|
57
|
-
tracking_number_types = []
|
58
|
-
|
59
|
-
Dir.glob(File.join(File.dirname(__FILE__), "data/couriers/*.json")).each do |file|
|
60
|
-
courier_info = read_courier_info(file)
|
61
|
-
|
62
|
-
courier_info[:tracking_numbers].each do |tracking_info|
|
63
|
-
tracking_name = tracking_info[:name]
|
64
|
-
klass = create_class(klass, courier_info, tracking_info)
|
65
|
-
|
66
|
-
# Do some basic checks on the data file
|
67
|
-
throw 'missing test numbers' unless has_test_numbers?(tracking_info)
|
68
|
-
throw 'missing regex match groups' unless test_numbers_return_required_groups?(tracking_info, Regexp.new(klass::VERIFY_PATTERN))
|
69
|
-
|
70
|
-
const = register_class(klass, tracking_name)
|
71
|
-
tracking_number_types.push(const)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
TrackingNumber.const_set("TYPES", tracking_number_types)
|
16
|
+
TrackingNumber::Loader.load_tracking_number_data
|
76
17
|
|
77
18
|
module TrackingNumber
|
78
19
|
def self.search(body)
|
data/lib/tracking_number/base.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'checksum_validations'
|
2
|
-
|
3
1
|
module TrackingNumber
|
4
2
|
class Base
|
5
3
|
attr_accessor :tracking_number
|
@@ -95,7 +93,7 @@ module TrackingNumber
|
|
95
93
|
name = checksum_info[:name]
|
96
94
|
method_name = "validates_#{name}?"
|
97
95
|
|
98
|
-
ChecksumValidations.send(method_name, serial_number, check_digit, checksum_info)
|
96
|
+
TrackingNumber::ChecksumValidations.send(method_name, serial_number, check_digit, checksum_info)
|
99
97
|
end
|
100
98
|
|
101
99
|
def to_s
|
@@ -113,8 +111,7 @@ module TrackingNumber
|
|
113
111
|
:service_description => service_description,
|
114
112
|
:destination_zip => destination_zip,
|
115
113
|
:shipper_id => shipper_id,
|
116
|
-
:package_type => package_type
|
117
|
-
:package_description => package_description
|
114
|
+
:package_type => package_type
|
118
115
|
})
|
119
116
|
end
|
120
117
|
|
@@ -172,6 +169,21 @@ module TrackingNumber
|
|
172
169
|
match_group("ShipperId")
|
173
170
|
end
|
174
171
|
|
172
|
+
def tracking_url
|
173
|
+
url = nil
|
174
|
+
if matching_additional["Courier"]
|
175
|
+
url = matching_additional["Courier"][:tracking_url]
|
176
|
+
else
|
177
|
+
if self.class.const_defined?(:TRACKING_URL)
|
178
|
+
url = self.class.const_get(:TRACKING_URL)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
if url
|
183
|
+
url.sub('%s', self.tracking_number)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
175
187
|
def matching_additional
|
176
188
|
additional = self.class.const_get(:ADDITIONAL) || []
|
177
189
|
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module TrackingNumber
|
2
|
+
module ChecksumValidations
|
3
|
+
class << self
|
4
|
+
def validates_s10?(sequence, check_digit, extras = {})
|
5
|
+
weighting = [8,6,4,2,3,5,9,7]
|
6
|
+
|
7
|
+
total = 0
|
8
|
+
sequence.chars.to_a.zip(weighting).each do |(a,b)|
|
9
|
+
total += a.to_i * b.to_i
|
10
|
+
end
|
11
|
+
|
12
|
+
remainder = total % 11
|
13
|
+
check = case remainder
|
14
|
+
when 1
|
15
|
+
0
|
16
|
+
when 0
|
17
|
+
5
|
18
|
+
else
|
19
|
+
11 - remainder
|
20
|
+
end
|
21
|
+
|
22
|
+
return check.to_i == check_digit.to_i
|
23
|
+
end
|
24
|
+
|
25
|
+
def validates_sum_product_with_weightings_and_modulo?(sequence, check_digit, extras = {})
|
26
|
+
weighting = extras[:weightings] || []
|
27
|
+
|
28
|
+
total = 0
|
29
|
+
sequence.chars.to_a.zip(weighting).each do |(a,b)|
|
30
|
+
total += a.to_i * b
|
31
|
+
end
|
32
|
+
return (total % extras[:modulo1] % extras[:modulo2]) == check_digit.to_i
|
33
|
+
end
|
34
|
+
|
35
|
+
def validates_mod10?(sequence, check_digit, extras = {})
|
36
|
+
total = 0
|
37
|
+
sequence.chars.each_with_index do |c, i|
|
38
|
+
x = if c[/[0-9]/] # numeric
|
39
|
+
c.to_i
|
40
|
+
else
|
41
|
+
(c[0].ord - 3) % 10
|
42
|
+
end
|
43
|
+
|
44
|
+
if extras[:odds_multiplier] && i.odd?
|
45
|
+
x *= extras[:odds_multiplier].to_i
|
46
|
+
elsif extras[:evens_multiplier] && i.even?
|
47
|
+
x *= extras[:evens_multiplier].to_i
|
48
|
+
end
|
49
|
+
|
50
|
+
total += x
|
51
|
+
end
|
52
|
+
|
53
|
+
check = (total % 10)
|
54
|
+
check = (10 - check) unless (check.zero?)
|
55
|
+
|
56
|
+
return (check.to_i == check_digit.to_i)
|
57
|
+
end
|
58
|
+
|
59
|
+
def validates_mod7?(sequence, check_digit, extras = {})
|
60
|
+
# standard mod 7 check
|
61
|
+
return true if sequence.to_i % 7 == check_digit.to_i
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/tracking_number/info.rb
CHANGED
@@ -0,0 +1,73 @@
|
|
1
|
+
|
2
|
+
module TrackingNumber
|
3
|
+
module Loader
|
4
|
+
class << self
|
5
|
+
def load_tracking_number_data
|
6
|
+
tracking_number_types = []
|
7
|
+
|
8
|
+
Dir.glob(File.join(File.dirname(__FILE__), "../data/couriers/*.json")).each do |file|
|
9
|
+
courier_info = read_courier_info(file)
|
10
|
+
|
11
|
+
courier_info[:tracking_numbers].each do |tracking_info|
|
12
|
+
tracking_name = tracking_info[:name]
|
13
|
+
klass = create_class(klass, courier_info, tracking_info)
|
14
|
+
|
15
|
+
# Do some basic checks on the data file
|
16
|
+
throw 'missing test numbers' unless has_test_numbers?(tracking_info)
|
17
|
+
throw 'missing regex match groups' unless test_numbers_return_required_groups?(tracking_info, Regexp.new(klass::VERIFY_PATTERN))
|
18
|
+
|
19
|
+
const = register_class(klass, tracking_name)
|
20
|
+
tracking_number_types.push(const)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
TrackingNumber.const_set("TYPES", tracking_number_types)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def has_test_numbers?(tracking)
|
30
|
+
return tracking[:test_numbers] && tracking[:test_numbers][:valid]
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_numbers_return_required_groups?(tracking, regex)
|
34
|
+
test_number = tracking[:test_numbers][:valid][0]
|
35
|
+
matches = test_number.match(regex)
|
36
|
+
|
37
|
+
return matches["SerialNumber"]
|
38
|
+
end
|
39
|
+
|
40
|
+
def read_courier_info(file)
|
41
|
+
return JSON.parse(File.read(file)).deep_symbolize_keys!
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_class(klass, courier_info, tracking_info)
|
45
|
+
klass = Class.new(TrackingNumber::Base)
|
46
|
+
klass.const_set("COURIER_CODE", courier_info[:courier_code])
|
47
|
+
info = courier_info.dup
|
48
|
+
info.delete(:tracking_numbers)
|
49
|
+
klass.const_set("COURIER_INFO", info)
|
50
|
+
|
51
|
+
pattern = tracking_info[:regex]
|
52
|
+
pattern = tracking_info[:regex].join if tracking_info[:regex].is_a?(Array)
|
53
|
+
|
54
|
+
verify_pattern = "^#{pattern}$"
|
55
|
+
search_pattern = "\\b#{pattern}\\b"
|
56
|
+
|
57
|
+
klass.const_set("SEARCH_PATTERN", Regexp.new(search_pattern))
|
58
|
+
klass.const_set("VERIFY_PATTERN", Regexp.new(verify_pattern))
|
59
|
+
|
60
|
+
klass.const_set("VALIDATION", tracking_info[:validation])
|
61
|
+
klass.const_set("ADDITIONAL", tracking_info[:additional])
|
62
|
+
klass.const_set("TRACKING_URL", tracking_info[:tracking_url])
|
63
|
+
|
64
|
+
return klass
|
65
|
+
end
|
66
|
+
|
67
|
+
def register_class(klass, tracking_name)
|
68
|
+
klass_name = tracking_name.gsub(/[^0-9A-Za-z]/, '')
|
69
|
+
return TrackingNumber.const_set(klass_name, klass)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -21,13 +21,6 @@ class TrackingNumberMetaTest < Minitest::Test
|
|
21
21
|
|
22
22
|
describe "[#{tracking_info[:name]}]" do
|
23
23
|
tracking_info[:test_numbers][:valid].each do |valid_number|
|
24
|
-
|
25
|
-
should "validate #{valid_number} with #{klass_name}" do
|
26
|
-
t = klass.new(valid_number)
|
27
|
-
assert_equal courier_code, t.carrier
|
28
|
-
assert t.valid?, "should be valid"
|
29
|
-
end
|
30
|
-
|
31
24
|
should "detect #{valid_number} as #{klass_name}" do
|
32
25
|
#TODO fix this multiple matching thing
|
33
26
|
matches = TrackingNumber.search(valid_number)
|
@@ -45,47 +38,53 @@ class TrackingNumberMetaTest < Minitest::Test
|
|
45
38
|
should_detect_number_variants(valid_number, "TrackingNumber::#{klass_name}".constantize)
|
46
39
|
end
|
47
40
|
|
48
|
-
|
49
|
-
|
50
|
-
assert_equal courier_info[:courier_code].to_sym, t.courier_code
|
51
|
-
assert_equal courier_info[:courier_code].to_sym, t.courier_code
|
52
|
-
end
|
41
|
+
context "number test" do
|
42
|
+
tracking_number = klass.new(valid_number)
|
53
43
|
|
54
|
-
|
55
|
-
|
44
|
+
should "validate #{valid_number} with #{klass_name}" do
|
45
|
+
assert_equal courier_code, tracking_number.carrier
|
46
|
+
assert tracking_number.valid?, "should be valid"
|
47
|
+
end
|
56
48
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
assert_equal
|
49
|
+
should "return correct courier code on #{valid_number} when calling #courier_code" do
|
50
|
+
tracking_number = klass.new(valid_number)
|
51
|
+
assert_equal courier_info[:courier_code].to_sym, tracking_number.courier_code
|
52
|
+
assert_equal courier_info[:courier_code].to_sym,tracking_number.courier_code
|
61
53
|
end
|
62
|
-
end
|
63
54
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
55
|
+
should "return correct courier name on #{valid_number} when calling #courier_name" do
|
56
|
+
if (tracking_number.matching_additional["Courier"])
|
57
|
+
assert_equal tracking_number.matching_additional["Courier"][:courier], tracking_number.courier_name
|
58
|
+
else
|
59
|
+
assert_equal courier_name, tracking_number.courier_name
|
60
|
+
end
|
61
|
+
end
|
69
62
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
63
|
+
should "not throw an error when calling #service_type on #{valid_number}" do
|
64
|
+
service_type = tracking_number.service_type
|
65
|
+
assert service_type.is_a?(String) || service_type.nil?
|
66
|
+
end
|
74
67
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
end
|
68
|
+
should "not throw an error when calling #destination on #{valid_number}" do
|
69
|
+
assert tracking_number.destination_zip.is_a?(String) || tracking_number.destination_zip.nil?
|
70
|
+
end
|
79
71
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
72
|
+
should "not throw an error when calling #shipper on #{valid_number}" do
|
73
|
+
t = klass.new(valid_number)
|
74
|
+
assert tracking_number.shipper_id.is_a?(String) || tracking_number.shipper_id.nil?
|
75
|
+
end
|
76
|
+
|
77
|
+
should "not throw an error when calling #package_type on #{valid_number}" do
|
78
|
+
t = klass.new(valid_number)
|
79
|
+
assert tracking_number.package_type.is_a?(String) || tracking_number.package_type.nil?
|
80
|
+
end
|
81
|
+
|
82
|
+
should "not throw an error when calling #decode on #{valid_number}" do
|
83
|
+
t = klass.new(valid_number)
|
84
|
+
decode = tracking_number.decode
|
85
|
+
assert decode.is_a?(Hash)
|
86
|
+
end
|
84
87
|
|
85
|
-
should "not throw an error when calling #decode on #{valid_number}" do
|
86
|
-
t = klass.new(valid_number)
|
87
|
-
decode = t.decode
|
88
|
-
assert decode.is_a?(Hash)
|
89
88
|
end
|
90
89
|
end
|
91
90
|
|
@@ -64,6 +64,11 @@ class TrackingNumberTest < Minitest::Test
|
|
64
64
|
should "report correct no package info" do
|
65
65
|
assert_nil tracking_number.package_type
|
66
66
|
end
|
67
|
+
|
68
|
+
should "have valid tracking url" do
|
69
|
+
assert tracking_number.tracking_url, "Tracking url should not be blank"
|
70
|
+
assert tracking_number.tracking_url.include?(tracking_number.tracking_number), "Should include tracking number in the url"
|
71
|
+
end
|
67
72
|
end
|
68
73
|
|
69
74
|
context "tracking number additional data for s10" do
|
@@ -112,6 +117,11 @@ class TrackingNumberTest < Minitest::Test
|
|
112
117
|
should "report correct no package info" do
|
113
118
|
assert_nil tracking_number.package_type
|
114
119
|
end
|
120
|
+
|
121
|
+
should "have valid tracking url" do
|
122
|
+
assert tracking_number.tracking_url, "Tracking url should not be blank"
|
123
|
+
assert tracking_number.tracking_url.include?(tracking_number.tracking_number), "Should include tracking number in the url"
|
124
|
+
end
|
115
125
|
end
|
116
126
|
|
117
127
|
context "tracking number additional data for USPS 34v2" do
|
@@ -136,5 +146,10 @@ class TrackingNumberTest < Minitest::Test
|
|
136
146
|
should "report correct no package info" do
|
137
147
|
assert_nil tracking_number.package_type
|
138
148
|
end
|
149
|
+
|
150
|
+
should "have valid tracking url" do
|
151
|
+
assert tracking_number.tracking_url, "Tracking url should not be blank"
|
152
|
+
assert tracking_number.tracking_url.include?(tracking_number.tracking_number), "Should include tracking number in the url"
|
153
|
+
end
|
139
154
|
end
|
140
155
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tracking_number
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Keen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -139,7 +139,6 @@ files:
|
|
139
139
|
- LICENSE.txt
|
140
140
|
- README.md
|
141
141
|
- Rakefile
|
142
|
-
- lib/checksum_validations.rb
|
143
142
|
- lib/data/couriers/amazon.json
|
144
143
|
- lib/data/couriers/dhl.json
|
145
144
|
- lib/data/couriers/fedex.json
|
@@ -150,7 +149,9 @@ files:
|
|
150
149
|
- lib/tracking_number.rb
|
151
150
|
- lib/tracking_number/active_model_validator.rb
|
152
151
|
- lib/tracking_number/base.rb
|
152
|
+
- lib/tracking_number/checksum_validations.rb
|
153
153
|
- lib/tracking_number/info.rb
|
154
|
+
- lib/tracking_number/loader.rb
|
154
155
|
- lib/tracking_number/unknown.rb
|
155
156
|
- lib/tracking_number/version.rb
|
156
157
|
- test/active_model_validator_test.rb
|
@@ -182,4 +183,8 @@ rubygems_version: 2.7.4
|
|
182
183
|
signing_key:
|
183
184
|
specification_version: 4
|
184
185
|
summary: Identifies valid tracking numbers
|
185
|
-
test_files:
|
186
|
+
test_files:
|
187
|
+
- test/active_model_validator_test.rb
|
188
|
+
- test/test_helper.rb
|
189
|
+
- test/tracking_number_meta_test.rb
|
190
|
+
- test/tracking_number_test.rb
|
data/lib/checksum_validations.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
module ChecksumValidations
|
2
|
-
class << self
|
3
|
-
def validates_s10?(sequence, check_digit, extras = {})
|
4
|
-
weighting = [8,6,4,2,3,5,9,7]
|
5
|
-
|
6
|
-
total = 0
|
7
|
-
sequence.chars.to_a.zip(weighting).each do |(a,b)|
|
8
|
-
total += a.to_i * b.to_i
|
9
|
-
end
|
10
|
-
|
11
|
-
remainder = total % 11
|
12
|
-
check = case remainder
|
13
|
-
when 1
|
14
|
-
0
|
15
|
-
when 0
|
16
|
-
5
|
17
|
-
else
|
18
|
-
11 - remainder
|
19
|
-
end
|
20
|
-
|
21
|
-
return check.to_i == check_digit.to_i
|
22
|
-
end
|
23
|
-
|
24
|
-
def validates_sum_product_with_weightings_and_modulo?(sequence, check_digit, extras = {})
|
25
|
-
weighting = extras[:weightings] || []
|
26
|
-
|
27
|
-
total = 0
|
28
|
-
sequence.chars.to_a.zip(weighting).each do |(a,b)|
|
29
|
-
total += a.to_i * b
|
30
|
-
end
|
31
|
-
return (total % extras[:modulo1] % extras[:modulo2]) == check_digit.to_i
|
32
|
-
end
|
33
|
-
|
34
|
-
def validates_mod10?(sequence, check_digit, extras = {})
|
35
|
-
total = 0
|
36
|
-
sequence.chars.each_with_index do |c, i|
|
37
|
-
x = if c[/[0-9]/] # numeric
|
38
|
-
c.to_i
|
39
|
-
else
|
40
|
-
(c[0].ord - 3) % 10
|
41
|
-
end
|
42
|
-
|
43
|
-
if extras[:odds_multiplier] && i.odd?
|
44
|
-
x *= extras[:odds_multiplier].to_i
|
45
|
-
elsif extras[:evens_multiplier] && i.even?
|
46
|
-
x *= extras[:evens_multiplier].to_i
|
47
|
-
end
|
48
|
-
|
49
|
-
total += x
|
50
|
-
end
|
51
|
-
|
52
|
-
check = (total % 10)
|
53
|
-
check = (10 - check) unless (check.zero?)
|
54
|
-
|
55
|
-
return (check.to_i == check_digit.to_i)
|
56
|
-
end
|
57
|
-
|
58
|
-
def validates_mod7?(sequence, check_digit, extras = {})
|
59
|
-
# standard mod 7 check
|
60
|
-
return true if sequence.to_i % 7 == check_digit.to_i
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|