Class: SpreeDoordash::Quote

Inherits:
Object
  • Object
show all
Defined in:
app/services/spree_doordash/quote.rb

Overview

Requests a live DoorDash Drive delivery-fee quote for an order — the storefront-facing half of this extension (called from Spree::Calculator::Shipping::DoordashQuote during checkout, M3) and again at order.completed if the original quote expired (M4).

order.total at whichever moment this is called is what's sent as order_value — Spree recalculates on every checkout step already, and DoorDash isn't in the money path (Spree's own payment method still charges the customer; DoorDash only uses this for delivery-fee/ insurance math).

Defined Under Namespace

Classes: Result

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.callObject



15
# File 'app/services/spree_doordash/quote.rb', line 15

def self.call(...) = new.call(...)

Instance Method Details

#call(order) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'app/services/spree_doordash/quote.rb', line 17

def call(order)
  location_mapping = location_mapping_for(order)
  return nil unless location_mapping && order.ship_address

  client = SpreeDoordash::Client.for_store(order.store || Spree::Store.default)
  # A random suffix per attempt, not just order.number — confirmed live
  # against a real Sandbox quote: DoorDash rejects a *second*
  # /drive/v2/quotes call reusing the same external_delivery_id with a
  # 409 duplicate_delivery_id, even though the first quote is still open
  # (not yet accepted or expired). Checkout recalculates shipping rates
  # on essentially every step, so calling this twice for the same order
  # is the normal case, not an edge case — a stable per-order id made
  # the DoorDash rate silently vanish (RequestError is rescued below,
  # same as any other unserviceable-rate case) after the very first
  # quote. QuoteMapping upserts on order, so only the most recent
  # attempt's id is kept — the one that matters for accept (M4).
  external_delivery_id = "spree-doordash-#{order.number}-#{SecureRandom.hex(4)}"

  response = client.create_quote(build_payload(order, location_mapping, external_delivery_id))
  mapping = persist_quote!(order, external_delivery_id, response)

  Result.new(
    fee_cents: mapping.quoted_fee_cents,
    currency: mapping.currency,
    external_delivery_id: mapping.external_delivery_id,
    expires_at: mapping.quote_expires_at
  )
rescue SpreeDoordash::Client::MissingCredentialsError, SpreeDoordash::RequestError => e
  # Unserviceable address, no credential connected, DoorDash-side
  # rejection — none of these should ever raise into checkout. The
  # calculator (M3) treats a nil Result as "this rate isn't available",
  # Spree's normal shape for "can't quote this," same as a carrier
  # simply not covering an address.
  Rails.logger.info("[SpreeDoordash] quote skipped for order #{order.number}: #{e.message}")
  nil
end