class ReactiveShipping::DRRQ
Constants
- JSON_HEADERS
- REACTIVE_FREIGHT_CARRIER
Public Instance Methods
available_services()
click to toggle source
# File lib/reactive_freight/carriers/drrq.rb, line 17 def available_services nil end
find_pod(tracking_number, options = {})
click to toggle source
Documents
# File lib/reactive_freight/carriers/drrq.rb, line 26 def find_pod(tracking_number, options = {}) options = @options.merge(options) parse_pod_response(tracking_number, options) end
find_rates(origin, destination, packages, options = {})
click to toggle source
Rates
# File lib/reactive_freight/carriers/drrq.rb, line 32 def find_rates(origin, destination, packages, options = {}) options = @options.merge(options) origin = Location.from(origin) destination = Location.from(destination) packages = Array(packages) request = build_rate_request(origin, destination, packages, options) parse_rate_response(origin, destination, commit(request)) end
requirements()
click to toggle source
# File lib/reactive_freight/carriers/drrq.rb, line 21 def requirements %i[username password] end
Protected Instance Methods
build_headers(action, options = {})
click to toggle source
Tracking
# File lib/reactive_freight/carriers/drrq.rb, line 46 def build_headers(action, options = {}) options = @options.merge(options) case action when :quote JSON_HEADERS.merge( { 'UserName' => options[:username], 'ApiKey' => options[:password] } ) else {} end end
build_rate_request(origin, destination, packages, options = {})
click to toggle source
Rates
# File lib/reactive_freight/carriers/drrq.rb, line 173 def build_rate_request(origin, destination, packages, options = {}) options = @options.merge(options) accessorials = [] unless options[:accessorials].blank? serviceable_accessorials?(options[:accessorials]) options[:accessorials].each do |a| unless @conf.dig(:accessorials, :unserviceable).include?(a) accessorials << { ServiceCode: @conf.dig(:accessorials, :mappable)[a] } end end end longest_dimension_ft = (packages.inject([]) { |_arr, p| [p.length(:in), p.width(:in)] }.max.ceil.to_f / 12).ceil.to_i if longest_dimension_ft >= 8 && longest_dimension_ft < 30 accessorials << { ServiceCode: "OVL#{longest_dimension_ft}" } end accessorials = accessorials.uniq.to_a items = [] packages.each do |package| items << { Name: 'Freight', FreightClass: package.freight_class.to_s, Weight: package.pounds.ceil.to_s, WeightUnits: 'lb', Width: package.width(:in).ceil, Length: package.length(:in).ceil, Height: package.height(:in).ceil, DimensionUnits: 'in', Quantity: 1, QuantityUnits: 'PLT' # Check this } end body = { Constraints: { ServiceFlags: accessorials }, Items: items, PickupEvent: { Date: DateTime.now.strftime('%m/%d/%Y %I:%M:00 %p'), LocationCode: 'PLocationCode', City: origin.to_hash[:city].upcase, State: origin.to_hash[:province].upcase, Zip: origin.to_hash[:postal_code].upcase, Country: 'USA' }, DropEvent: { Date: (DateTime.now + 5.days).strftime('%m/%d/%Y %I:%M:00 %p'), LocationCode: 'DLocationCode', City: destination.to_hash[:city].upcase, State: destination.to_hash[:province].upcase, Zip: destination.to_hash[:postal_code].upcase, Country: 'USA', MaxPriceSheet: 6, ShowInsurance: false } }.to_json request = { url: build_url(:quote), headers: build_headers(:quote, options), method: @conf.dig(:api, :methods, :quote), body: body } save_request(request) request end
build_url(action)
click to toggle source
# File lib/reactive_freight/carriers/drrq.rb, line 62 def build_url(action) "#{@conf.dig(:api, :use_ssl, action) ? 'https' : 'http'}://#{@conf.dig(:api, :domains, action)}#{@conf.dig(:api, :endpoints, action)}" end
commit(request)
click to toggle source
# File lib/reactive_freight/carriers/drrq.rb, line 66 def commit(request) url = request[:url] headers = request[:headers] method = request[:method] body = request[:body] response = case method when :post HTTParty.post(url, headers: headers, body: body) else HTTParty.get(url, headers: headers) end JSON.parse(response.body) if response&.body end
parse_document_response(type, tracking_number, url, options = {})
click to toggle source
Documents
# File lib/reactive_freight/carriers/drrq.rb, line 89 def parse_document_response(type, tracking_number, url, options = {}) options = @options.merge(options) raise ReactiveShipping::ResponseError, "API Error: #{self.class.name}: Document not found" if url.blank? path = if options[:path].blank? File.join(Dir.tmpdir, "#{self.class.name} #{tracking_number} #{type.to_s.upcase}.pdf") else options[:path] end file = File.new(path, 'w') File.open(file.path, 'wb') do |file| URI.parse(url).open do |input| file.write(input.read) end rescue OpenURI::HTTPError raise ReactiveShipping::ResponseError, "API Error: #{self.class.name}: Document not found" end unless url.end_with?('.pdf') file = Magick::ImageList.new(file.path) file.write(path) end File.exist?(path) ? path : false end
parse_pod_response(tracking_number, options = {})
click to toggle source
# File lib/reactive_freight/carriers/drrq.rb, line 117 def parse_pod_response(tracking_number, options = {}) options = @options.merge(options) browser = Watir::Browser.new(:chrome, headless: !@debug) browser.goto(build_url(:pod)) browser.text_field(name: 'UserId').set(options[:username]) browser.text_field(name: 'Password').set(options[:password]) browser.button(name: 'submitbutton').click browser .element(xpath: '//*[@id="__AppFrameBaseTable"]/tbody/tr[2]/td/div[4]') .click browser.iframes(src: '../mainframe/MainFrame.jsp?bRedirect=true') browser.iframe(name: 'AppBody').frame(id: 'Header') .text_field(name: 'filter') .set(tracking_number) browser.iframe(name: 'AppBody').frame(id: 'Header').button(value: 'Find') .click begin browser.iframe(name: 'AppBody').frame(id: 'Detail') .iframe(id: 'transportsWin') .element(xpath: '/html/body/div/table/tbody/tr[2]/td[1]/span/a[2]') .click rescue StandardError # POD not yet available raise ReactiveShipping::ResponseError, "API Error: #{self.class.name}: Document not found" end browser.iframe(name: 'AppBody').frame(id: 'Detail') .element(xpath: '/html/body/div[1]/div/div/div[1]/div[1]/div[2]/div/a[5]') .click html = browser.iframe(name: 'AppBody').frame(id: 'Detail').iframes[1] .element(xpath: '/html/body/table[3]') .html html = Nokogiri::HTML(html) browser.close url = nil html.css('tr').each do |tr| tds = tr.css('td') next if tds.size <= 1 || tds.blank? text = tds[1].text next unless text&.include?('http') url = text if url.blank? || !url.include?('hubtran') # Prefer HubTran end parse_document_response(:pod, tracking_number, url, options) end
parse_rate_response(origin, destination, response)
click to toggle source
# File lib/reactive_freight/carriers/drrq.rb, line 246 def parse_rate_response(origin, destination, response) success = true message = '' rate_estimates = [] if !response success = false message = 'API Error: Unknown response' else response.each do |response_line| next if response_line.dig('Message') # Signifies error cost = response_line.dig('Total') if cost cost = (cost.to_f * 100).to_i service = response_line.dig('Charges').map { |charges| charges.dig('Description') } service = case service when service.any?('Standard LTL Guarantee') :guaranteed when service.any?('Guaranteed LTL Service AM') :guaranteed_am when service.any?('Guaranteed LTL Service PM') :guaranteed_pm else :standard end transit_days = response_line.dig('ServiceDays').to_i rate_estimates << RateEstimate.new( origin, destination, { scac: response_line.dig('Scac'), name: response_line.dig('CarrierName') }, service, transit_days: transit_days, estimate_reference: nil, total_cost: cost, total_price: cost, currency: 'USD', with_excessive_length_fees: @conf.dig(:attributes, :rates, :with_excessive_length_fees) ) else next end end end RateResponse.new( success, message, { response: response }, rates: rate_estimates, response: response, request: last_request ) end
request_url(action)
click to toggle source
# File lib/reactive_freight/carriers/drrq.rb, line 82 def request_url(action) scheme = @conf.dig(:api, :use_ssl, action) ? 'https://' : 'http://' "#{scheme}#{@conf.dig(:api, :domain)}#{@conf.dig(:api, :endpoints, action)}" end