module AuspostTrack
AuspostTrack — fetch and parse Australia Post tracking via public page scrape. Public: fetch_tracking, parse_tracking_payload, parse_merchant_payload, event_key, delivered?, valid_tracking_id? Depends: AuspostScrape (lazy) Tests: test/lib/auspost_track_test.rb
Constants
- MAX_IDS_PER_REQUEST
- TRACKING_ID_PATTERN
- USER_AGENT
Public Instance Methods
Source
# File lib/auspost_track.rb, line 100 def delivered?(status) status.to_s.strip.casecmp?("delivered") end
Source
# File lib/auspost_track.rb, line 93 def event_key(event) date = event[:date] || event["date"] location = event[:location] || event["location"] description = event[:description] || event["description"] "#{date}|#{location}|#{description}" end
Source
# File lib/auspost_track.rb, line 86 def event_time(event) raw = event.is_a?(Hash) ? (event[:date] || event["date"]) : nil Time.parse(raw.to_s) rescue ArgumentError nil end
Source
# File lib/auspost_track.rb, line 30 def fetch_tracking(tracking_ids, scrape: nil) require_relative "auspost_scrape" ids = Array(tracking_ids).map { |id| normalize_tracking_id(id) }.compact.uniq return {} if ids.empty? results = {} ids.each do |id| entry = AuspostScrape.scrape(id, scrape: scrape) results[id] = entry unless entry.nil? end results rescue StandardError {} end
Source
# File lib/auspost_track.rb, line 124 def format_event_line(event) description = (event[:description] || event["description"]).to_s.strip location = (event[:location] || event["location"]).to_s.strip when_text = format_event_time(event) parts = [description] parts << location unless location.empty? parts << when_text unless when_text.empty? parts.join(" — ") end
Source
# File lib/auspost_track.rb, line 115 def format_event_time(event) time = event_time(event.is_a?(Hash) ? event : {}) return "" unless time time.strftime("%-d %b %H:%M") rescue StandardError "" end
Source
# File lib/auspost_track.rb, line 78 def latest_event_from_row(row) events = Array(row["trackable_items"]).flat_map { |item| Array(item["events"]) } return nil if events.empty? latest = events.max_by { |event| event_time(event) || Time.at(0) } symbolize_event(latest) end
Source
# File lib/auspost_track.rb, line 111 def normalize_status(raw) TextUtil.title_words(raw.to_s.strip) end
Source
# File lib/auspost_track.rb, line 23 def normalize_tracking_id(value) id = value.to_s.strip.upcase return nil unless TRACKING_ID_PATTERN.match?(id) id end
Source
# File lib/auspost_track.rb, line 50 def parse_merchant_payload(payload, tracking_id:) row = Array(payload["tracking_results"]).find { |entry| entry["tracking_id"].to_s == tracking_id.to_s } return nil unless row errors = Array(row["errors"]) if errors.any? message = errors.first["message"].to_s message = errors.first["name"].to_s if message.empty? return { tracking_id: tracking_id, error: user_error_message(message) } end latest_event = latest_event_from_row(row) { tracking_id: tracking_id, status: row["status"].to_s, latest_event: latest_event, last_event_key: latest_event ? event_key(latest_event) : nil } end
Source
# File lib/auspost_track.rb, line 45 def parse_tracking_payload(payload, tracking_id:) require_relative "auspost_scrape" AuspostScrape.parse_payload(payload, tracking_id: tracking_id) end
Source
# File lib/auspost_track.rb, line 70 def symbolize_event(event) { date: event["date"] || event[:date], location: event["location"] || event[:location], description: event["description"] || event[:description] } end
Source
# File lib/auspost_track.rb, line 104 def user_error_message(raw) text = raw.to_s.strip return "Invalid tracking ID" if text.match?(/invalid.*tracking/i) text.empty? ? "Could not track parcel" : text end
Source
# File lib/auspost_track.rb, line 19 def valid_tracking_id?(value) !normalize_tracking_id(value).nil? end