Module: Heatwave::TrackingNumber::Checksums
- Defined in:
- app/lib/heatwave/tracking_number/checksums.rb
Overview
Check-digit algorithms used by the owned courier JSON.
Ported from tracking_number 2.4.0 so existing barcode fixtures keep
the same pass/fail behaviour. Do not "clean up" the arithmetic without
re-checking every JSON test_numbers entry.
Constant Summary collapse
- MOD_37_36_LETTERS =
Letter values for ISO/IEC 7064 Mod 37,36.
{ A: 10, B: 11, C: 12, D: 13, E: 14, F: 15, G: 16, H: 17, I: 18, J: 19, K: 20, L: 21, M: 22, N: 23, O: 24, P: 25, Q: 26, R: 27, S: 28, T: 29, U: 30, V: 31, W: 32, X: 33, Y: 34, Z: 35 }.freeze
Class Method Summary collapse
- .mod10_value(char, index, extras) ⇒ Integer
- .mod_37_36_encode(check) ⇒ String
- .mod_37_36_step(check, char) ⇒ Integer
-
.valid?(name, sequence, check_digit, extras = {}) ⇒ Boolean
Dispatch a JSON
validation.checksum.nameto the matching algorithm. - .validates_luhn?(sequence, check_digit, _extras = {}) ⇒ Boolean
- .validates_mod10?(sequence, check_digit, extras = {}) ⇒ Boolean
- .validates_mod7?(sequence, check_digit, _extras = {}) ⇒ Boolean
- .validates_mod_37_36?(sequence, check_digit, _extras = {}) ⇒ Boolean
- .validates_s10?(sequence, check_digit, _extras = {}) ⇒ Boolean
- .validates_sum_product_with_weightings_and_modulo?(sequence, check_digit, extras = {}) ⇒ Boolean
Class Method Details
.mod10_value(char, index, extras) ⇒ Integer
97 98 99 100 101 102 103 104 105 106 |
# File 'app/lib/heatwave/tracking_number/checksums.rb', line 97 def mod10_value(char, index, extras) value = char.match?(/[0-9]/) ? char.to_i : ((char.ord - 3) % 10) if extras[:odds_multiplier] && index.odd? value * extras[:odds_multiplier].to_i elsif extras[:evens_multiplier] && index.even? value * extras[:evens_multiplier].to_i else value end end |
.mod_37_36_encode(check) ⇒ String
121 122 123 124 125 |
# File 'app/lib/heatwave/tracking_number/checksums.rb', line 121 def mod_37_36_encode(check) return check.to_s if check < 10 MOD_37_36_LETTERS.find { |_letter, value| value == check }[0].to_s end |
.mod_37_36_step(check, char) ⇒ Integer
111 112 113 114 115 116 117 |
# File 'app/lib/heatwave/tracking_number/checksums.rb', line 111 def mod_37_36_step(check, char) value = char.match?(/[A-Za-z]/) ? MOD_37_36_LETTERS[char.to_sym] : char.to_i check += value check -= 36 if check > 36 check *= 2 check > 36 ? check - 37 : check end |
.valid?(name, sequence, check_digit, extras = {}) ⇒ Boolean
Dispatch a JSON validation.checksum.name to the matching algorithm.
28 29 30 31 32 33 |
# File 'app/lib/heatwave/tracking_number/checksums.rb', line 28 def valid?(name, sequence, check_digit, extras = {}) method = "validates_#{name}?" raise ArgumentError, "unknown checksum #{name.inspect}" unless respond_to?(method, true) public_send(method, sequence, check_digit, extras || {}) end |
.validates_luhn?(sequence, check_digit, _extras = {}) ⇒ Boolean
131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'app/lib/heatwave/tracking_number/checksums.rb', line 131 def validates_luhn?(sequence, check_digit, _extras = {}) total = 0 sequence.chars.reverse.each_with_index do |char, index| value = char.to_i value *= 2 if index.even? value -= 9 if value > 9 total += value end check = total % 10 check = (10 - check) unless check.zero? check.to_i == check_digit.to_i end |
.validates_mod10?(sequence, check_digit, extras = {}) ⇒ Boolean
65 66 67 68 69 70 71 |
# File 'app/lib/heatwave/tracking_number/checksums.rb', line 65 def validates_mod10?(sequence, check_digit, extras = {}) characters = extras[:reverse] ? sequence.chars.reverse : sequence.chars total = characters.each_with_index.sum { |char, index| mod10_value(char, index, extras) } check = total % 10 check = (10 - check) unless check.zero? check.to_i == check_digit.to_i end |
.validates_mod7?(sequence, check_digit, _extras = {}) ⇒ Boolean
77 78 79 |
# File 'app/lib/heatwave/tracking_number/checksums.rb', line 77 def validates_mod7?(sequence, check_digit, _extras = {}) sequence.to_i % 7 == check_digit.to_i end |
.validates_mod_37_36?(sequence, check_digit, _extras = {}) ⇒ Boolean
85 86 87 88 89 90 91 |
# File 'app/lib/heatwave/tracking_number/checksums.rb', line 85 def validates_mod_37_36?(sequence, check_digit, _extras = {}) check = 36 sequence.chars.each { |char| check = mod_37_36_step(check, char) } check = 37 - check check = 0 if check == 36 mod_37_36_encode(check) == check_digit end |
.validates_s10?(sequence, check_digit, _extras = {}) ⇒ Boolean
39 40 41 42 43 44 45 46 47 48 49 |
# File 'app/lib/heatwave/tracking_number/checksums.rb', line 39 def validates_s10?(sequence, check_digit, _extras = {}) weighting = [8, 6, 4, 2, 3, 5, 9, 7] total = sequence.chars.zip(weighting).sum { |char, weight| char.to_i * weight.to_i } remainder = total % 11 check = case remainder when 1 then 0 when 0 then 5 else 11 - remainder end check.to_i == check_digit.to_i end |
.validates_sum_product_with_weightings_and_modulo?(sequence, check_digit, extras = {}) ⇒ Boolean
55 56 57 58 59 |
# File 'app/lib/heatwave/tracking_number/checksums.rb', line 55 def validates_sum_product_with_weightings_and_modulo?(sequence, check_digit, extras = {}) weighting = extras[:weightings] || [] total = sequence.chars.zip(weighting).sum { |char, weight| char.to_i * weight } (total % extras[:modulo1] % extras[:modulo2]) == check_digit.to_i end |