freight_kit 0.1.17 → 0.1.18

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44ddf6522da07b3f38b6fa21e2209126e5b247b3ad874c406e5b856160f7a994
4
- data.tar.gz: 35f7b97346b38dfe7dba144504797e08df4a21da0ad42c05c356dd2b6bf609b3
3
+ metadata.gz: a388e3b699bfd3954ee2505e18db4d202af11dfba48c1c64643c0331f52a4a63
4
+ data.tar.gz: db547dada7eb6f6f65980ea8004b18210cae4e90e27022d194a513c3184c56b0
5
5
  SHA512:
6
- metadata.gz: ab133a86dbe534e1c3c142d8ae800e8b94ad9e7cc6942a6d1c0f94d2425cb09082ff50d7d7e9a3b8500ae9aded131d6448f69b7bb9b586e0dd2118420208019a
7
- data.tar.gz: 82391670cf07c687dfec3abaecbbdf1c5b22c44ba96b6d0fbc0af22448c1416139ad08f3cf76b99a603a88c0a1d40cb122b0f927578bac9fab59f83d79984fde
6
+ metadata.gz: 76be478d726587dda86efd0aa86cf758daee9537f16f65dafd3227ecc128bf3915dbc1bc5eeb403b21099247629d43f5962fc35b2ced934a7f98837ac8500941
7
+ data.tar.gz: 689dbeed18ddd0929e360a9ec232cea1916dcb47575e2567092ef141b9ff67cc069d1ba28c6969692cb293e7a2932bf75f1b364feb188f9b4d1aa5de9f2ade98
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- freight_kit (0.1.15)
4
+ freight_kit (0.1.17)
5
5
  active_utils (>= 3.3.1, < 3.7.0)
6
6
  activemodel (>= 7.1, < 8.1.4)
7
7
  activesupport (>= 7.1, < 8.1.4)
@@ -39,21 +39,20 @@ GEM
39
39
  mutex_m
40
40
  securerandom (>= 0.3)
41
41
  tzinfo (~> 2.0)
42
- addressable (2.9.0)
43
- public_suffix (>= 2.0.2, < 8.0)
44
- akami (1.3.3)
45
- base64
42
+ addressable (2.8.5)
43
+ public_suffix (>= 2.0.2, < 6.0)
44
+ akami (1.3.1)
46
45
  gyoku (>= 0.4.0)
47
46
  nokogiri
48
- ast (2.4.2)
47
+ ast (2.4.3)
49
48
  base64 (0.3.0)
50
49
  benchmark (0.5.0)
51
- bigdecimal (3.3.1)
52
- builder (3.3.0)
50
+ bigdecimal (4.1.2)
51
+ builder (3.2.4)
53
52
  business_time (0.13.0)
54
53
  activesupport (>= 3.2.0)
55
54
  tzinfo
56
- concurrent-ruby (1.3.6)
55
+ concurrent-ruby (1.2.2)
57
56
  connection_pool (3.0.2)
58
57
  csv (3.3.5)
59
58
  date (3.5.1)
@@ -61,7 +60,7 @@ GEM
61
60
  drb (2.2.3)
62
61
  faker (3.8.0)
63
62
  i18n (>= 1.8.11, < 2)
64
- faraday (2.14.2)
63
+ faraday (2.14.3)
65
64
  faraday-net_http (>= 2.0, < 3.5)
66
65
  json
67
66
  logger
@@ -78,12 +77,12 @@ GEM
78
77
  mutex_m
79
78
  nkf
80
79
  rack (>= 2.0, < 4)
81
- i18n (1.14.8)
80
+ i18n (1.14.1)
82
81
  concurrent-ruby (~> 1.0)
83
- json (2.7.2)
84
- language_server-protocol (3.17.0.3)
82
+ json (2.21.1)
83
+ language_server-protocol (3.17.0.6)
85
84
  logger (1.7.0)
86
- mail (2.9.0)
85
+ mail (2.9.1)
87
86
  logger
88
87
  mini_mime (>= 0.1.1)
89
88
  net-imap
@@ -95,15 +94,13 @@ GEM
95
94
  nokogiri (~> 1)
96
95
  rake
97
96
  mini_mime (1.1.5)
98
- minitest (6.0.6)
99
- drb (~> 2.0)
100
- prism (~> 1.5)
101
- multi_xml (0.7.1)
102
- bigdecimal (~> 3.1)
97
+ mini_portile2 (2.8.4)
98
+ minitest (5.15.0)
99
+ multi_xml (0.6.0)
103
100
  mutex_m (0.3.0)
104
101
  net-http (0.9.1)
105
102
  uri (>= 0.11.1)
106
- net-imap (0.6.4)
103
+ net-imap (0.6.4.1)
107
104
  date
108
105
  net-protocol
109
106
  net-pop (0.1.2)
