Class: ListingIssue
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- ListingIssue
- Defined in:
- app/models/listing_issue.rb
Overview
A single problem with a catalog item's marketplace listing as reported by the
marketplace's own API — Amazon suppression / SP-API listing issues, Walmart
unpublished reasons, Wayfair catalog-sync gaps, and (as integrations land)
other providers.
Distinct from CatalogItemRetailerProbe, which scrapes the public retailer
page: a listing issue is what the channel says is wrong with our listing,
not what our scraper could or couldn't read. Rows are reconciled by
ListingIssues::Sync (per provider): current issues are upserted on the
(catalog_item_id, provider, fingerprint) key and issues no longer reported
are auto-resolved, so the open set always mirrors the channel. Surfaced as the
"Listing Issues" column in the daily retailer-compliance report and reviewed /
resolved in the CRM Listing Issues dashboard.
Constant Summary collapse
- PROVIDERS =
Recognised providers (the marketplace the issue came from).
retailer_probe
is not a marketplace itself — it's our own probe's cross-retailer signal
(see ListingIssues::RetailerProbeAdapter);websiteis our own storefront
(see ListingIssues::WebsiteAdapter), where WE are the channel. %w[amazon walmart wayfair google retailer_probe website].freeze
- SEVERITIES =
Severity buckets, worst first.
criticalis a listing we independently
verified is broken — the retailer page loads (ruling out a scraper/network
blip) but the product is not buyable or not on it; self-verified live
revenue loss, so it outranks everything.errorblocks/suppresses the
listing per the channel's own signal (suppression, NOT_LIVE, missing
required spec).warningis advisory (the listing still shows). %w[critical error warning].freeze
Constants included from Models::Schedulable
Models::Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
Belongs to collapse
Has one collapse
Class Method Summary collapse
-
.by_sku ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are by sku.
-
.critical ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are critical.
-
.errors ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are errors.
-
.for_provider ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are for provider.
-
.open ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are open.
-
.open_item_ids ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are open item ids.
-
.resolved ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are resolved.
-
.warnings ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are warnings.
Instance Method Summary collapse
-
#open? ⇒ Boolean
True while the issue is still open (unresolved).
-
#resolve!(note: nil) ⇒ Boolean
Mark the issue resolved.
-
#resolved? ⇒ Boolean
True once the issue has been resolved.
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Models::Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#code ⇒ String
79 |
# File 'app/models/listing_issue.rb', line 79 validates :code, presence: true |
#fingerprint ⇒ String
85 |
# File 'app/models/listing_issue.rb', line 85 validates :fingerprint, presence: true, uniqueness: { scope: %i[catalog_item_id provider] } |
#provider ⇒ String
76 |
# File 'app/models/listing_issue.rb', line 76 validates :provider, presence: true, inclusion: { in: PROVIDERS } |
#severity ⇒ String
82 |
# File 'app/models/listing_issue.rb', line 82 validates :severity, inclusion: { in: SEVERITIES } |
Class Method Details
.by_sku ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are by sku. Active Record Scope
97 98 99 100 101 |
# File 'app/models/listing_issue.rb', line 97 scope :by_sku, ->(sku) { return all if sku.blank? joins(catalog_item: { store_item: :item }).where('items.sku ILIKE ?', "%#{sku.strip}%") } |
.critical ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are critical. Active Record Scope
90 |
# File 'app/models/listing_issue.rb', line 90 scope :critical, -> { where(severity: 'critical') } |
.errors ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are errors. Active Record Scope
91 |
# File 'app/models/listing_issue.rb', line 91 scope :errors, -> { where(severity: 'error') } |
.for_provider ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are for provider. Active Record Scope
89 |
# File 'app/models/listing_issue.rb', line 89 scope :for_provider, ->(provider) { where(provider:) } |
.open ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are open. Active Record Scope
87 |
# File 'app/models/listing_issue.rb', line 87 scope :open, -> { where(resolved_at: nil) } |
.open_item_ids ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are open item ids. Active Record Scope
95 |
# File 'app/models/listing_issue.rb', line 95 scope :open_item_ids, -> { open.distinct.select(:catalog_item_id) } |
.resolved ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are resolved. Active Record Scope
88 |
# File 'app/models/listing_issue.rb', line 88 scope :resolved, -> { where.not(resolved_at: nil) } |
.warnings ⇒ ActiveRecord::Relation<ListingIssue>
A relation of ListingIssues that are warnings. Active Record Scope
92 |
# File 'app/models/listing_issue.rb', line 92 scope :warnings, -> { where(severity: 'warning') } |
Instance Method Details
#catalog ⇒ Catalog
72 |
# File 'app/models/listing_issue.rb', line 72 has_one :catalog, through: :catalog_item |
#catalog_item ⇒ CatalogItem
67 |
# File 'app/models/listing_issue.rb', line 67 belongs_to :catalog_item |
#open? ⇒ Boolean
Returns true while the issue is still open (unresolved).
104 105 106 |
# File 'app/models/listing_issue.rb', line 104 def open? resolved_at.nil? end |
#resolve!(note: nil) ⇒ Boolean
Mark the issue resolved. Resolution is detection-derived only — called by
ListingIssues::Sync when the provider stops reporting the issue. There is
no manual "mark fixed": an auto-detected issue is open while detected and
resolved when it's gone.
119 120 121 |
# File 'app/models/listing_issue.rb', line 119 def resolve!(note: nil) update!(resolved_at: Time.current, resolution_note: note) end |
#resolved? ⇒ Boolean
Returns true once the issue has been resolved.
109 110 111 |
# File 'app/models/listing_issue.rb', line 109 def resolved? resolved_at.present? end |
#resolved_by ⇒ EmployeeRecord?
69 |
# File 'app/models/listing_issue.rb', line 69 belongs_to :resolved_by, class_name: 'EmployeeRecord', optional: true |