Class: ListingIssues::AmazonAdapter
- Inherits:
-
BaseAdapter
- Object
- BaseAdapter
- ListingIssues::AmazonAdapter
- Defined in:
- app/services/listing_issues/amazon_adapter.rb
Overview
Amazon listing issues, sourced from signals the SP-API pulls already persist:
active has_issues AmazonCatalogItemFlag rows (the SP-API listing issues
array, joined into text by Catalog::AmazonPricingAutomationService) and
CatalogItem#item_suppressed_status. Reads stored data only — never calls
Amazon — so it can't block on rate limits and stays consistent with whatever
the pricing / listings pulls last recorded.
Constant Summary collapse
- PROVIDER =
Provider key stamped on every Issue this adapter emits.
'amazon'- SEGMENT_BOUNDARY =
The joined
issuestext is split back into per-issue segments on the
boundary before a "[xx_XX] " locale marker, so a ';' inside a message
doesn't fracture it. /;\s+(?=\[[a-z]{2}_[A-Z]{2}\]\s)/- SEGMENT_FORMAT =
"[en_US] ERROR: 13013 - message" → locale / severity word / code / message.
/\A\[(?<locale>[a-z]{2}_[A-Z]{2})\]\s+(?<sev>ERROR|WARNING|INFO)?:?\s*(?<code>\d+)?\s*-?\s*(?<msg>.*)\z/m- PRODUCT_TYPE_DESIRED_MISMATCH_SQL =
Static SQL (column references only — no interpolation) mirroring
#issues_from_desired_product_type so the bulk sweep only visits genuine
mismatches. Two independent axes: the LISTING should carry the submittable
type (amazon_product_schema, else desired) and the CATALOG should carry the
desired type. The intended catalog≠listing split (desired=TOWEL_WARMER,
schema/listing=TOWEL_HOLDER) is therefore NOT selected. <<~SQL.squish.freeze COALESCE(NULLIF(catalog_items.amazon_desired_product_type, ''), NULLIF(variant_groups.channel_settings->>'amazon_desired_product_type', '')) IS NOT NULL AND ( (NULLIF(catalog_items.amazon_listing_reported_product_type, '') IS NOT NULL AND NULLIF(catalog_items.amazon_listing_reported_product_type, '') <> COALESCE(NULLIF(catalog_items.amazon_product_schema, ''), NULLIF(variant_groups.channel_settings->>'amazon_product_schema', ''), NULLIF(catalog_items.amazon_desired_product_type, ''), NULLIF(variant_groups.channel_settings->>'amazon_desired_product_type', ''))) OR (NULLIF(catalog_items.amazon_reported_product_type, '') IS NOT NULL AND NULLIF(catalog_items.amazon_reported_product_type, '') <> COALESCE(NULLIF(catalog_items.amazon_desired_product_type, ''), NULLIF(variant_groups.channel_settings->>'amazon_desired_product_type', ''))) ) SQL
- PRODUCT_CATEGORY_DESIRED_MISMATCH_SQL =
Static SQL mirroring #issues_from_desired_category so the bulk sweep only
visits genuine category mismatches: the catalog has a marketplace, the item
has a desired browse node for that marketplace, and Amazon's reported browse
classification (stored catalog payload, any locale) is NOT one of those
desired nodes. The precise compare stays here rather than scanning every
item that merely has a browse node. <<~SQL.squish.freeze catalogs.amazon_marketplace_id IS NOT NULL AND EXISTS ( SELECT 1 FROM amazon_browse_nodes_catalog_items dci JOIN amazon_browse_nodes dn ON dn.id = dci.amazon_browse_node_id WHERE dci.catalog_item_id = catalog_items.id AND dn.amazon_marketplace_id = catalogs.amazon_marketplace_id ) AND EXISTS ( SELECT 1 FROM jsonb_each(catalog_items.retailer_information) AS loc(key, value) CROSS JOIN LATERAL jsonb_array_elements( CASE WHEN jsonb_typeof(value #> '{catalog,payload,summaries}') = 'array' THEN value #> '{catalog,payload,summaries}' ELSE '[]'::jsonb END ) AS summary(value) WHERE (summary.value #>> '{browseClassification,classificationId}') IS NOT NULL AND NOT EXISTS ( SELECT 1 FROM amazon_browse_nodes_catalog_items mci JOIN amazon_browse_nodes mn ON mn.id = mci.amazon_browse_node_id WHERE mci.catalog_item_id = catalog_items.id AND mn.amazon_marketplace_id = catalogs.amazon_marketplace_id AND mn.node_id = (summary.value #>> '{browseClassification,classificationId}') ) ) SQL
Instance Method Summary collapse
- #candidate_item_ids ⇒ Array<Integer>
-
#eager_load ⇒ Array
Everything the checks above touch, eager-loaded by the bulk sweep.
- #issues_for(catalog_item) ⇒ Array<ListingIssues::Issue>
- #provider ⇒ String
Instance Method Details
#candidate_item_ids ⇒ Array<Integer>
79 80 81 82 83 |
# File 'app/services/listing_issues/amazon_adapter.rb', line 79 def candidate_item_ids (has_issues_item_ids + suppressed_item_ids + open_issue_item_ids + product_type_desired_mismatch_item_ids + desired_category_mismatch_item_ids + buy_box_lost_item_ids + variation_product_type_divergent_item_ids).uniq end |
#eager_load ⇒ Array
Everything the checks above touch, eager-loaded by the bulk sweep.
104 105 106 |
# File 'app/services/listing_issues/amazon_adapter.rb', line 104 def eager_load %i[amazon_catalog_item_flags catalog amazon_browse_nodes variant_group] end |
#issues_for(catalog_item) ⇒ Array<ListingIssues::Issue>
87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'app/services/listing_issues/amazon_adapter.rb', line 87 def issues_for(catalog_item) # Only active listings are actionable. Returning [] for non-active items # (which can still be candidates via open_issue_item_ids) lets the sync # auto-resolve issues left over from an item that has since been # discontinued — keeping the dashboard to the live catalog. return [] unless catalog_item.state == 'active' issues_from_flags(catalog_item) + issues_from_suppression(catalog_item) + issues_from_desired_product_type(catalog_item) + issues_from_desired_category(catalog_item) + issues_from_buy_box_loss(catalog_item) + issues_from_variation_product_type_divergence(catalog_item) end |
#provider ⇒ String
76 |
# File 'app/services/listing_issues/amazon_adapter.rb', line 76 def provider = PROVIDER |