@@ -112,14 +109,14 @@ GEM
112
109
  timeout
113
110
  net-smtp (0.5.1)
114
111
  net-protocol
115
- nkf (0.2.0)
116
- nokogiri (1.19.3-arm64-darwin)
112
+ nkf (0.3.0)
113
+ nokogiri (1.13.10)
114
+ mini_portile2 (~> 2.8.0)
117
115
  racc (~> 1.4)
118
- nori (2.7.1)
119
- bigdecimal
116
+ nori (2.6.0)
120
117
  observer (0.1.2)
121
- parallel (1.25.1)
122
- parser (3.3.2.0)
118
+ parallel (1.28.0)
119
+ parser (3.3.12.0)
123
120
  ast (~> 2.4.1)
124
121
  racc
125
122
  pkg-config (1.6.5)
@@ -127,15 +124,15 @@ GEM
127
124
  activesupport (>= 7.1, < 8.1.4)
128
125
  csv (~> 3.3)
129
126
  prism (1.9.0)
130
- public_suffix (7.0.5)
131
- racc (1.8.1)
132
- rack (3.2.6)
127
+ public_suffix (5.0.3)
128
+ racc (1.7.1)
129
+ rack (3.0.8)
133
130
  rainbow (3.1.1)
134
131
  rake (13.4.2)
135
132
  redcarpet (3.6.0)
136
- regexp_parser (2.9.0)
137
- rexml (3.4.4)
138
- rmagick (7.0.3)
133
+ regexp_parser (2.8.1)
134
+ rexml (3.2.6)
135
+ rmagick (7.0.5)
139
136
  observer (~> 0.1)
140
137
  pkg-config (~> 1.4)
141
138
  rspec (3.12.0)
@@ -162,10 +159,11 @@ GEM
162
159
  rubocop-ast (>= 1.31.1, < 2.0)
163
160
  ruby-progressbar (~> 1.7)
164
161
  unicode-display_width (>= 2.4.0, < 3.0)
165
- rubocop-ast (1.31.3)
166
- parser (>= 3.3.1.0)
167
- rubocop-graphql (1.5.2)
168
- rubocop (>= 0.90, < 2)
162
+ rubocop-ast (1.50.0)
163
+ parser (>= 3.3.7.2)
164
+ prism (~> 1.7)
165
+ rubocop-graphql (1.5.4)
166
+ rubocop (>= 1.50, < 2)
169
167
  rubocop-next (1.0.7)
170
168
  rubocop (>= 1.56, < 1.65)
171
169
  rubocop-graphql (>= 1.4, < 1.6)
@@ -173,14 +171,14 @@ GEM
173
171
  rubocop-rake (~> 0.6.0)
174
172
  rubocop-rspec (>= 2.23.2, < 3.1.0)
175
173
  rubocop-shopify (>= 2.14, < 2.16)
176
- rubocop-rails (2.25.0)
174
+ rubocop-rails (2.25.1)
177
175
  activesupport (>= 4.2.0)
178
176
  rack (>= 1.1)
179
177
  rubocop (>= 1.33.0, < 2.0)
180
178
  rubocop-ast (>= 1.31.1, < 2.0)
181
179
  rubocop-rake (0.6.0)
182
180
  rubocop (~> 1.0)
183
- rubocop-rspec (3.0.1)
181
+ rubocop-rspec (3.0.5)
184
182
  rubocop (~> 1.61)
185
183
  rubocop-shopify (2.15.1)
186
184
  rubocop (~> 1.51)
@@ -196,32 +194,30 @@ GEM
196
194
  nori (~> 2.4)
197
195
  wasabi (>= 5.1.0, < 6)
198
196
  securerandom (0.4.1)
199
- selenium-webdriver (4.16.0)
197
+ selenium-webdriver (4.12.0)
200
198
  rexml (~> 3.2, >= 3.2.5)
201
199
  rubyzip (>= 1.2.2, < 3.0)
202
200
  websocket (~> 1.0)
203
201
  timeout (0.6.1)
204
202
  tzinfo (2.0.6)
205
203
  concurrent-ruby (~> 1.0)
206
- tzinfo-data (1.2023.3)
204
+ tzinfo-data (1.2023.4)
207
205
  tzinfo (>= 1.0.0)
208
- unicode-display_width (2.5.0)
206
+ unicode-display_width (2.6.0)
209
207
  uri (1.1.1)
210
208
  wasabi (5.1.0)
211
209
  addressable
212
210
  faraday (>= 1.9, < 3)
213
211
  nokogiri (>= 1.13.9)
214
- watir (7.3.0)
212
+ watir (7.1.0)
215
213
  regexp_parser (>= 1.2, < 3)
