rate-card 0.1.1 → 0.1.3
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/lib/rate_card/constants/addresses.rb +34 -0
- data/lib/rate_card/constants/carriers.rb +9 -0
- data/lib/rate_card/providers/ehub/token_prompt.rb +1 -1
- data/lib/rate_card/run_spec.rb +35 -3
- data/lib/rate_card/table_renderer.rb +1 -1
- data/lib/rate_card/tui/app.rb +63 -5
- data/lib/rate_card/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 160b23b771a6920c394ff1d8e33b625499f0bd384c8aab8453471c18d1244a23
|
|
4
|
+
data.tar.gz: c03c94b913253b5037be1f5f4d2b9b11304943712215b81bcbae092148675b84
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d11060dc015d5eaa28ab8ec883bc38b865383f22e85cccce7ea455945b304fabefa0f22c9463e0ed8bdf986fa3b3cc2d43975154d52296ed29999b518343e34a
|
|
7
|
+
data.tar.gz: 6f1649f1183ab8b1b7627b43494d9277999e22939e4492852be6827ff9694edd768bbd4ca7202bcf714b684ecc7deed9ace3d50661202a26070fdfcb0caf02a6
|
|
@@ -72,6 +72,40 @@ module RateCard
|
|
|
72
72
|
|
|
73
73
|
BY_CARRIER = { 'USPS' => USPS, 'UPS' => UPS, 'FedEx' => FEDEX, 'DHL' => DHL_ECOMMERCE, 'OSM' => OSM }.freeze
|
|
74
74
|
|
|
75
|
+
# Rural/remote-area surcharge test addresses. These aren't zone charts
|
|
76
|
+
# (rural surcharge eligibility is a property of the destination zip on
|
|
77
|
+
# a carrier's rural list, not something for_carrier's zone lookup
|
|
78
|
+
# models), so they live outside BY_CARRIER and are looked up directly
|
|
79
|
+
# by callers that need them.
|
|
80
|
+
#
|
|
81
|
+
# Ported from ../rate_table_builder/constants.rb. USPS_RURAL_DAS zones
|
|
82
|
+
# 4-8 were tagged 'maybe' or unverified in the source file - re-verify
|
|
83
|
+
# against USPS's rural lookup before relying on them for a real card.
|
|
84
|
+
USPS_RURAL_DAS = {
|
|
85
|
+
0 => { address1: '12078 W 4000 N', city: 'Bluebell', state: 'UT', postal_code: '84007', country: 'US' },
|
|
86
|
+
1 => { address1: '6074 N 4700 W', city: 'Bear River City', state: 'UT', postal_code: '84301', country: 'US' },
|
|
87
|
+
2 => { address1: '25670 Buffalo Run', city: 'Moran', state: 'WY', postal_code: '83013', country: 'US' },
|
|
88
|
+
3 => { address1: '17 Texs Loop', city: 'Alder', state: 'MT', postal_code: '59710', country: 'US' },
|
|
89
|
+
4 => { address1: '1250 153rd St SE', city: 'Norwich', state: 'ND', postal_code: '58768', country: 'US' },
|
|
90
|
+
5 => { address1: '103 Stonegate Ct', city: 'Gurdon', state: 'AR', postal_code: '71743', country: 'US' },
|
|
91
|
+
6 => { address1: '31 Edsel Rd', city: 'Webbville', state: 'KY', postal_code: '41180', country: 'US' },
|
|
92
|
+
7 => { address1: '295 Old Waterford Road', city: 'Littleton', state: 'NH', postal_code: '03561', country: 'US' },
|
|
93
|
+
8 => { address1: '77 Main Street', city: 'Mars Hill', state: 'ME', postal_code: '04758', country: 'US' }
|
|
94
|
+
}.freeze
|
|
95
|
+
|
|
96
|
+
# UPS has no per-zone rural chart - just one known address per DAS
|
|
97
|
+
# variant. EDAS = Extended Delivery Area Surcharge, RDAS = Remote
|
|
98
|
+
# Delivery Area Surcharge.
|
|
99
|
+
UPS_EDAS_EXCEPTION = { address1: '149 Pheasant Runn Road', city: 'Goshen', state: 'NH', postal_code: '03752',
|
|
100
|
+
country: 'US' }.freeze
|
|
101
|
+
|
|
102
|
+
UPS_RDAS_EXCEPTION = { address1: '106 Yellow Hammer Rd', city: 'Tyner', state: 'NC', postal_code: '27980',
|
|
103
|
+
country: 'US' }.freeze
|
|
104
|
+
|
|
105
|
+
# Looked up by surcharge-type symbol rather than zone, since UPS rural
|
|
106
|
+
# mode sweeps surcharge types instead of zones — see RunSpec#address_for.
|
|
107
|
+
UPS_RURAL = { edas: UPS_EDAS_EXCEPTION, rdas: UPS_RDAS_EXCEPTION }.freeze
|
|
108
|
+
|
|
75
109
|
module_function
|
|
76
110
|
|
|
77
111
|
# Raises rather than falling back. The old USPS default meant asking for
|
|
@@ -30,6 +30,11 @@ module RateCard
|
|
|
30
30
|
'dhl' => 'DHL Express', 'dhl_ecommerce' => 'DHL', 'osm' => 'OSM', 'amazon' => 'Amazon'
|
|
31
31
|
}.freeze
|
|
32
32
|
|
|
33
|
+
# Carriers with a rural/DAS surcharge test address in Constants::Addresses.
|
|
34
|
+
# Independent of zone-chart support - a carrier can have a verified zone
|
|
35
|
+
# chart and no rural chart at all.
|
|
36
|
+
RURAL_AWARE = %w[USPS UPS].freeze
|
|
37
|
+
|
|
33
38
|
module_function
|
|
34
39
|
|
|
35
40
|
# OTHER is only for a malformed entry with no code at all, so a service is
|
|
@@ -44,6 +49,10 @@ module RateCard
|
|
|
44
49
|
def display_order
|
|
45
50
|
DISPLAY_ORDER
|
|
46
51
|
end
|
|
52
|
+
|
|
53
|
+
def rural_aware?(carrier)
|
|
54
|
+
RURAL_AWARE.include?(carrier.to_s)
|
|
55
|
+
end
|
|
47
56
|
end
|
|
48
57
|
end
|
|
49
58
|
end
|
data/lib/rate_card/run_spec.rb
CHANGED
|
@@ -16,7 +16,7 @@ module RateCard
|
|
|
16
16
|
class RunSpec < Struct.new(
|
|
17
17
|
:token, :customer_name, :customer_id, :carrier, :services, :zones,
|
|
18
18
|
:weight_unit, :weights, :package_type, :rate_keys, :output_base,
|
|
19
|
-
:show_table, :started_at, :rate_mode, :cubic_tiers,
|
|
19
|
+
:show_table, :started_at, :rate_mode, :cubic_tiers, :rural,
|
|
20
20
|
keyword_init: true
|
|
21
21
|
)
|
|
22
22
|
# Our rate-key name => the field it arrives as in service_rates. Getting
|
|
@@ -44,10 +44,26 @@ module RateCard
|
|
|
44
44
|
self.class.compact_range(zones)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
def zone_label(zone)
|
|
48
|
+
zone.is_a?(Symbol) ? zone.to_s.upcase : "Z#{zone}"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# true for USPS with rural mode on, or any UPS surcharge type/combination.
|
|
52
|
+
# nil/false (rural mode off, or a non-rural-aware carrier) is falsy here.
|
|
53
|
+
def rural?
|
|
54
|
+
!!rural
|
|
55
|
+
end
|
|
56
|
+
|
|
47
57
|
# [1,2,3,5] => "1-3,5". Runs of three or more collapse; a pair stays listed,
|
|
48
58
|
# since "4,5" is no longer than "4-5" and reads as what the user typed.
|
|
59
|
+
#
|
|
60
|
+
# UPS rural mode sweeps surcharge-type symbols (:edas, :rdas) instead of
|
|
61
|
+
# numbered zones - those aren't a range at all, so they're just listed.
|
|
49
62
|
def self.compact_range(numbers)
|
|
50
|
-
|
|
63
|
+
array = numbers.to_a
|
|
64
|
+
return array.join(',') if array.any? { |n| n.is_a?(Symbol) }
|
|
65
|
+
|
|
66
|
+
sorted = array.sort.uniq
|
|
51
67
|
runs = sorted.slice_when { |a, b| b != a + 1 }.to_a
|
|
52
68
|
runs.map { |run| run.length >= 3 ? "#{run.first}-#{run.last}" : run.join(',') }.join(',')
|
|
53
69
|
end
|
|
@@ -104,7 +120,14 @@ module RateCard
|
|
|
104
120
|
end
|
|
105
121
|
end
|
|
106
122
|
|
|
123
|
+
# A Symbol zone (:edas, :rdas) only ever comes from UPS rural mode, so it
|
|
124
|
+
# disambiguates from a real zone number without needing to check carrier
|
|
125
|
+
# or rural separately. USPS rural mode keeps integer zones, just against
|
|
126
|
+
# the rural chart instead of the normal one.
|
|
107
127
|
def address_for(zone)
|
|
128
|
+
return Constants::Addresses::UPS_RURAL[zone] if zone.is_a?(Symbol)
|
|
129
|
+
return Constants::Addresses::USPS_RURAL_DAS[zone] if carrier == 'USPS' && rural?
|
|
130
|
+
|
|
108
131
|
Constants::Addresses.for_carrier(carrier)[zone]
|
|
109
132
|
end
|
|
110
133
|
|
|
@@ -136,7 +159,16 @@ module RateCard
|
|
|
136
159
|
end
|
|
137
160
|
|
|
138
161
|
def run_dir
|
|
139
|
-
Pathname.new(output_base).join("#{slug}_#{customer_id}_#{timestamp}")
|
|
162
|
+
Pathname.new(output_base).join("#{slug}_#{customer_id}_#{timestamp}#{rural_suffix}")
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def rural_suffix
|
|
166
|
+
case rural
|
|
167
|
+
when true then '_rural'
|
|
168
|
+
when :edas, :rdas then "_#{rural}"
|
|
169
|
+
when :both then '_edas_rdas'
|
|
170
|
+
else ''
|
|
171
|
+
end
|
|
140
172
|
end
|
|
141
173
|
|
|
142
174
|
def validate!
|
|
@@ -47,7 +47,7 @@ module RateCard
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def render(service, rate_key)
|
|
50
|
-
header = [spec.weight_label, *spec.zones.map { |zone|
|
|
50
|
+
header = [spec.weight_label, *spec.zones.map { |zone| spec.zone_label(zone) }]
|
|
51
51
|
body = rows(service, rate_key)
|
|
52
52
|
|
|
53
53
|
Lipgloss::Table.new
|
data/lib/rate_card/tui/app.rb
CHANGED
|
@@ -24,7 +24,7 @@ module RateCard
|
|
|
24
24
|
|
|
25
25
|
# No :token stage — see TokenPrompt for why it cannot live in the loop.
|
|
26
26
|
STAGES = %i[
|
|
27
|
-
loading rate_mode carrier services zones unit weights package_type
|
|
27
|
+
loading rate_mode carrier rural services zones unit weights package_type
|
|
28
28
|
rate_keys confirm fetching
|
|
29
29
|
].freeze
|
|
30
30
|
|
|
@@ -177,6 +177,7 @@ module RateCard
|
|
|
177
177
|
case stage
|
|
178
178
|
when :rate_mode then rate_mode_field
|
|
179
179
|
when :carrier then carrier_field
|
|
180
|
+
when :rural then rural_field
|
|
180
181
|
when :services then services_field
|
|
181
182
|
when :zones then zones_field
|
|
182
183
|
when :unit then unit_field
|
|
@@ -238,8 +239,43 @@ module RateCard
|
|
|
238
239
|
)
|
|
239
240
|
end
|
|
240
241
|
|
|
242
|
+
# Only USPS and UPS have a rural/DAS chart (Addresses::USPS_RURAL_DAS,
|
|
243
|
+
# Addresses::UPS_RURAL); every other carrier is decided :normal (nil)
|
|
244
|
+
# and skips this stage, same as any other single-answer stage.
|
|
245
|
+
def rural_field
|
|
246
|
+
return nil unless Constants::Carriers.rural_aware?(carrier)
|
|
247
|
+
|
|
248
|
+
choices = carrier == 'USPS' ? usps_rural_choices : ups_rural_choices
|
|
249
|
+
Fields::Select.new(label: 'Rural / DAS test mode', choices: choices,
|
|
250
|
+
selected: choices.index { |_, v| v == @answers[:rural] } || 0)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def usps_rural_choices
|
|
254
|
+
[['Normal', false], ['Rural (DAS)', true]]
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def ups_rural_choices
|
|
258
|
+
[['Normal', nil], ['EDAS', :edas], ['RDAS', :rdas], ['Both', :both]]
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# UPS rural mode has no real zone choice - each surcharge type is a
|
|
262
|
+
# single fixed address - so it's decided here as the chosen surcharge
|
|
263
|
+
# symbol(s) and the zones stage is skipped rather than asked.
|
|
264
|
+
def ups_rural_zones
|
|
265
|
+
case @answers[:rural]
|
|
266
|
+
when :edas then [:edas]
|
|
267
|
+
when :rdas then [:rdas]
|
|
268
|
+
when :both then %i[edas rdas]
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
241
272
|
def zones_field
|
|
242
|
-
|
|
273
|
+
if carrier == 'UPS' && (decided = ups_rural_zones)
|
|
274
|
+
@answers[:zones] = decided
|
|
275
|
+
return nil
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
available = usps_rural? ? Constants::Addresses::USPS_RURAL_DAS.keys.sort : Constants::Addresses.available_zones(carrier)
|
|
243
279
|
full = "#{available.first}-#{available.last}"
|
|
244
280
|
answered = @answers[:zones]
|
|
245
281
|
|
|
@@ -255,6 +291,10 @@ module RateCard
|
|
|
255
291
|
)
|
|
256
292
|
end
|
|
257
293
|
|
|
294
|
+
def usps_rural?
|
|
295
|
+
carrier == 'USPS' && @answers[:rural] == true
|
|
296
|
+
end
|
|
297
|
+
|
|
258
298
|
# Weight is fixed per cubic tier, so asking for a display unit is
|
|
259
299
|
# meaningless in cubic mode — decided as :oz (unused) and skipped.
|
|
260
300
|
def unit_field
|
|
@@ -431,6 +471,7 @@ module RateCard
|
|
|
431
471
|
weights: cubic ? [] : @answers[:weights],
|
|
432
472
|
cubic_tiers: cubic ? @answers[:weights] : [],
|
|
433
473
|
rate_mode: @answers[:rate_mode] || :weight,
|
|
474
|
+
rural: @answers[:rural],
|
|
434
475
|
package_type: @answers[:package_type],
|
|
435
476
|
rate_keys: @answers[:rate_keys],
|
|
436
477
|
output_base: @output_base,
|
|
@@ -458,14 +499,21 @@ module RateCard
|
|
|
458
499
|
# in the transcript above, but they arrived one at a time over eight
|
|
459
500
|
# screens; this is the only place they can be read against each other.
|
|
460
501
|
def recap_view
|
|
502
|
+
carrier_line = " #{Theme.bold(carrier)}#{rural_recap} · #{@answers[:services].map(&:name).join(', ')}"
|
|
461
503
|
[
|
|
462
|
-
|
|
504
|
+
carrier_line,
|
|
463
505
|
" zones #{RunSpec.compact_range(@answers[:zones])} · #{rows_recap} · #{@answers[:package_type]}",
|
|
464
506
|
" columns: #{@answers[:rate_keys].map { |k| RunSpec::RATE_KEY_LABELS.fetch(k) }.join(', ')}",
|
|
465
507
|
" #{Theme.bold(call_count.to_s)} rate calls against #{Theme.danger('production')}"
|
|
466
508
|
].join("\n")
|
|
467
509
|
end
|
|
468
510
|
|
|
511
|
+
def rural_recap
|
|
512
|
+
return '' if !@answers[:rural] || @answers[:rural].nil?
|
|
513
|
+
|
|
514
|
+
" (#{rural_label(@answers[:rural])})"
|
|
515
|
+
end
|
|
516
|
+
|
|
469
517
|
def rows_recap
|
|
470
518
|
if @answers[:rate_mode] == :cubic
|
|
471
519
|
"cubic tiers #{RunSpec.compact_range(@answers[:weights])}"
|
|
@@ -500,8 +548,8 @@ module RateCard
|
|
|
500
548
|
# transcript of the run stays on screen — the recap is then a summary of
|
|
501
549
|
# what is already visible rather than the first chance to check it.
|
|
502
550
|
def answered_line(stage, value)
|
|
503
|
-
label = { rate_mode: 'rate by', carrier: 'carrier',
|
|
504
|
-
unit: 'unit', weights: 'weights', package_type: 'package',
|
|
551
|
+
label = { rate_mode: 'rate by', carrier: 'carrier', rural: 'rural / DAS', services: 'services',
|
|
552
|
+
zones: 'zones', unit: 'unit', weights: 'weights', package_type: 'package',
|
|
505
553
|
rate_keys: 'columns' }[stage]
|
|
506
554
|
label = 'cubic tiers' if stage == :weights && @answers[:rate_mode] == :cubic
|
|
507
555
|
return nil if label.nil?
|
|
@@ -514,10 +562,20 @@ module RateCard
|
|
|
514
562
|
when :services then value.map(&:name).join(', ')
|
|
515
563
|
when :zones then RunSpec.compact_range(value)
|
|
516
564
|
when :weights then RunSpec.compact_range(value)
|
|
565
|
+
when :rural then rural_label(value)
|
|
517
566
|
when :rate_keys then value.map { |k| RunSpec::RATE_KEY_LABELS.fetch(k) }.join(', ')
|
|
518
567
|
else value.to_s
|
|
519
568
|
end
|
|
520
569
|
end
|
|
570
|
+
|
|
571
|
+
def rural_label(value)
|
|
572
|
+
case value
|
|
573
|
+
when false, nil then 'normal'
|
|
574
|
+
when true then 'rural (DAS)'
|
|
575
|
+
when :edas, :rdas then value.to_s.upcase
|
|
576
|
+
when :both then 'EDAS + RDAS'
|
|
577
|
+
end
|
|
578
|
+
end
|
|
521
579
|
end
|
|
522
580
|
end
|
|
523
581
|
end
|
data/lib/rate_card/version.rb
CHANGED