Class: CatalogItemRetailerProbe
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- CatalogItemRetailerProbe
- Includes:
- Turbo::Broadcastable
- Defined in:
- app/models/catalog_item_retailer_probe.rb
Overview
== Schema Information
Table name: catalog_item_retailer_probes
Database name: primary
id :bigint not null, primary key
content_size_bytes :integer
currency :string(3)
error_message :string
geo_location :string(10)
page_accessible :boolean default(FALSE)
price :decimal(10, 2)
product_available :boolean
response_time_ms :integer
status :string default("pending"), not null
store_json :jsonb
url :string
created_at :datetime not null
updated_at :datetime not null
catalog_item_id :bigint not null
Indexes
idx_retailer_probes_item_created (catalog_item_id,created_at)
index_catalog_item_retailer_probes_on_created_at (created_at)
index_catalog_item_retailer_probes_on_status (status)
Foreign Keys
fk_rails_... (catalog_item_id => catalog_items.id)
Constant Summary collapse
- STATUSES =
Status values
{ pending: 'pending', # Probe queued but not yet performed success: 'success', # Page loaded and data extracted failed: 'failed', # Request failed (timeout, error) not_found: 'not_found', # Page returned 404 or product not on page product_mismatch: 'product_mismatch' # Page loaded but product identifiers not found }.freeze
- CURRENT_STATE_LOOKBACK_DAYS =
Lookback window for treating a probe as the item's current external state.
Retailer::DailyComplianceReport derives its probe-based columns (scrape
failures / unreachable / out of stock online) from this same window, and the
latest-probe scopes below back the deep links in that daily email, so the
report's counts and the lists those links open stay in lockstep. 14
Constants included from Schedulable
Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
- #currency ⇒ Object readonly
- #geo_location ⇒ Object readonly
- #status ⇒ Object readonly
Belongs to collapse
Class Method Summary collapse
-
.current_out_of_stock_online_item_ids ⇒ ActiveRecord::Relation
catalog_item_ids whose most-recent probe in the window reported the item out of stock at the retailer.
-
.current_scrape_failure_item_ids ⇒ ActiveRecord::Relation
catalog_item_ids whose most-recent probe in the window loaded the page but could not yield a valid product/price — a scrape failure (product not on page / 404-on-page / product mismatch).
-
.current_unreachable_online_item_ids ⇒ ActiveRecord::Relation
catalog_item_ids whose most-recent probe in the window could not load the product page at all (request failed / timed out / blocked / Oxylabs job faulted → status 'failed').
-
.failed ⇒ ActiveRecord::Relation<CatalogItemRetailerProbe>
A relation of CatalogItemRetailerProbes that are failed.
-
.in_stock ⇒ ActiveRecord::Relation<CatalogItemRetailerProbe>
A relation of CatalogItemRetailerProbes that are in stock.
-
.latest ⇒ ActiveRecord::Relation<CatalogItemRetailerProbe>
A relation of CatalogItemRetailerProbes that are latest.
-
.latest_probe_ids_in_window ⇒ ActiveRecord::Relation
Probe-row ids of the single most-recent probe per catalog item within the current-state lookback window (Postgres DISTINCT ON).
-
.out_of_stock ⇒ ActiveRecord::Relation<CatalogItemRetailerProbe>
A relation of CatalogItemRetailerProbes that are out of stock.
-
.recent ⇒ ActiveRecord::Relation<CatalogItemRetailerProbe>
A relation of CatalogItemRetailerProbes that are recent.
-
.successful ⇒ ActiveRecord::Relation<CatalogItemRetailerProbe>
A relation of CatalogItemRetailerProbes that are successful.
-
.today ⇒ ActiveRecord::Relation<CatalogItemRetailerProbe>
A relation of CatalogItemRetailerProbes that are today.
Instance Method Summary collapse
-
#amazon_probe? ⇒ Boolean
Check if this is an Amazon probe (has buy box tracking).
-
#availability_text ⇒ Object
Availability as text.
-
#buy_box? ⇒ Boolean
Check if this probe detected a buy box (Amazon-specific) Returns true only if we explicitly detected a buy box.
-
#in_stock? ⇒ Boolean
Check if product appears to be in stock.
-
#no_buy_box? ⇒ Boolean
Check if this probe explicitly detected NO buy box (Amazon-specific) Returns true only if we explicitly detected no buy box (not just nil/unknown).
-
#out_of_stock? ⇒ Boolean
Check if product is definitely out of stock.
-
#price_captured? ⇒ Boolean
Check if this represents a successful price capture.
-
#summary ⇒ Object
Human-readable summary.
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#currency ⇒ Object (readonly)
66 |
# File 'app/models/catalog_item_retailer_probe.rb', line 66 validates :currency, length: { maximum: 3 } |
#geo_location ⇒ Object (readonly)
65 |
# File 'app/models/catalog_item_retailer_probe.rb', line 65 validates :geo_location, length: { maximum: 10 } |
#status ⇒ Object (readonly)
64 |
# File 'app/models/catalog_item_retailer_probe.rb', line 64 validates :status, presence: true, inclusion: { in: STATUSES.values } |
Class Method Details
.current_out_of_stock_online_item_ids ⇒ ActiveRecord::Relation
catalog_item_ids whose most-recent probe in the window reported the item out
of stock at the retailer. Mirrors the out_of_stock_online column.
115 116 117 |
# File 'app/models/catalog_item_retailer_probe.rb', line 115 def self.current_out_of_stock_online_item_ids where(id: latest_probe_ids_in_window).out_of_stock.select(:catalog_item_id) end |
.current_scrape_failure_item_ids ⇒ ActiveRecord::Relation
catalog_item_ids whose most-recent probe in the window loaded the page but
could not yield a valid product/price — a scrape failure (product not on
page / 404-on-page / product mismatch). Distinct from the page being
unreachable. Mirrors the scrape_failures column in
Retailer::DailyComplianceReport.
94 95 96 97 98 |
# File 'app/models/catalog_item_retailer_probe.rb', line 94 def self.current_scrape_failure_item_ids where(id: latest_probe_ids_in_window) .where(status: %w[not_found product_mismatch]) .select(:catalog_item_id) end |
.current_unreachable_online_item_ids ⇒ ActiveRecord::Relation
catalog_item_ids whose most-recent probe in the window could not load the
product page at all (request failed / timed out / blocked / Oxylabs job
faulted → status 'failed'). Mirrors the unreachable_online column. Uses
status rather than the page_accessible flag, which the async batch path
historically left at its FALSE default even on success.
107 108 109 |
# File 'app/models/catalog_item_retailer_probe.rb', line 107 def self.current_unreachable_online_item_ids where(id: latest_probe_ids_in_window).where(status: 'failed').select(:catalog_item_id) end |
.failed ⇒ ActiveRecord::Relation<CatalogItemRetailerProbe>
A relation of CatalogItemRetailerProbes that are failed. Active Record Scope
69 |
# File 'app/models/catalog_item_retailer_probe.rb', line 69 scope :failed, -> { where(status: %w[failed not_found product_mismatch]) } |
.in_stock ⇒ ActiveRecord::Relation<CatalogItemRetailerProbe>
A relation of CatalogItemRetailerProbes that are in stock. Active Record Scope
73 |
# File 'app/models/catalog_item_retailer_probe.rb', line 73 scope :in_stock, -> { where(product_available: true) } |
.latest ⇒ ActiveRecord::Relation<CatalogItemRetailerProbe>
A relation of CatalogItemRetailerProbes that are latest. Active Record Scope
71 |
# File 'app/models/catalog_item_retailer_probe.rb', line 71 scope :latest, -> { order(created_at: :desc).first } |
.latest_probe_ids_in_window ⇒ ActiveRecord::Relation
Probe-row ids of the single most-recent probe per catalog item within the
current-state lookback window (Postgres DISTINCT ON). Shaped as a relation so
it can drive where(id: …) subqueries that evaluate each item's latest state.
81 82 83 84 85 |
# File 'app/models/catalog_item_retailer_probe.rb', line 81 def self.latest_probe_ids_in_window where(created_at: CURRENT_STATE_LOOKBACK_DAYS.days.ago..) .select('DISTINCT ON (catalog_item_id) id') .order(:catalog_item_id, created_at: :desc) end |
.out_of_stock ⇒ ActiveRecord::Relation<CatalogItemRetailerProbe>
A relation of CatalogItemRetailerProbes that are out of stock. Active Record Scope
74 |
# File 'app/models/catalog_item_retailer_probe.rb', line 74 scope :out_of_stock, -> { where(product_available: false) } |
.recent ⇒ ActiveRecord::Relation<CatalogItemRetailerProbe>
A relation of CatalogItemRetailerProbes that are recent. Active Record Scope
70 |
# File 'app/models/catalog_item_retailer_probe.rb', line 70 scope :recent, -> { where(created_at: 7.days.ago..) } |
.successful ⇒ ActiveRecord::Relation<CatalogItemRetailerProbe>
A relation of CatalogItemRetailerProbes that are successful. Active Record Scope
68 |
# File 'app/models/catalog_item_retailer_probe.rb', line 68 scope :successful, -> { where(status: 'success') } |
.today ⇒ ActiveRecord::Relation<CatalogItemRetailerProbe>
A relation of CatalogItemRetailerProbes that are today. Active Record Scope
72 |
# File 'app/models/catalog_item_retailer_probe.rb', line 72 scope :today, -> { where(created_at: Time.current.beginning_of_day..) } |
Instance Method Details
#amazon_probe? ⇒ Boolean
Check if this is an Amazon probe (has buy box tracking)
166 167 168 |
# File 'app/models/catalog_item_retailer_probe.rb', line 166 def amazon_probe? has_buy_box != nil end |
#availability_text ⇒ Object
Availability as text
193 194 195 196 197 198 199 200 201 |
# File 'app/models/catalog_item_retailer_probe.rb', line 193 def availability_text if product_available.nil? 'Unknown' elsif product_available 'In Stock' else 'Out of Stock' end end |
#buy_box? ⇒ Boolean
Check if this probe detected a buy box (Amazon-specific)
Returns true only if we explicitly detected a buy box
155 156 157 |
# File 'app/models/catalog_item_retailer_probe.rb', line 155 def buy_box? has_buy_box == true end |
#catalog_item ⇒ CatalogItem
39 |
# File 'app/models/catalog_item_retailer_probe.rb', line 39 belongs_to :catalog_item |
#in_stock? ⇒ Boolean
Check if product appears to be in stock
144 145 146 |
# File 'app/models/catalog_item_retailer_probe.rb', line 144 def in_stock? product_available == true end |
#no_buy_box? ⇒ Boolean
Check if this probe explicitly detected NO buy box (Amazon-specific)
Returns true only if we explicitly detected no buy box (not just nil/unknown)
161 162 163 |
# File 'app/models/catalog_item_retailer_probe.rb', line 161 def no_buy_box? has_buy_box == false end |
#out_of_stock? ⇒ Boolean
Check if product is definitely out of stock
149 150 151 |
# File 'app/models/catalog_item_retailer_probe.rb', line 149 def out_of_stock? product_available == false end |
#price_captured? ⇒ Boolean
Check if this represents a successful price capture
139 140 141 |
# File 'app/models/catalog_item_retailer_probe.rb', line 139 def price_captured? status == 'success' && price.present? end |
#summary ⇒ Object
Human-readable summary
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'app/models/catalog_item_retailer_probe.rb', line 171 def summary case status when 'success' parts = [] if no_buy_box? parts << 'No Buy Box' elsif price.present? parts << format_price parts << "Seller: #{buy_box_seller}" if buy_box_seller.present? end parts << availability_text if product_available.present? parts.join(' | ') when 'failed' "Failed: #{&.truncate(50)}" when 'not_found' 'Product not found' else 'Pending' end end |