spree_doordash 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -0
- data/app/models/spree/calculator/shipping/doordash_quote.rb +36 -4
- data/app/models/spree/order_decorator.rb +54 -0
- data/lib/spree_doordash/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6a028415e34fd065f59a11e00034d88ef6ea2dfa8155538bf61f63ba26cf16ed
|
|
4
|
+
data.tar.gz: f0425700d9f63218ee14eae64ce30d6e444c46b2eefae2fe4d3854f38426e13a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 25f7dc0b927d237844b908072f4b3f9fa738fe3db1c6b4036280e51d739c6b5eea92c2578dc730dbd5c89b33de5a10318f9898ee91e295a55deafcdf3426ae5b
|
|
7
|
+
data.tar.gz: b32fb99c09cb7344185f06ca15c72c60253669b0d5ea5374de62490c4a62e007ce39589b6df4a491bcfd8a54e71c4caf266ea348c0b8d9abf1355b01c03dcd23
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented here.
|
|
4
4
|
|
|
5
|
+
## 0.1.3
|
|
6
|
+
|
|
7
|
+
A real bug found live: the `doordash_quote_unavailable` warning added in 0.1.2 never actually
|
|
8
|
+
worked in production. `Spree::Calculator::Shipping::DoordashQuote#compute_package` pushed it onto
|
|
9
|
+
`package.order.warnings` — but `package.order` is **not** the same in-memory object as the order
|
|
10
|
+
the caller (`Spree::Order#create_proposed_shipments`) holds. `spree_core`'s own
|
|
11
|
+
`Spree::Stock::InventoryUnitBuilder#units` builds each inventory unit with `order_id: @order.id`
|
|
12
|
+
but deliberately *not* `order: @order` ("avoid loading the association to order until needed," per
|
|
13
|
+
its own comment) — the first thing that touches `.order` on one of those units triggers a fresh
|
|
14
|
+
`Spree::Order.find`, a brand-new Ruby object. So the warning was mutating a throwaway copy,
|
|
15
|
+
discarded the instant `compute_package` returned, and never reached the order this request
|
|
16
|
+
actually serializes back to the storefront as `cart.warnings`. Confirmed via `object_id` tracing
|
|
17
|
+
against production, not assumed — and confirmed the existing spec suite couldn't have caught it:
|
|
18
|
+
`doordash_quote_spec.rb`'s own `instance_double(Spree::Stock::Package, order: order)` makes
|
|
19
|
+
`package.order` the *same* object as the test's `order` by construction, sidestepping the exact
|
|
20
|
+
boundary that breaks in real Spree core.
|
|
21
|
+
|
|
22
|
+
Fixed by bridging across that boundary with the order's stable id instead of Ruby object identity
|
|
23
|
+
— `Spree::Calculator::Shipping::DoordashQuote.mark_unavailable(order_id)` sets a thread-local flag
|
|
24
|
+
(chosen over `Rails.cache`: this gem installs into arbitrary host apps, some of which legitimately
|
|
25
|
+
run `config.cache_store = :null_store`, which would silently degrade this back to the original bug
|
|
26
|
+
with zero indication anything was wrong — `compute_package` and `create_proposed_shipments` always
|
|
27
|
+
run synchronously on the same thread within one request, so a thread-local needs no external store
|
|
28
|
+
and no expiry logic). A new `Spree::OrderDecorator#create_proposed_shipments` reads the flag back
|
|
29
|
+
and merges the warning onto `self.warnings` immediately after `super` returns — `self` there *is*
|
|
30
|
+
the real order, since `create_proposed_shipments` is called directly on it by the checkout flow.
|
|
31
|
+
The flag is cleared unconditionally at the *start* of every call (not just after a successful
|
|
32
|
+
merge), so a stale flag left behind by an earlier request that raised before reaching the merge
|
|
33
|
+
step can never leak into a later, unrelated call that happens to reuse the same thread.
|
|
34
|
+
|
|
35
|
+
New `spec/models/spree/order_decorator_spec.rb` exercises the real
|
|
36
|
+
`order_routing_strategy -> Estimator -> Packer -> InventoryUnitBuilder` path end to end (only
|
|
37
|
+
`SpreeDoordash::Quote.call` is stubbed) — the only way to actually exercise the object-identity
|
|
38
|
+
boundary the fix bridges across, rather than doubling it away. Full suite: 95 examples, 0 failures
|
|
39
|
+
(5 new). Coverage: 94.14%. Brakeman clean.
|
|
40
|
+
|
|
5
41
|
## 0.1.2
|
|
6
42
|
|
|
7
43
|
A real bug found live during checkout-validation work: a blank phone on the dropoff address used
|
|
@@ -34,16 +34,48 @@ module Spree
|
|
|
34
34
|
# with no new API surface needed. The storefront renders its own
|
|
35
35
|
# localized copy for this code; `message` here is English-only,
|
|
36
36
|
# a fallback for any other API consumer, not the UI text itself.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
#
|
|
38
|
+
# A SECOND real bug found live (v0.1.2, this fix is v0.1.3):
|
|
39
|
+
# package.order is not the same object as the order the caller
|
|
40
|
+
# holds (spree_core's InventoryUnitBuilder deliberately defers
|
|
41
|
+
# loading that association — see the Spree::OrderDecorator this
|
|
42
|
+
# gem ships for the full story), so pushing the warning directly
|
|
43
|
+
# onto package.order.warnings here mutated a throwaway copy that
|
|
44
|
+
# never reached the real order. Thread.current bridges across
|
|
45
|
+
# that boundary via the order's id instead of Ruby object
|
|
46
|
+
# identity — chosen over Rails.cache deliberately: this gem
|
|
47
|
+
# installs into arbitrary host apps, some of which run
|
|
48
|
+
# `config.cache_store = :null_store` (the Rails test-env
|
|
49
|
+
# default, and a legitimate production choice too), which would
|
|
50
|
+
# silently degrade this back to the original bug with no
|
|
51
|
+
# indication anything was wrong. compute_package and
|
|
52
|
+
# create_proposed_shipments always run synchronously on the same
|
|
53
|
+
# thread within one request (confirmed: this is the exact call
|
|
54
|
+
# chain reproduced live to root-cause the original bug), so a
|
|
55
|
+
# thread-local flag needs no external store and no expiry logic
|
|
56
|
+
# — Spree::OrderDecorator clears it unconditionally at the start
|
|
57
|
+
# of every create_proposed_shipments call, so a stale flag from
|
|
58
|
+
# an earlier request that errored out before consuming it can
|
|
59
|
+
# never leak into a later, unrelated one.
|
|
60
|
+
self.class.mark_unavailable(package.order.id)
|
|
41
61
|
return nil
|
|
42
62
|
end
|
|
43
63
|
|
|
44
64
|
result.fee_cents / 100.0
|
|
45
65
|
end
|
|
46
66
|
|
|
67
|
+
def self.mark_unavailable(order_id)
|
|
68
|
+
(Thread.current[:spree_doordash_quote_unavailable_order_ids] ||= []) << order_id
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def self.unavailable?(order_id)
|
|
72
|
+
Thread.current[:spree_doordash_quote_unavailable_order_ids]&.include?(order_id) || false
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.clear_unavailable(order_id)
|
|
76
|
+
Thread.current[:spree_doordash_quote_unavailable_order_ids]&.delete(order_id)
|
|
77
|
+
end
|
|
78
|
+
|
|
47
79
|
# Called by Estimator to filter which shipping methods even attempt
|
|
48
80
|
# a compute_package call. Skips the DoorDash API round-trip entirely
|
|
49
81
|
# for an order with no ship address yet (early checkout, before
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
# Bridges Spree::Calculator::Shipping::DoordashQuote#compute_package's
|
|
3
|
+
# doordash_quote_unavailable warning back onto the real order object.
|
|
4
|
+
#
|
|
5
|
+
# A real bug found live (confirmed via object_id tracing against
|
|
6
|
+
# production, not assumed): `compute_package` receives a
|
|
7
|
+
# `Spree::Stock::Package`, and `package.order` is NOT the same in-memory
|
|
8
|
+
# object as `self` in `create_proposed_shipments` below. spree_core's own
|
|
9
|
+
# `Spree::Stock::InventoryUnitBuilder#units` builds each inventory unit
|
|
10
|
+
# with `order_id: @order.id` but deliberately *not* `order: @order` — its
|
|
11
|
+
# own comment says why: "avoid loading the association to order until
|
|
12
|
+
# needed." The first thing that touches `.order` on one of those units (or
|
|
13
|
+
# a Package built from them) triggers a fresh `Spree::Order.find`, a
|
|
14
|
+
# brand-new Ruby object. So `package.order.warnings |= [...]` inside the
|
|
15
|
+
# calculator was mutating a throwaway copy that's discarded the instant
|
|
16
|
+
# `compute_package` returns — the warning never reached the order object
|
|
17
|
+
# this request actually serializes back to the storefront as
|
|
18
|
+
# `cart.warnings`. `spree_doordash` v0.1.2's warning never worked in
|
|
19
|
+
# production despite passing its own specs (the dummy app's specs call
|
|
20
|
+
# the calculator directly against a single order instance, which can't
|
|
21
|
+
# exhibit this — it only shows up through the real
|
|
22
|
+
# create_proposed_shipments -> order_routing_strategy -> Estimator path).
|
|
23
|
+
#
|
|
24
|
+
# Fix: since Ruby object identity doesn't survive that boundary, bridge
|
|
25
|
+
# across it with the order's stable id instead, via a thread-local flag
|
|
26
|
+
# (see DoordashQuote.mark_unavailable/unavailable?/clear_unavailable for
|
|
27
|
+
# why Thread.current was chosen over Rails.cache). Cleared unconditionally
|
|
28
|
+
# at the *start* of every call — not just after a successful merge — so a
|
|
29
|
+
# stale flag left behind by an earlier request that raised before
|
|
30
|
+
# reaching the merge step can never leak into a later, unrelated
|
|
31
|
+
# create_proposed_shipments call that happens to reuse the same thread.
|
|
32
|
+
module OrderDecorator
|
|
33
|
+
def create_proposed_shipments
|
|
34
|
+
Spree::Calculator::Shipping::DoordashQuote.clear_unavailable(id)
|
|
35
|
+
result = super
|
|
36
|
+
merge_doordash_quote_warning!
|
|
37
|
+
result
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def merge_doordash_quote_warning!
|
|
43
|
+
return unless Spree::Calculator::Shipping::DoordashQuote.unavailable?(id)
|
|
44
|
+
|
|
45
|
+
Spree::Calculator::Shipping::DoordashQuote.clear_unavailable(id)
|
|
46
|
+
self.warnings |= [{
|
|
47
|
+
code: 'doordash_quote_unavailable',
|
|
48
|
+
message: 'We could not get a DoorDash delivery quote for this address.'
|
|
49
|
+
}]
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
Order.prepend OrderDecorator
|
|
54
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: spree_doordash
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Amit Solanki
|
|
@@ -120,6 +120,7 @@ files:
|
|
|
120
120
|
- app/jobs/spree_doordash/delivery_dispatch_job.rb
|
|
121
121
|
- app/jobs/spree_doordash/delivery_webhook_job.rb
|
|
122
122
|
- app/models/spree/calculator/shipping/doordash_quote.rb
|
|
123
|
+
- app/models/spree/order_decorator.rb
|
|
123
124
|
- app/models/spree_doordash/credential.rb
|
|
124
125
|
- app/models/spree_doordash/delivery_mapping.rb
|
|
125
126
|
- app/models/spree_doordash/location_mapping.rb
|