module AuspostWatch
AuspostWatch — per-channel parcel watch list and polling logic for !auspost. Public: load_state, save_state, add_parcel, remove_parcel, refresh_state, due_for_refresh? Depends: AuspostTrack, AuspostReport, RabbotDb Tests: test/lib/auspost_watch_test.rb
Constants
- PLUGIN
- REFRESH_INTERVAL_SEC
- STATE_KEY
Public Instance Methods
Source
# File lib/auspost_watch.rb, line 56 def add_parcel(state, tracking_id:, added_by:, scrape:) id = AuspostTrack.normalize_tracking_id(tracking_id) return { error: "Invalid tracking ID" } unless id return { error: "already tracking #{id}" } if state["parcels"].any? { |parcel| parcel["id"] == id } tracking = AuspostTrack.fetch_tracking([id], scrape: scrape)[id] return { error: "Could not fetch tracking details" } unless tracking return { error: tracking[:error] } if tracking[:error] parcel = { "id" => id, "status" => tracking[:status], "last_event_key" => tracking[:last_event_key], "added_by" => added_by.to_s } updated_state = state.merge("parcels" => state["parcels"] + [parcel]) text = if tracking[:latest_event] AuspostReport.format_status_card(parcel, tracking[:latest_event]) else AuspostReport.format_status_card(parcel, { description: tracking[:status], location: "", date: "" }) end { state: updated_state, text: text } end
Source
# File lib/auspost_watch.rb, line 19 def default_state { "parcels" => [], "last_refresh_at" => nil } end
Source
# File lib/auspost_watch.rb, line 46 def due_for_refresh?(state, now: Time.now, interval_sec: REFRESH_INTERVAL_SEC) raw = state["last_refresh_at"] return true if raw.nil? || raw.to_s.strip.empty? last = RabbotDb.parse_time(raw) return true unless last (now - last) >= interval_sec end
Source
# File lib/auspost_watch.rb, line 26 def load_state(network:, channel:, store: RabbotDb) store.get_plugin_json( plugin: PLUGIN, key: STATE_KEY, network: network, channel: channel, default: nil ) || default_state end
Source
# File lib/auspost_watch.rb, line 91 def refresh_state(state, scrape:, now: Time.now) parcels = state["parcels"] return refresh_timestamp(state, now: now) if parcels.empty? tracking = AuspostTrack.fetch_tracking(parcels.map { |parcel| parcel["id"] }, scrape: scrape) announcements = [] remaining = [] parcels.each do |parcel| entry = tracking[parcel["id"]] next remaining << parcel unless entry if entry[:error] remaining << parcel next end updated_parcel = parcel.merge("status" => entry[:status]) latest_event = entry[:latest_event] new_key = entry[:last_event_key] old_key = parcel["last_event_key"] if old_key.nil? || old_key.to_s.empty? remaining << updated_parcel.merge("last_event_key" => new_key) next end if new_key && new_key != old_key if AuspostTrack.delivered?(entry[:status]) announcements << { type: :delivered, text: AuspostReport.format_delivered_card(updated_parcel, latest_event) } else announcements << { type: :update, text: AuspostReport.format_update_card(updated_parcel, latest_event) } remaining << updated_parcel.merge("last_event_key" => new_key) end else remaining << updated_parcel end end { state: state.merge( "parcels" => remaining, "last_refresh_at" => RabbotDb.iso_time(now) ), announcements: announcements } end
Source
# File lib/auspost_watch.rb, line 145 def refresh_timestamp(state, now:) { state: state.merge("last_refresh_at" => RabbotDb.iso_time(now)), announcements: [] } end
Source
# File lib/auspost_watch.rb, line 81 def remove_parcel(state, tracking_id:) id = AuspostTrack.normalize_tracking_id(tracking_id) return { error: "Invalid tracking ID" } unless id return { error: "Parcel not found" } unless state["parcels"].any? { |parcel| parcel["id"] == id } { state: state.merge("parcels" => state["parcels"].reject { |parcel| parcel["id"] == id }) } end
Source
# File lib/auspost_watch.rb, line 36 def save_state(network:, channel:, state:, store: RabbotDb) store.set_plugin_json( plugin: PLUGIN, key: STATE_KEY, network: network, channel: channel, value: state ) end