216
- selenium-webdriver (~> 4.2)
217
- websocket (1.2.10)
214
+ selenium-webdriver (~> 4.0)
215
+ websocket (1.2.9)
218
216
  yard (0.9.34)
219
- zeitwerk (2.6.11)
217
+ zeitwerk (2.8.2)
220
218
 
221
219
  PLATFORMS
222
220
  arm64-darwin-22
223
- arm64-darwin-23
224
- arm64-darwin-24
225
221
  arm64-darwin-25
226
222
 
227
223
  DEPENDENCIES
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.17
1
+ 0.1.18
@@ -353,21 +353,44 @@ module FreightKit
353
353
  raise NotImplementedError, "#valid_pro is not supported by #{self.class.name}."
354
354
  end
355
355
 
356
- def overlength_fee(tarrif, package)
357
- max_dimension_inches = [package.length(:inches), package.width(:inches)].max
356
+ # The package's longest horizontal dimension (length or width), as a
357
+ # Measured::Length so comparisons stay unit-agnostic.
358
+ #
359
+ # @param package [FreightKit::Package]
360
+ # @return [Measured::Length]
361
+ def longest_dimension(package)
362
+ [
363
+ Measured::Length.new(package.length(:inches), :inches),
364
+ Measured::Length.new(package.width(:inches), :inches),
365
+ ].max
366
+ end
358
367
 
359
- return 0 if max_dimension_inches < self.class.minimum_length_for_overlength_fees.convert_to(:inches).value
368
+ # @param package [FreightKit::Package]
369
+ # @return [Boolean] whether the package is long enough to incur overlength fees.
370
+ def overlength?(package) = longest_dimension(package) >= self.class.minimum_length_for_overlength_fees
360
371
 
361
- tarrif.overlength_rules.each do |overlength_rule|
362
- next if max_dimension_inches < overlength_rule[:min_length].convert_to(:inches).value
372
+ def overlength_fee(tariff, package)
373
+ overlength_rule = overlength_rule_for(tariff, package)
374
+ return 0 if overlength_rule.nil?
363
375
 
364
- if overlength_rule[:max_length].blank? ||
365
- max_dimension_inches <= overlength_rule[:max_length].convert_to(:inches).value
366
- return (package.quantity * overlength_rule[:fee_cents])
367
- end
368
- end
376
+ package.quantity * overlength_rule.fee_cents
377
+ end
378
+
379
+ # Returns the overlength rule from +tariff+ that applies to +package+, or
380
+ # +nil+ when the package is not overlength, or no configured rule covers it.
381
+ #
382
+ # This is the single source of truth for "does a rule cover this package?"
383
+ # shared by {#overlength_fee} and {#validate_packages} so the two can never
384
+ # disagree (e.g. a package quoting $0 overlength while also being treated as
385
+ # serviceable).
386
+ #
387
+ # @param tariff [FreightKit::Tariff, nil]
388
+ # @param package [FreightKit::Package]
389
+ # @return [FreightKit::Tariff::OverlengthRule, nil]
390
+ def overlength_rule_for(tariff, package)
391
+ return unless tariff.is_a?(FreightKit::Tariff) && overlength?(package)
369
392
 
370
- 0
393
+ tariff.overlength_rules.find { |overlength_rule| overlength_rule.cover?(longest_dimension(package)) }
371
394
  end
372
395
 
373
396
  # Determine whether the carrier will accept the packages based on credentials and/or tariff.
@@ -389,19 +412,30 @@ module FreightKit
389
412
  message << "items must weigh #{max_weight_pounds.to_f} lbs or less"
390
413
  end
391
414
 
392
- if self.class.overlength_fees_require_tariff? && (tariff.blank? || !tariff.is_a?(FreightKit::Tariff))
393
- missing_dimensions = packages.map do |p|
394
- [p.height(:inches), p.length(:inches), p.width(:inches)].any?(&:zero?)
395
- end.any?(true)
415
+ # Carriers that don't quote overlength fees via their API rely on the
416
+ # tariff to price them. Fail closed rather than silently under-quoting: a
417
+ # missing, empty, or non-covering tariff for an overlength package must
418
+ # make the carrier unserviceable. We key off rule *coverage* (via
419
+ # #overlength_rule_for) rather than the tariff object's mere presence,
420
+ # because a present-but-empty FreightKit::Tariff is not `blank?` and would
421
+ # otherwise slip past this check.
422
+ if self.class.overlength_fees_require_tariff?
423
+ missing_dimensions = packages.any? do |package|
424
+ [
425
+ package.height(:inches),
426
+ package.length(:inches),
427
+ package.width(:inches),
428
+ ].any?(&:zero?)
429
+ end
430
+
431
+ uncovered_overlength = packages.any? do |package|
432
+ overlength?(package) && overlength_rule_for(tariff, package).nil?
433
+ end
396
434
 
397
435
  if missing_dimensions
