module USPS class PricingEngine class << self # this will have to be updated when they come out with a new notice 123! FCMI_RATE_TABLE = { letter: { 1.0 => { ca: 1.70, mx: 1.70, other: 1.70 }, 2.0 => { ca: 2.00, mx: 2.55, other: 3.40 }, 3.0 => { ca: 2.70, mx: 3.40, other: 5.10 }, 3.5 => { ca: 3.40, mx: 4.15, other: 5.75 }, }, flat: { 1.0 => { ca: 3.15, mx: 3.15, other: 3.15 }, 2.0 => { ca: 3.65, mx: 4.25, other: 4.55 }, 3.0 => { ca: 4.15, mx: 5.35, other: 5.95 }, 4.0 => { ca: 4.65, mx: 6.45, other: 7.35 }, 5.0 => { ca: 5.15, mx: 7.55, other: 8.75 }, 6.0 => { ca: 5.65, mx: 8.65, other: 10.15 }, 7.0 => { ca: 6.15, mx: 9.75, other: 11.55 }, 8.0 => { ca: 6.65, mx: 10.85, other: 12.95 }, 12.0 => { ca: 7.60, mx: 13.00, other: 15.75 }, 15.994 => { ca: 8.55, mx: 15.15, other: 18.55 }, } } FCMI_NON_MACHINABLE_SURCHARGE = 0.49 US_LETTER_RATES = { 1.0 => 0.74, 2.0 => 1.03, 3.0 => 1.32, 3.5 => 1.61 } US_FLAT_RATES = { 1.0 => 1.63, 2.0 => 1.90, 3.0 => 2.17, 4.0 => 2.44, 5.0 => 2.72, 6.0 => 3.00, 7.0 => 3.28, 8.0 => 3.56, 9.0 => 3.84, 10.0 => 4.14, 11.0 => 4.44, 12.0 => 4.74, 13.0 => 5.04 } US_STAMP_LETTER_RATES = { 1.0 => 0.74, 2.0 => 1.03, 3.0 => 1.32, 3.5 => 1.61 } US_STAMP_FLAT_RATES = { 1.0 => 1.63, 2.0 => 1.90, 3.0 => 2.17, 4.0 => 2.44, 5.0 => 2.72, 6.0 => 3.00, 7.0 => 3.28, 8.0 => 3.56, 9.0 => 3.84, 10.0 => 4.14, 11.0 => 4.44, 12.0 => 4.74, 13.0 => 5.04 } def metered_price(processing_category, weight, non_machinable = false) type = processing_category.to_sym rates = case type when :letter US_LETTER_RATES when :flat US_FLAT_RATES else raise ArgumentError, "type must be :letter or :flat" end rate = rates.find { |k, v| weight <= k }&.last raise ArgumentError, "#{weight} oz is too heavy for a #{type}" unless rate if non_machinable raise ArgumentError, "only letters can be non-machinable!" unless type == :letter rate += FCMI_NON_MACHINABLE_SURCHARGE end rate end def domestic_stamp_price(processing_category, weight, non_machinable = false) type = processing_category.to_sym rates = case type when :letter US_STAMP_LETTER_RATES when :flat US_STAMP_FLAT_RATES else raise ArgumentError, "type must be :letter or :flat" end rate = rates.find { |k, v| weight <= k }&.last raise ArgumentError, "#{weight} oz is too heavy for a #{type}" unless rate if non_machinable raise ArgumentError, "only letters can be non-machinable!" unless type == :letter rate += FCMI_NON_MACHINABLE_SURCHARGE end rate end def fcmi_price(processing_category, weight, country, non_machinable = false) type = processing_category.to_sym rates = FCMI_RATE_TABLE[type] raise ArgumentError, "idk the rates for #{type}..." unless rates country = case country when "CA" :ca when "MX" :mx else :other end rate = rates.find { |k, v| weight <= k }&.dig(1) raise "#{weight} oz is too heavy for an FCMI #{type}" unless rate price = rate[country] if non_machinable raise ArgumentError, "only letters can be nonmachinable!" unless type == :letter price += FCMI_NON_MACHINABLE_SURCHARGE end price end def stamp_price(processing_category, weight, country, non_machinable = false) if country == "US" domestic_stamp_price(processing_category, weight, non_machinable) else fcmi_price(processing_category, weight, country, non_machinable) end end end end end