class ReactiveShipping::RDFS
Constants
- REACTIVE_FREIGHT_CARRIER
Public Instance Methods
find_bol(tracking_number, options = {})
click to toggle source
Documents
# File lib/reactive_freight/carriers/rdfs.rb, line 16 def find_bol(tracking_number, options = {}) options = @options.merge(options) parse_document_response(:bol, tracking_number, options) end
find_pod(tracking_number, options = {})
click to toggle source
# File lib/reactive_freight/carriers/rdfs.rb, line 21 def find_pod(tracking_number, options = {}) options = @options.merge(options) parse_document_response(:pod, tracking_number, options) end
find_rates(origin, destination, packages, options = {})
click to toggle source
Rates
# File lib/reactive_freight/carriers/rdfs.rb, line 27 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_soap(:rates, request)) end
find_tracking_info(tracking_number)
click to toggle source
Tracking
# File lib/reactive_freight/carriers/rdfs.rb, line 38 def find_tracking_info(tracking_number) tracking_request = build_tracking_request(tracking_number) parse_tracking_response(tracking_request) end
requirements()
click to toggle source
# File lib/reactive_freight/carriers/rdfs.rb, line 11 def requirements %i[username password account] end
Protected Instance Methods
build_rate_request(origin, destination, packages, options = {})
click to toggle source
Rates
# File lib/reactive_freight/carriers/rdfs.rb, line 106 def build_rate_request(origin, destination, packages, options = {}) options = @options.merge(options) service_deliveryoptions = [ serviceoptions: { service_code: 'SS' } ] unless options[:accessorials].blank? serviceable_accessorials?(options[:accessorials]) options[:accessorials].each do |a| unless @conf.dig(:accessorials, :unserviceable).include?(a) service_deliveryoptions << { serviceoptions: { service_code: @conf.dig(:accessorials, :mappable)[a] } } end end end longest_dimension = packages.inject([]) { |_arr, p| [p.length(:in), p.width(:in)] }.max.ceil if longest_dimension > 144 service_deliveryoptions << { serviceoptions: { service_code: 'EXL' } } elsif longest_dimension > 96 service_deliveryoptions << { serviceoptions: { service_code: 'EXM' } } end service_deliveryoptions = service_deliveryoptions.uniq.to_a request = { 'request' => { origin_zip: origin.to_hash[:postal_code].to_s, destination_zip: destination.to_hash[:postal_code].to_s, shipment_details: { shipment_detail: packages.inject([]) do |arr, package| arr << { 'ActualClass' => package.freight_class, 'Weight' => package.pounds.ceil } end }, service_deliveryoptions: service_deliveryoptions, origin_type: options[:origin_type] || 'B', # O for shipper, I for consignee, B for third party payment_type: options[:payment_type] || 'P', # Prepaid pallet_count: packages.size, # :linear_feet => linear_ft(packages), pieces: packages.size, account: options[:account] } } save_request(request) request end
build_soap_header(action)
click to toggle source
# File lib/reactive_freight/carriers/rdfs.rb, line 45 def build_soap_header(action) { authentication_header: { :@xmlns => @conf.dig(:api, :soap, :namespaces, action), :user_name => @options[:username], :password => @options[:password] } } end
build_tracking_request(tracking_number)
click to toggle source
Tracking
# File lib/reactive_freight/carriers/rdfs.rb, line 215 def build_tracking_request(tracking_number) URI.parse("#{request_url(:track)}/#{tracking_number}").open end
commit_soap(action, request)
click to toggle source
# File lib/reactive_freight/carriers/rdfs.rb, line 55 def commit_soap(action, request) Savon.client( wsdl: request_url(action), convert_request_keys_to: :camelcase, env_namespace: :soap, element_form_default: :qualified ).call( @conf.dig(:api, :actions, action), soap_header: build_soap_header(action), message: request ).body.to_json end
parse_date(date)
click to toggle source
# File lib/reactive_freight/carriers/rdfs.rb, line 68 def parse_date(date) date ? DateTime.strptime(date, '%Y-%m-%dT%H:%M:%S').to_s(:db) : nil end
parse_document_response(type, tracking_number, options = {})
click to toggle source
Documents
# File lib/reactive_freight/carriers/rdfs.rb, line 82 def parse_document_response(type, tracking_number, options = {}) url = request_url(type).sub('%%TRACKING_NUMBER%%', tracking_number.to_s) begin doc = Nokogiri::HTML(URI.parse(url).open) rescue OpenURI::HTTPError raise ReactiveShipping::ResponseError, "API Error: #{@@name}: Document not found" end data = Base64.decode64(doc.css('img').first['src'].split('data:image/jpg;base64,').last) path = if options[:path].blank? File.join(Dir.tmpdir, "#{@@name} #{tracking_number} #{type.to_s.upcase}.pdf") else options[:path] end file = Tempfile.new file.write(data) file = Magick::ImageList.new(file.path) file.write(path) File.exist?(path) ? path : false end
parse_location(comment, delimiters)
click to toggle source
# File lib/reactive_freight/carriers/rdfs.rb, line 219 def parse_location(comment, delimiters) city = comment.split(delimiters[0])[0].split(delimiters[1])[1].split(', ')[0].titleize state = comment.split(delimiters[0])[0].split(delimiters[1])[1].split(', ')[1].upcase Location.new( city: city, province: state, state: state, country: ActiveUtils::Country.find('USA') ) end
parse_rate_response(origin, destination, response)
click to toggle source
# File lib/reactive_freight/carriers/rdfs.rb, line 157 def parse_rate_response(origin, destination, response) success = true message = '' if !response success = false message = 'API Error: Unknown response' else response = JSON.parse(response) if response[:error] success = false message = response[:error] else cost = response.dig('rate_quote_by_account_response', 'rate_quote_by_account_result', 'net_charge') transit_days = response.dig( 'rate_quote_by_account_response', 'rate_quote_by_account_result', 'routing_info', 'estimated_transit_days' ).to_i estimate_reference = response.dig( 'rate_quote_by_account_response', 'rate_quote_by_account_result', 'quote_number' ) if cost rate_estimates = [ RateEstimate.new( origin, destination, { scac: self.class.scac.upcase, name: self.class.name }, :standard, transit_days: transit_days, estimate_reference: estimate_reference, total_cost: cost, total_price: cost, currency: 'USD', with_excessive_length_fees: @conf.dig(:attributes, :rates, :with_excessive_length_fees) ) ] else success = false message = 'API Error: Cost is emtpy' end end end RateResponse.new( success, message, response.to_hash, rates: rate_estimates, response: response, request: last_request ) end
parse_tracking_response(response)
click to toggle source
# File lib/reactive_freight/carriers/rdfs.rb, line 231 def parse_tracking_response(response) json = JSON.parse(response.read) if (response.status[0] != '200') || !json.dig('SearchResults') status = json.dig('error') || "API Error: HTTP #{response.status[0]}" return TrackingResponse.new(false, status, json, carrier: "#{@@scac}, #{@@name}", json: json, response: response, request: last_request) end search_result = json.dig('SearchResults')[0] if search_result.dig('Shipment', 'ProNumber').downcase.include?('not available') status = "API Error: #{@@name} tracking number not found" return TrackingResponse.new(false, status, json, carrier: "#{@@scac}, #{@@name}", json: json, response: response, request: last_request) end receiver_address = Location.new( city: search_result.dig('Shipment', 'Consignee', 'City').titleize, province: search_result.dig('Shipment', 'Consignee', 'State').upcase, state: search_result.dig('Shipment', 'Consignee', 'State').upcase, country: ActiveUtils::Country.find('USA') ) shipper_address = Location.new( city: search_result.dig('Shipment', 'Origin', 'City').titleize, province: search_result.dig('Shipment', 'Origin', 'State').upcase, state: search_result.dig('Shipment', 'Origin', 'State').upcase, country: ActiveUtils::Country.find('USA') ) actual_delivery_date = parse_date(search_result.dig('Shipment', 'DeliveredDateTime')) scheduled_delivery_date = parse_date(search_result.dig('Shipment', 'ApptDateTime')) tracking_number = search_result.dig('Shipment', 'SearchItem') last_location = nil shipment_events = [] search_result.dig('Shipment', 'Comments').each do |api_event| type_code = api_event.dig('ActivityCode') next if !type_code || type_code == 'ARQ' event = @conf.dig(:events, :types).key(type_code) next if event.blank? datetime_without_time_zone = parse_date(api_event.dig('StatusDateTime')) comment = strip_date(api_event.dig('StatusComment')) case event when :arrived_at_terminal location = parse_location(comment, [' to ', 'in ']) when :delivered location = receiver_address when :departed location = parse_location(comment, [' to ', 'from ']) when :out_for_delivery location = parse_location(comment, [' to ', 'from ']) when :picked_up location = shipper_address when :trailer_closed location = last_location when :trailer_unloaded location = parse_location(comment, [' to ', 'in ']) end last_location = location # status and type_code set automatically by ActiveFreight based on event shipment_events << ShipmentEvent.new(event, datetime_without_time_zone, location) end shipment_events = shipment_events.sort_by(&:time) TrackingResponse.new( true, shipment_events.last.status, json, carrier: "#{@@scac}, #{@@name}", json: json, response: response, status: status, type_code: shipment_events.last.status, ship_time: parse_date(search_result.dig('Shipment', 'ProDateTime')), scheduled_delivery_date: scheduled_delivery_date, actual_delivery_date: actual_delivery_date, delivery_signature: nil, shipment_events: shipment_events, shipper_address: shipper_address, origin: shipper_address, destination: receiver_address, tracking_number: tracking_number ) end
request_url(action)
click to toggle source
# File lib/reactive_freight/carriers/rdfs.rb, line 72 def request_url(action) scheme = @conf.dig(:api, :use_ssl, action) ? 'https://' : 'http://' "#{scheme}#{@conf.dig(:api, :domains, action)}#{@conf.dig(:api, :endpoints, action)}" end
strip_date(str)
click to toggle source
# File lib/reactive_freight/carriers/rdfs.rb, line 77 def strip_date(str) str ? str.split(/[A|P]M /)[1] : nil end