398
436
  message << 'item dimensions are required'
399
- else
400
- max_length_inches = self.class.minimum_length_for_overlength_fees.convert_to(:inches).value
401
-
402
- if packages.map { |p| [p.width(:inches), p.length(:inches)].max }.max >= max_length_inches
403
- message << 'tariff must be defined to calculate overlength fees'
404
- end
437
+ elsif uncovered_overlength
438
+ message << 'tariff must be defined to calculate overlength fees'
405
439
  end
406
440
  end
407
441
 
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FreightKit
4
+ class Tariff
5
+ class OverlengthRule
6
+ attr_reader :fee_cents, :max_length, :min_length
7
+
8
+ def initialize(fee_cents:, max_length:, min_length:)
9
+ raise ArgumentError, 'overlength_rule[:fee_cents] must be an Integer' unless fee_cents.is_a?(Integer)
10
+
11
+ if max_length && !max_length.is_a?(Measured::Length)
12
+ raise ArgumentError, 'overlength_rule[:max_length] must be one of Measured::Length, NilClass'
13
+ end
14
+
15
+ unless min_length.is_a?(Measured::Length)
16
+ raise ArgumentError, 'overlength_rule[:min_length] must be a Measured::Length'
17
+ end
18
+
19
+ @fee_cents = fee_cents
20
+ @max_length = max_length
21
+ @min_length = min_length
22
+ end
23
+
24
+ # @param length [Measured::Length] a package's longest dimension.
25
+ # @return [Boolean] whether this rule's length band covers the dimension.
26
+ def cover?(length)
27
+ return false if length < min_length
28
+
29
+ max_length.nil? || length <= max_length
30
+ end
31
+ end
32
+ end
33
+ end
@@ -8,22 +8,12 @@ module FreightKit
8
8
  options.symbolize_keys!
9
9
  @options = options
10
10
 
11
- @options[:overlength_rules] = (@options[:overlength_rules].presence || [])
12
- raise ArgumentError, 'overlength_rules must be an Array' unless @options[:overlength_rules].is_a?(Array)
11
+ overlength_rules = options[:overlength_rules].presence || []
12
+ raise ArgumentError, 'overlength_rules must be an Array' unless overlength_rules.is_a?(Array)
13
13
 
14
- @options[:overlength_rules].each do |overlength_rule|
15
- if !overlength_rule[:min_length].is_a?(Measured::Length)
16
- raise ArgumentError, 'overlength_rule[:min_length] must be a Measured::Length'
17
- elsif ![Measured::Length, NilClass].include?(overlength_rule[:max_length].class)
18
- raise ArgumentError, 'overlength_rule[:max_length] must be one of Measured::Length, NilClass'
19
- end
20
-
21
- unless overlength_rule[:fee_cents].is_a?(Integer)
22
- raise ArgumentError, 'overlength_rule[:fee_cents] must be an Integer'
23
- end
14
+ @overlength_rules = overlength_rules.map do |overlength_rule|
15
+ overlength_rule.is_a?(OverlengthRule) ? overlength_rule : OverlengthRule.new(**overlength_rule)
24
16
  end
25
-
26
- @overlength_rules = @options[:overlength_rules]
27
17
  end
28
18
  end
29
19
  end
metadata CHANGED
@@ -1,16 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: freight_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.17
4
+ version: 0.1.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Third Party Transportation Systems LLC
8
8
  - Brody Hoskins
9
9
  - Sub Pop Records
10
10
  - Shopify
11
+ autorequire:
11
12
  bindir: bin
12
13
  cert_chain: []
13
- date: 1980-01-02 00:00:00.000000000 Z
14
+ date: 2026-07-23 00:00:00.000000000 Z
14
15
  dependencies:
15
16
  - !ruby/object:Gem::Dependency
16
17
  name: faker
@@ -477,11 +478,13 @@ files:
477
478
  - lib/freight_kit/platforms/the_great_information_factory.rb
478
479
  - lib/freight_kit/shipment_packer.rb
479
480
  - lib/freight_kit/tariff.rb
481
+ - lib/freight_kit/tariff/overlength_rule.rb
480
482
  - service_type_symbols.txt
481
483
  - shipment_event_symbols.txt
482
484
  homepage: https://github.com/next-tms/freight_kit
483
485
  licenses: []
484
486
  metadata: {}
487
+ post_install_message:
485
488
  rdoc_options: []
486
489
  require_paths:
487
490
  - lib
@@ -496,7 +499,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
496
499
  - !ruby/object:Gem::Version
497
500
  version: '0'
498
501
  requirements: []
499
- rubygems_version: 4.0.10
502
+ rubygems_version: 3.4.10
503
+ signing_key:
500
504
  specification_version: 4
501
505
  summary: Freight carrier API and website abstraction library for transportation management
502
506
  systems (TMS)