Class: Portage::Ucp::Etsy::Adapter
- Inherits:
-
Adapter
- Object
- Adapter
- Portage::Ucp::Etsy::Adapter
- Includes:
- Support::Idempotency, Support::NotFound
- Defined in:
- lib/portage/ucp/etsy/adapter.rb
Overview
Generic Portage::Ucp::Adapter over Etsy's Open API v3 — no merchant-specific business logic, same posture as the other adapters in this project.
IMPORTANT: unlike Shopify/Wix/WooCommerce/BigCommerce/Magento, this is deliberately a catalog + redirect-link checkout + order adapter, not a full transactional one — Etsy's public API has no cart, checkout, or add-to-cart endpoint at all. Buying only ever happens on etsy.com itself. This adapter therefore:
- Doesn't override
get_cart/create_cart/update_cart/cancel_cartat all —dev.ucp.shopping.cartstays unadvertised. - Overrides only
create_checkout/get_checkout.Checkout#linkscarries one link per requested listing, pointing straight at that listing's own etsy.com page — the closest real equivalent to "add this to your cart and check out" this API allows.update_ checkout/complete_checkout/cancel_checkoutare left unoverridden on purpose: there's nothing to update or complete programmatically, and calling them raises Portage::Ucp::NotImplementedError rather than silently pretending to do something.dev.ucp.shopping.checkoutstill gets advertised (Capability#advertised_for? only needs one overridden method), so an agent sees the capability and can discover which actions are actually backed by trying them. - The Checkout objects
create_checkoutreturns are not real Etsy resources — nothing on Etsy's side tracks them. They live only in this Adapter instance's memory (get_checkoutreads back whatcreate_checkoutstored), so they don't survive a process restart or a different Adapter instance. get_order'scheckout_idis always blank — there's no real checkout for a receipt to link back to in the first place (see above), a more fundamental gap than WooCommerce/Magento needing adapter-side tracking for a real checkout.
Deliberately doesn't override link_identity either — Etsy buyer/
seller OAuth identity is a separate concern from the shop-owner
access_token this gem uses for catalog/order reads.
Instance Method Summary collapse
- #create_checkout(line_items:, idempotency_key:) ⇒ Object
- #get_checkout(checkout_id:) ⇒ Object
- #get_order(order_id:) ⇒ Object
- #get_product(product_id:) ⇒ Object
-
#initialize(client:, shop_id:) ⇒ Adapter
constructor
A new instance of Adapter.
-
#search_catalog(query:, limit:) ⇒ Object
Etsy's shop-listings endpoint supports no keyword filter at all (only limit/offset/sort) — this fetches a page of active listings and filters by title client-side, so it's a much weaker "search" than every other adapter's real server-side query.
Constructor Details
#initialize(client:, shop_id:) ⇒ Adapter
Returns a new instance of Adapter.
50 51 52 53 54 55 |
# File 'lib/portage/ucp/etsy/adapter.rb', line 50 def initialize(client:, shop_id:) super() @client = client @shop_id = shop_id @checkouts = {} end |
Instance Method Details
#create_checkout(line_items:, idempotency_key:) ⇒ Object
78 79 80 81 82 83 84 85 86 |
# File 'lib/portage/ucp/etsy/adapter.rb', line 78 def create_checkout(line_items:, idempotency_key:) dedup(idempotency_key) do listings = line_items.map { |li| listing_with_quantity(li) } checkout_id = "etsy-checkout-#{idempotency_key}" checkout = Mapper.checkout(listings, id: checkout_id, status: "incomplete") @checkouts[checkout_id] = checkout checkout end end |
#get_checkout(checkout_id:) ⇒ Object
88 89 90 |
# File 'lib/portage/ucp/etsy/adapter.rb', line 88 def get_checkout(checkout_id:) @checkouts[checkout_id] end |
#get_order(order_id:) ⇒ Object
92 93 94 95 96 97 |
# File 'lib/portage/ucp/etsy/adapter.rb', line 92 def get_order(order_id:) nil_on_not_found do node = @client.get("/shops/#{@shop_id}/receipts/#{order_id}") node["receipt_id"] ? Mapper.order(node) : nil end end |
#get_product(product_id:) ⇒ Object
68 69 70 71 72 73 74 75 76 |
# File 'lib/portage/ucp/etsy/adapter.rb', line 68 def get_product(product_id:) nil_on_not_found do node = @client.get("/listings/#{product_id}") next nil unless node["listing_id"] inventory = @client.get("/listings/#{product_id}/inventory") Portage::Ucp::ProductDetail.new(product: Mapper.product(node.merge("variants_detail" => inventory))) end end |
#search_catalog(query:, limit:) ⇒ Object
Etsy's shop-listings endpoint supports no keyword filter at all (only limit/offset/sort) — this fetches a page of active listings and filters by title client-side, so it's a much weaker "search" than every other adapter's real server-side query. Fine for a small shop, misleading for a large one.
62 63 64 65 66 |
# File 'lib/portage/ucp/etsy/adapter.rb', line 62 def search_catalog(query:, limit:) data = @client.get("/shops/#{@shop_id}/listings/active?limit=100") matches = (data["results"] || []).select { |l| l["title"].to_s.downcase.include?(query.downcase) } Portage::Ucp::CatalogSearchResult.new(products: matches.first(limit).map { |node| Mapper.product(node) }) end |