spree_api 5.4.0.beta3 → 5.4.0.beta4
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/app/controllers/concerns/spree/api/v3/error_handler.rb +2 -0
- data/app/controllers/concerns/spree/api/v3/http_caching.rb +7 -7
- data/app/controllers/concerns/spree/api/v3/order_lock.rb +42 -0
- data/app/controllers/concerns/spree/api/v3/resource_serializer.rb +7 -7
- data/app/controllers/spree/api/v3/resource_controller.rb +7 -1
- data/app/controllers/spree/api/v3/store/markets/countries_controller.rb +39 -0
- data/app/controllers/spree/api/v3/store/markets_controller.rb +42 -0
- data/app/controllers/spree/api/v3/store/orders/coupon_codes_controller.rb +18 -13
- data/app/controllers/spree/api/v3/store/orders/line_items_controller.rb +43 -36
- data/app/controllers/spree/api/v3/store/orders/shipments_controller.rb +9 -6
- data/app/controllers/spree/api/v3/store/orders/store_credits_controller.rb +18 -13
- data/app/controllers/spree/api/v3/store/orders_controller.rb +37 -28
- data/app/controllers/spree/api/v3/store/products_controller.rb +31 -12
- data/app/serializers/spree/api/v3/address_serializer.rb +3 -2
- data/app/serializers/spree/api/v3/admin/customer_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/order_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/product_serializer.rb +4 -4
- data/app/serializers/spree/api/v3/admin/taxon_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/taxonomy_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/variant_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/base_serializer.rb +9 -9
- data/app/serializers/spree/api/v3/country_serializer.rb +7 -18
- data/app/serializers/spree/api/v3/market_serializer.rb +23 -0
- data/app/serializers/spree/api/v3/order_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/product_serializer.rb +8 -8
- data/app/serializers/spree/api/v3/taxon_serializer.rb +8 -8
- data/app/serializers/spree/api/v3/taxonomy_serializer.rb +6 -6
- data/app/serializers/spree/api/v3/variant_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/wishlist_serializer.rb +1 -1
- data/app/services/spree/api/v3/filters_aggregator.rb +8 -21
- data/config/routes.rb +8 -0
- data/lib/spree/api/dependencies.rb +1 -0
- metadata +10 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e8154a8dd735a006cee415621ff4d95bfdfb4f30935e139bcc72b3d665868ae3
|
|
4
|
+
data.tar.gz: d013be2887432f12fd2dc3440aa14d7fd5d831ebdedc4f814c93c6925dc6b450
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ec930921c59d1e904c643ae363efa3cd40c634567ab7a1daf696e35014efae10e6197c0b3f657d0ff537a05ed36b165e34316eb11a25a83fe2d5352793d0afb2
|
|
7
|
+
data.tar.gz: 92175956237d07cbf778b29d7bb2bd562f0e39cbef764d9f608e01c69c849fdc648727750f52a2370d228a8e79df7080d1c84e2802f585ac1ca2303a36d8acb6
|
|
@@ -23,6 +23,7 @@ module Spree
|
|
|
23
23
|
order_cannot_transition: 'order_cannot_transition',
|
|
24
24
|
order_empty: 'order_empty',
|
|
25
25
|
order_invalid_state: 'order_invalid_state',
|
|
26
|
+
order_already_updated: 'order_already_updated',
|
|
26
27
|
|
|
27
28
|
# Line item errors
|
|
28
29
|
line_item_not_found: 'line_item_not_found',
|
|
@@ -192,6 +193,7 @@ module Spree
|
|
|
192
193
|
)
|
|
193
194
|
end
|
|
194
195
|
|
|
196
|
+
|
|
195
197
|
private
|
|
196
198
|
|
|
197
199
|
# Format validation errors for details field
|
|
@@ -12,7 +12,7 @@ module Spree
|
|
|
12
12
|
extend ActiveSupport::Concern
|
|
13
13
|
|
|
14
14
|
included do
|
|
15
|
-
|
|
15
|
+
after_action :set_vary_headers
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
protected
|
|
@@ -69,15 +69,15 @@ module Spree
|
|
|
69
69
|
private
|
|
70
70
|
|
|
71
71
|
# Build a cache key for a collection
|
|
72
|
-
# Includes: query params, pagination,
|
|
73
|
-
# Strips order to avoid PostgreSQL errors with DISTINCT + subquery ORDER BY expressions
|
|
72
|
+
# Includes: latest updated_at, total count, query params, pagination, expand, currency, locale
|
|
74
73
|
def collection_cache_key(collection)
|
|
75
74
|
parts = [
|
|
76
|
-
collection.
|
|
77
|
-
|
|
78
|
-
params[:
|
|
75
|
+
collection.map(&:updated_at).max&.to_i,
|
|
76
|
+
@pagy&.count,
|
|
77
|
+
params[:expand],
|
|
78
|
+
params[:q]&.to_json,
|
|
79
79
|
params[:page],
|
|
80
|
-
params[:
|
|
80
|
+
params[:limit],
|
|
81
81
|
current_currency,
|
|
82
82
|
current_locale
|
|
83
83
|
]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module OrderLock
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do
|
|
8
|
+
rescue_from ActiveRecord::Deadlocked, with: :handle_order_lock_conflict
|
|
9
|
+
rescue_from ActiveRecord::LockWaitTimeout, with: :handle_order_lock_conflict
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def with_order_lock
|
|
15
|
+
order = @order || @parent
|
|
16
|
+
|
|
17
|
+
order.with_lock do
|
|
18
|
+
# Persist increment within the transaction so reloads inside yield see the new version
|
|
19
|
+
new_version = order.state_lock_version + 1
|
|
20
|
+
order.update_column(:state_lock_version, new_version)
|
|
21
|
+
|
|
22
|
+
yield
|
|
23
|
+
|
|
24
|
+
if performed? && response.status >= 400
|
|
25
|
+
# Operation failed — revert the increment
|
|
26
|
+
order.update_column(:state_lock_version, new_version - 1)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def handle_order_lock_conflict(exception)
|
|
32
|
+
Rails.error.report(exception, context: { order_id: (@order || @parent)&.id }, source: 'spree.api.v3')
|
|
33
|
+
render_error(
|
|
34
|
+
code: Spree::Api::V3::ErrorHandler::ERROR_CODES[:order_already_updated],
|
|
35
|
+
message: Spree.t(:order_already_updated),
|
|
36
|
+
status: :conflict
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -23,17 +23,17 @@ module Spree
|
|
|
23
23
|
store: current_store,
|
|
24
24
|
user: current_user,
|
|
25
25
|
locale: current_locale,
|
|
26
|
-
|
|
26
|
+
expand: expand_list
|
|
27
27
|
}
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
# Parse
|
|
31
|
-
# Supports: ?
|
|
32
|
-
def
|
|
33
|
-
|
|
34
|
-
return [] unless
|
|
30
|
+
# Parse expand parameter into list
|
|
31
|
+
# Supports: ?expand=variants,images
|
|
32
|
+
def expand_list
|
|
33
|
+
expand_param = params[:expand].presence
|
|
34
|
+
return [] unless expand_param
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
expand_param.to_s.split(',').map(&:strip)
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
end
|
|
@@ -103,6 +103,7 @@ module Spree
|
|
|
103
103
|
end
|
|
104
104
|
|
|
105
105
|
# Override in subclass to disable distinct (e.g., for custom sorting with computed columns)
|
|
106
|
+
# @return [Boolean] whether to apply distinct to the collection
|
|
106
107
|
def collection_distinct?
|
|
107
108
|
true
|
|
108
109
|
end
|
|
@@ -112,6 +113,8 @@ module Spree
|
|
|
112
113
|
collection
|
|
113
114
|
end
|
|
114
115
|
|
|
116
|
+
# Override in subclass to specify collection includes
|
|
117
|
+
# @return [Array<Symbol>] the includes to apply to the collection
|
|
115
118
|
def collection_includes
|
|
116
119
|
[]
|
|
117
120
|
end
|
|
@@ -122,16 +125,19 @@ module Spree
|
|
|
122
125
|
end
|
|
123
126
|
|
|
124
127
|
# Pagination parameters
|
|
128
|
+
# @return [Integer] the current page number
|
|
125
129
|
def page
|
|
126
130
|
params[:page]&.to_i || 1
|
|
127
131
|
end
|
|
128
132
|
|
|
133
|
+
# @return [Integer] the number of items per page
|
|
129
134
|
def limit
|
|
130
|
-
limit_param = params[:
|
|
135
|
+
limit_param = params[:limit]&.to_i || 25
|
|
131
136
|
[limit_param, 100].min # Max 100 per page
|
|
132
137
|
end
|
|
133
138
|
|
|
134
139
|
# Metadata for collection responses
|
|
140
|
+
# @return [Hash] pagination metadata
|
|
135
141
|
def collection_meta(_collection)
|
|
136
142
|
return {} unless @pagy
|
|
137
143
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module Store
|
|
5
|
+
module Markets
|
|
6
|
+
class CountriesController < Store::BaseController
|
|
7
|
+
before_action :load_market
|
|
8
|
+
|
|
9
|
+
# GET /api/v3/store/markets/:market_id/countries
|
|
10
|
+
def index
|
|
11
|
+
countries = @market.countries.order(:name)
|
|
12
|
+
|
|
13
|
+
render json: {
|
|
14
|
+
data: countries.map { |country| serialize_country(country) }
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# GET /api/v3/store/markets/:market_id/countries/:id
|
|
19
|
+
def show
|
|
20
|
+
country = @market.countries.find_by!(iso: params[:id].upcase)
|
|
21
|
+
|
|
22
|
+
render json: serialize_country(country)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def load_market
|
|
28
|
+
@market = current_store.markets.find_by_prefix_id!(params[:market_id])
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def serialize_country(country)
|
|
32
|
+
Spree.api.country_serializer.new(country, params: serializer_params).to_h
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module Store
|
|
5
|
+
class MarketsController < Store::BaseController
|
|
6
|
+
# GET /api/v3/store/markets
|
|
7
|
+
def index
|
|
8
|
+
markets = current_store.markets.includes(:countries).order(:position)
|
|
9
|
+
|
|
10
|
+
render json: {
|
|
11
|
+
data: markets.map { |market| serialize_market(market) }
|
|
12
|
+
}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# GET /api/v3/store/markets/:id
|
|
16
|
+
def show
|
|
17
|
+
market = current_store.markets.includes(:countries).find_by_prefix_id!(params[:id])
|
|
18
|
+
|
|
19
|
+
render json: serialize_market(market)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# GET /api/v3/store/markets/resolve?country=DE
|
|
23
|
+
def resolve
|
|
24
|
+
country_iso = params[:country]&.upcase
|
|
25
|
+
country = Spree::Country.find_by!(iso: country_iso)
|
|
26
|
+
market = current_store.market_for_country(country)
|
|
27
|
+
|
|
28
|
+
raise ActiveRecord::RecordNotFound unless market
|
|
29
|
+
|
|
30
|
+
render json: serialize_market(market)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def serialize_market(market)
|
|
36
|
+
Spree.api.market_serializer.new(market, params: serializer_params.merge(expand: expand_list + ['countries'])).to_h
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -5,6 +5,7 @@ module Spree
|
|
|
5
5
|
module Orders
|
|
6
6
|
class CouponCodesController < ResourceController
|
|
7
7
|
include Spree::Api::V3::OrderConcern
|
|
8
|
+
include Spree::Api::V3::OrderLock
|
|
8
9
|
|
|
9
10
|
before_action :authorize_order_access!
|
|
10
11
|
skip_before_action :set_resource
|
|
@@ -12,14 +13,16 @@ module Spree
|
|
|
12
13
|
# POST /api/v3/store/orders/:order_id/coupon_codes
|
|
13
14
|
# Apply a coupon code to the order
|
|
14
15
|
def create
|
|
15
|
-
|
|
16
|
+
with_order_lock do
|
|
17
|
+
@parent.coupon_code = permitted_params[:code]
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
coupon_handler.apply
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
if coupon_handler.successful?
|
|
22
|
+
render_order(status: :created)
|
|
23
|
+
else
|
|
24
|
+
render_errors(coupon_handler.error)
|
|
25
|
+
end
|
|
23
26
|
end
|
|
24
27
|
end
|
|
25
28
|
|
|
@@ -27,15 +30,17 @@ module Spree
|
|
|
27
30
|
# Remove a coupon code from the order
|
|
28
31
|
# :id is the promotion prefix_id (e.g., promo_xxx)
|
|
29
32
|
def destroy
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
with_order_lock do
|
|
34
|
+
@resource = scope.find_by_prefix_id!(params[:id])
|
|
35
|
+
coupon_code = @resource.code.presence || @resource.name
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
coupon_handler.remove(coupon_code)
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
if coupon_handler.successful?
|
|
40
|
+
render_order
|
|
41
|
+
else
|
|
42
|
+
render_errors(coupon_handler.error)
|
|
43
|
+
end
|
|
39
44
|
end
|
|
40
45
|
end
|
|
41
46
|
|
|
@@ -5,63 +5,70 @@ module Spree
|
|
|
5
5
|
module Orders
|
|
6
6
|
class LineItemsController < ResourceController
|
|
7
7
|
include Spree::Api::V3::OrderConcern
|
|
8
|
+
include Spree::Api::V3::OrderLock
|
|
8
9
|
|
|
9
10
|
skip_before_action :set_resource
|
|
10
11
|
before_action :authorize_order_access!
|
|
11
12
|
|
|
12
13
|
# POST /api/v3/store/orders/:order_id/line_items
|
|
13
14
|
def create
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
with_order_lock do
|
|
16
|
+
result = Spree.cart_add_item_service.call(
|
|
17
|
+
order: @parent,
|
|
18
|
+
variant: variant,
|
|
19
|
+
quantity: permitted_params[:quantity] || 1,
|
|
20
|
+
metadata: permitted_params[:metadata] || {},
|
|
21
|
+
options: permitted_params[:options] || {}
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
if result.success?
|
|
25
|
+
render_order(status: :created)
|
|
26
|
+
else
|
|
27
|
+
render_service_error(result.error, code: ERROR_CODES[:insufficient_stock])
|
|
28
|
+
end
|
|
26
29
|
end
|
|
27
30
|
end
|
|
28
31
|
|
|
29
32
|
# PATCH /api/v3/store/orders/:order_id/line_items/:id
|
|
30
33
|
def update
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
with_order_lock do
|
|
35
|
+
@line_item = scope.find_by_prefix_id!(params[:id])
|
|
36
|
+
|
|
37
|
+
@line_item.metadata = @line_item.metadata.merge(permitted_params[:metadata].to_h) if permitted_params[:metadata].present?
|
|
38
|
+
|
|
39
|
+
if permitted_params[:quantity].present?
|
|
40
|
+
result = Spree.cart_set_item_quantity_service.call(
|
|
41
|
+
order: @parent,
|
|
42
|
+
line_item: @line_item,
|
|
43
|
+
quantity: permitted_params[:quantity]
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if result.success?
|
|
47
|
+
render_order
|
|
48
|
+
else
|
|
49
|
+
render_service_error(result.error, code: ERROR_CODES[:invalid_quantity])
|
|
50
|
+
end
|
|
51
|
+
elsif @line_item.changed?
|
|
52
|
+
@line_item.save!
|
|
43
53
|
render_order
|
|
44
54
|
else
|
|
45
|
-
|
|
55
|
+
render_order
|
|
46
56
|
end
|
|
47
|
-
elsif @line_item.changed?
|
|
48
|
-
@line_item.save!
|
|
49
|
-
render_order
|
|
50
|
-
else
|
|
51
|
-
render_order
|
|
52
57
|
end
|
|
53
58
|
end
|
|
54
59
|
|
|
55
60
|
# DELETE /api/v3/store/orders/:order_id/line_items/:id
|
|
56
61
|
def destroy
|
|
57
|
-
|
|
62
|
+
with_order_lock do
|
|
63
|
+
@line_item = scope.find_by_prefix_id!(params[:id])
|
|
58
64
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
65
|
+
Spree.cart_remove_line_item_service.call(
|
|
66
|
+
order: @parent,
|
|
67
|
+
line_item: @line_item
|
|
68
|
+
)
|
|
63
69
|
|
|
64
|
-
|
|
70
|
+
render_order
|
|
71
|
+
end
|
|
65
72
|
end
|
|
66
73
|
|
|
67
74
|
protected
|
|
@@ -5,6 +5,7 @@ module Spree
|
|
|
5
5
|
module Orders
|
|
6
6
|
class ShipmentsController < ResourceController
|
|
7
7
|
include Spree::Api::V3::OrderConcern
|
|
8
|
+
include Spree::Api::V3::OrderLock
|
|
8
9
|
|
|
9
10
|
before_action :authorize_order_access!
|
|
10
11
|
skip_before_action :set_resource
|
|
@@ -12,13 +13,15 @@ module Spree
|
|
|
12
13
|
|
|
13
14
|
# PATCH /api/v3/store/orders/:order_id/shipments/:id
|
|
14
15
|
def update
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
with_order_lock do
|
|
17
|
+
if permitted_params[:selected_shipping_rate_id].present?
|
|
18
|
+
shipping_rate = @resource.shipping_rates.find_by_prefix_id!(permitted_params[:selected_shipping_rate_id])
|
|
19
|
+
@resource.selected_shipping_rate_id = shipping_rate.id
|
|
20
|
+
@resource.save!
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
render_order
|
|
19
24
|
end
|
|
20
|
-
|
|
21
|
-
render_order
|
|
22
25
|
end
|
|
23
26
|
|
|
24
27
|
protected
|
|
@@ -5,6 +5,7 @@ module Spree
|
|
|
5
5
|
module Orders
|
|
6
6
|
class StoreCreditsController < Store::BaseController
|
|
7
7
|
include Spree::Api::V3::OrderConcern
|
|
8
|
+
include Spree::Api::V3::OrderLock
|
|
8
9
|
|
|
9
10
|
before_action :require_authentication!
|
|
10
11
|
before_action :set_parent
|
|
@@ -12,26 +13,30 @@ module Spree
|
|
|
12
13
|
|
|
13
14
|
# POST /api/v3/store/orders/:order_id/store_credits
|
|
14
15
|
def create
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
with_order_lock do
|
|
17
|
+
result = Spree.checkout_add_store_credit_service.call(
|
|
18
|
+
order: @parent,
|
|
19
|
+
amount: params[:amount].try(:to_f)
|
|
20
|
+
)
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
if result.success?
|
|
23
|
+
render_order
|
|
24
|
+
else
|
|
25
|
+
render_service_error(result.error)
|
|
26
|
+
end
|
|
24
27
|
end
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
# DELETE /api/v3/store/orders/:order_id/store_credits
|
|
28
31
|
def destroy
|
|
29
|
-
|
|
32
|
+
with_order_lock do
|
|
33
|
+
result = Spree.checkout_remove_store_credit_service.call(order: @parent)
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
+
if result.success?
|
|
36
|
+
render_order
|
|
37
|
+
else
|
|
38
|
+
render_service_error(result.error)
|
|
39
|
+
end
|
|
35
40
|
end
|
|
36
41
|
end
|
|
37
42
|
end
|
|
@@ -4,6 +4,7 @@ module Spree
|
|
|
4
4
|
module Store
|
|
5
5
|
class OrdersController < ResourceController
|
|
6
6
|
include Spree::Api::V3::OrderConcern
|
|
7
|
+
include Spree::Api::V3::OrderLock
|
|
7
8
|
|
|
8
9
|
# Skip base controller's set_resource and define our own complete list
|
|
9
10
|
skip_before_action :set_resource
|
|
@@ -20,48 +21,56 @@ module Spree
|
|
|
20
21
|
# }
|
|
21
22
|
#
|
|
22
23
|
def update
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
with_order_lock do
|
|
25
|
+
result = Spree::Api::V3::Orders::Update.call(
|
|
26
|
+
order: @order,
|
|
27
|
+
params: order_params
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
if result.success?
|
|
31
|
+
render json: serialize_resource(@order.reload)
|
|
32
|
+
else
|
|
33
|
+
render_service_error(result.error, code: ERROR_CODES[:validation_error])
|
|
34
|
+
end
|
|
32
35
|
end
|
|
33
36
|
end
|
|
34
37
|
|
|
35
38
|
# PATCH /api/v3/store/orders/:id/next
|
|
36
39
|
def next
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
with_order_lock do
|
|
41
|
+
result = Spree.checkout_next_service.call(order: @order)
|
|
42
|
+
|
|
43
|
+
if result.success?
|
|
44
|
+
render json: serialize_resource(@order)
|
|
45
|
+
else
|
|
46
|
+
render_service_error(result.error, code: ERROR_CODES[:order_cannot_transition])
|
|
47
|
+
end
|
|
43
48
|
end
|
|
44
49
|
end
|
|
45
50
|
|
|
46
51
|
# PATCH /api/v3/store/orders/:id/advance
|
|
47
52
|
def advance
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
with_order_lock do
|
|
54
|
+
result = Spree.checkout_advance_service.call(order: @order)
|
|
55
|
+
|
|
56
|
+
if result.success?
|
|
57
|
+
render json: serialize_resource(@order)
|
|
58
|
+
else
|
|
59
|
+
render_service_error(result.error, code: ERROR_CODES[:order_cannot_transition])
|
|
60
|
+
end
|
|
54
61
|
end
|
|
55
62
|
end
|
|
56
63
|
|
|
57
64
|
# PATCH /api/v3/store/orders/:id/complete
|
|
58
65
|
def complete
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
66
|
+
with_order_lock do
|
|
67
|
+
result = Spree.checkout_complete_service.call(order: @order)
|
|
68
|
+
|
|
69
|
+
if result.success?
|
|
70
|
+
render json: serialize_resource(@order)
|
|
71
|
+
else
|
|
72
|
+
render_service_error(result.error, code: ERROR_CODES[:order_already_completed])
|
|
73
|
+
end
|
|
65
74
|
end
|
|
66
75
|
end
|
|
67
76
|
|
|
@@ -117,7 +126,7 @@ module Spree
|
|
|
117
126
|
[
|
|
118
127
|
:id, :firstname, :lastname, :address1, :address2,
|
|
119
128
|
:city, :zipcode, :phone, :company,
|
|
120
|
-
:country_iso, :state_abbr, :state_name
|
|
129
|
+
:country_iso, :state_abbr, :state_name, :quick_checkout
|
|
121
130
|
]
|
|
122
131
|
end
|
|
123
132
|
end
|
|
@@ -3,9 +3,11 @@ module Spree
|
|
|
3
3
|
module V3
|
|
4
4
|
module Store
|
|
5
5
|
class ProductsController < ResourceController
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
'price
|
|
6
|
+
# Sort values that require special scopes (not plain Ransack column sorts).
|
|
7
|
+
CUSTOM_SORT_SCOPES = {
|
|
8
|
+
'price asc' => :ascend_by_price,
|
|
9
|
+
'price desc' => :descend_by_price,
|
|
10
|
+
'best_selling' => :by_best_selling
|
|
9
11
|
}.freeze
|
|
10
12
|
|
|
11
13
|
protected
|
|
@@ -48,24 +50,41 @@ module Spree
|
|
|
48
50
|
!custom_sort_requested?
|
|
49
51
|
end
|
|
50
52
|
|
|
51
|
-
#
|
|
53
|
+
# Applies sorting from the unified `sort` param.
|
|
54
|
+
# Custom values ('price asc', 'best_selling') use product-specific scopes.
|
|
55
|
+
# Standard Ransack values ('name asc', 'created_at desc') are passed to q[s].
|
|
52
56
|
def apply_collection_sort(collection)
|
|
53
|
-
|
|
54
|
-
return collection unless
|
|
57
|
+
sort_value = sort_param
|
|
58
|
+
return collection unless sort_value.present?
|
|
55
59
|
|
|
56
|
-
|
|
60
|
+
scope_method = CUSTOM_SORT_SCOPES[sort_value]
|
|
61
|
+
return collection unless scope_method
|
|
57
62
|
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
sorted = collection.reorder(nil)
|
|
64
|
+
sort_value == 'best_selling' ? sorted.distinct(false).send(scope_method) : sorted.send(scope_method)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Inject sort into ransack params when it's a standard Ransack sort
|
|
68
|
+
def ransack_params
|
|
69
|
+
rp = super
|
|
70
|
+
sort_value = sort_param
|
|
71
|
+
|
|
72
|
+
if sort_value.present? && !CUSTOM_SORT_SCOPES.key?(sort_value)
|
|
73
|
+
rp = rp.respond_to?(:to_unsafe_h) ? rp.to_unsafe_h : rp.dup
|
|
74
|
+
rp['s'] = sort_value
|
|
75
|
+
end
|
|
60
76
|
|
|
61
|
-
|
|
77
|
+
rp
|
|
62
78
|
end
|
|
63
79
|
|
|
64
80
|
private
|
|
65
81
|
|
|
82
|
+
def sort_param
|
|
83
|
+
params[:sort] || params.dig(:q, :s)
|
|
84
|
+
end
|
|
85
|
+
|
|
66
86
|
def custom_sort_requested?
|
|
67
|
-
|
|
68
|
-
SORT_OPTIONS.key?(sort_by)
|
|
87
|
+
CUSTOM_SORT_SCOPES.key?(sort_param)
|
|
69
88
|
end
|
|
70
89
|
end
|
|
71
90
|
end
|
|
@@ -6,11 +6,12 @@ module Spree
|
|
|
6
6
|
address1: [:string, nullable: true], address2: [:string, nullable: true],
|
|
7
7
|
city: [:string, nullable: true], zipcode: [:string, nullable: true], phone: [:string, nullable: true],
|
|
8
8
|
company: [:string, nullable: true], state_abbr: [:string, nullable: true], state_name: [:string, nullable: true],
|
|
9
|
-
state_text: [:string, nullable: true], country_iso: :string, country_name: :string
|
|
9
|
+
state_text: [:string, nullable: true], country_iso: :string, country_name: :string,
|
|
10
|
+
quick_checkout: :boolean
|
|
10
11
|
|
|
11
12
|
attributes :firstname, :lastname, :full_name, :address1, :address2,
|
|
12
13
|
:city, :zipcode, :phone, :company, :country_name, :country_iso, :state_text,
|
|
13
|
-
:state_abbr
|
|
14
|
+
:state_abbr, :quick_checkout
|
|
14
15
|
|
|
15
16
|
# State name - used for countries without predefined states
|
|
16
17
|
attribute :state_name do |address|
|
|
@@ -33,7 +33,7 @@ module Spree
|
|
|
33
33
|
|
|
34
34
|
many :orders,
|
|
35
35
|
resource: Spree.api.admin_order_serializer,
|
|
36
|
-
if: proc { params[:
|
|
36
|
+
if: proc { params[:expand]&.include?('orders') }
|
|
37
37
|
|
|
38
38
|
# TODO: Add store_credits association when Admin API is implemented
|
|
39
39
|
end
|
|
@@ -36,7 +36,7 @@ module Spree
|
|
|
36
36
|
|
|
37
37
|
one :user,
|
|
38
38
|
resource: Spree.api.admin_customer_serializer,
|
|
39
|
-
if: proc { params[:
|
|
39
|
+
if: proc { params[:expand]&.include?('user') }
|
|
40
40
|
|
|
41
41
|
# TODO: Add adjustments associations when Admin API is implemented
|
|
42
42
|
end
|
|
@@ -26,20 +26,20 @@ module Spree
|
|
|
26
26
|
# Admin uses admin variant serializer
|
|
27
27
|
many :variants,
|
|
28
28
|
resource: Spree.api.admin_variant_serializer,
|
|
29
|
-
if: proc { params[:
|
|
29
|
+
if: proc { params[:expand]&.include?('variants') }
|
|
30
30
|
|
|
31
31
|
one :default_variant,
|
|
32
32
|
resource: Spree.api.admin_variant_serializer,
|
|
33
|
-
if: proc { params[:
|
|
33
|
+
if: proc { params[:expand]&.include?('default_variant') }
|
|
34
34
|
|
|
35
35
|
one :master,
|
|
36
36
|
key: :master_variant,
|
|
37
37
|
resource: Spree.api.admin_variant_serializer,
|
|
38
|
-
if: proc { params[:
|
|
38
|
+
if: proc { params[:expand]&.include?('master_variant') }
|
|
39
39
|
|
|
40
40
|
many :metafields,
|
|
41
41
|
resource: Spree.api.admin_metafield_serializer,
|
|
42
|
-
if: proc { params[:
|
|
42
|
+
if: proc { params[:expand]&.include?('metafields') }
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
end
|
|
@@ -7,7 +7,7 @@ module Spree
|
|
|
7
7
|
class TaxonomySerializer < V3::TaxonomySerializer
|
|
8
8
|
many :metafields,
|
|
9
9
|
resource: Spree.api.admin_metafield_serializer,
|
|
10
|
-
if: proc { params[:
|
|
10
|
+
if: proc { params[:expand]&.include?('metafields') }
|
|
11
11
|
end
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -30,11 +30,11 @@ module Spree
|
|
|
30
30
|
# All prices for this variant (for admin management)
|
|
31
31
|
many :prices,
|
|
32
32
|
resource: Spree.api.admin_price_serializer,
|
|
33
|
-
if: proc { params[:
|
|
33
|
+
if: proc { params[:expand]&.include?('prices') }
|
|
34
34
|
|
|
35
35
|
many :metafields,
|
|
36
36
|
resource: Spree.api.admin_metafield_serializer,
|
|
37
|
-
if: proc { params[:
|
|
37
|
+
if: proc { params[:expand]&.include?('metafields') }
|
|
38
38
|
|
|
39
39
|
# TODO: Add stock_items association when Admin API is implemented
|
|
40
40
|
end
|
|
@@ -33,24 +33,24 @@ module Spree
|
|
|
33
33
|
params[:locale]
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
def
|
|
37
|
-
@
|
|
36
|
+
def expands
|
|
37
|
+
@expands ||= Array(params[:expand] || [])
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
# Check if an association should be
|
|
41
|
-
def
|
|
42
|
-
|
|
40
|
+
# Check if an association should be expanded
|
|
41
|
+
def expand?(name)
|
|
42
|
+
expands.include?(name.to_s)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
# Get nested
|
|
46
|
-
def
|
|
45
|
+
# Get nested expands for a given parent
|
|
46
|
+
def nested_expands_for(parent)
|
|
47
47
|
prefix = "#{parent}."
|
|
48
|
-
|
|
48
|
+
expands.select { |i| i.start_with?(prefix) }.map { |i| i.sub(prefix, '') }
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
# Build nested params for child serializers
|
|
52
52
|
def nested_params(parent = nil)
|
|
53
|
-
params.merge(
|
|
53
|
+
params.merge(expand: parent ? nested_expands_for(parent) : [])
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
# Returns price for a variant using full Price List resolution
|
|
@@ -5,30 +5,19 @@ module Spree
|
|
|
5
5
|
include Alba::Resource
|
|
6
6
|
include Typelizer::DSL
|
|
7
7
|
|
|
8
|
-
# ISO 3166-1 codes - iso is the identifier, no redundant id field
|
|
9
8
|
typelize iso: :string, iso3: :string, name: :string,
|
|
10
|
-
states_required: :boolean, zipcode_required: :boolean
|
|
11
|
-
currency: [:string, nullable: true],
|
|
12
|
-
default_locale: [:string, nullable: true],
|
|
13
|
-
supported_locales: [:string, multi: true]
|
|
9
|
+
states_required: :boolean, zipcode_required: :boolean
|
|
14
10
|
|
|
15
11
|
attributes :iso, :iso3, :name, :states_required, :zipcode_required
|
|
16
12
|
|
|
17
|
-
attribute :currency do |country|
|
|
18
|
-
country.market_currency
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
attribute :default_locale do |country|
|
|
22
|
-
country.market_locale
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
attribute :supported_locales do |country|
|
|
26
|
-
country.market_supported_locales
|
|
27
|
-
end
|
|
28
|
-
|
|
29
13
|
many :states,
|
|
30
14
|
resource: Spree.api.state_serializer,
|
|
31
|
-
if: proc { params[:
|
|
15
|
+
if: proc { params[:expand]&.include?('states') }
|
|
16
|
+
|
|
17
|
+
attribute :market, if: proc { params[:expand]&.include?('market') } do |country|
|
|
18
|
+
m = country.current_market
|
|
19
|
+
m ? Spree.api.market_serializer.new(m, params: params).to_h : nil
|
|
20
|
+
end
|
|
32
21
|
end
|
|
33
22
|
end
|
|
34
23
|
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
class MarketSerializer < BaseSerializer
|
|
5
|
+
typelize name: :string, currency: :string,
|
|
6
|
+
default_locale: :string,
|
|
7
|
+
supported_locales: [:string, multi: true],
|
|
8
|
+
tax_inclusive: :boolean,
|
|
9
|
+
default: :boolean
|
|
10
|
+
|
|
11
|
+
attributes :name, :currency, :default_locale, :tax_inclusive, :default
|
|
12
|
+
|
|
13
|
+
attribute :supported_locales do |market|
|
|
14
|
+
market.supported_locales_list
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
many :countries,
|
|
18
|
+
resource: Spree.api.country_serializer,
|
|
19
|
+
if: proc { expand?(:countries) }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -6,7 +6,7 @@ module Spree
|
|
|
6
6
|
class OrderSerializer < BaseSerializer
|
|
7
7
|
typelize number: :string, state: :string, token: :string, email: [:string, nullable: true],
|
|
8
8
|
special_instructions: [:string, nullable: true], currency: :string, locale: [:string, nullable: true], item_count: :number,
|
|
9
|
-
shipment_state: [:string, nullable: true], payment_state: [:string, nullable: true],
|
|
9
|
+
state_lock_version: :number, shipment_state: [:string, nullable: true], payment_state: [:string, nullable: true],
|
|
10
10
|
item_total: :string, display_item_total: :string,
|
|
11
11
|
ship_total: :string, display_ship_total: :string,
|
|
12
12
|
adjustment_total: :string, display_adjustment_total: :string,
|
|
@@ -18,7 +18,7 @@ module Spree
|
|
|
18
18
|
bill_address: { nullable: true }, ship_address: { nullable: true }
|
|
19
19
|
|
|
20
20
|
attributes :number, :state, :token, :email, :special_instructions,
|
|
21
|
-
:currency, :locale, :item_count, :shipment_state, :payment_state,
|
|
21
|
+
:currency, :locale, :item_count, :state_lock_version, :shipment_state, :payment_state,
|
|
22
22
|
:item_total, :display_item_total, :ship_total, :display_ship_total,
|
|
23
23
|
:adjustment_total, :display_adjustment_total, :promo_total, :display_promo_total,
|
|
24
24
|
:tax_total, :display_tax_total, :included_tax_total, :display_included_tax_total,
|
|
@@ -71,37 +71,37 @@ module Spree
|
|
|
71
71
|
many :variant_images,
|
|
72
72
|
key: :images,
|
|
73
73
|
resource: Spree.api.image_serializer,
|
|
74
|
-
if: proc { params[:
|
|
74
|
+
if: proc { params[:expand]&.include?('images') }
|
|
75
75
|
|
|
76
76
|
many :variants,
|
|
77
77
|
resource: Spree.api.variant_serializer,
|
|
78
|
-
if: proc { params[:
|
|
78
|
+
if: proc { params[:expand]&.include?('variants') }
|
|
79
79
|
|
|
80
80
|
one :default_variant,
|
|
81
81
|
resource: Spree.api.variant_serializer,
|
|
82
|
-
if: proc { params[:
|
|
82
|
+
if: proc { params[:expand]&.include?('default_variant') }
|
|
83
83
|
|
|
84
84
|
one :master,
|
|
85
85
|
key: :master_variant,
|
|
86
86
|
resource: Spree.api.variant_serializer,
|
|
87
|
-
if: proc { params[:
|
|
87
|
+
if: proc { params[:expand]&.include?('master_variant') }
|
|
88
88
|
|
|
89
89
|
many :option_types,
|
|
90
90
|
resource: Spree.api.option_type_serializer,
|
|
91
|
-
if: proc { params[:
|
|
91
|
+
if: proc { params[:expand]&.include?('option_types') }
|
|
92
92
|
|
|
93
93
|
many :taxons,
|
|
94
94
|
proc { |taxons, params|
|
|
95
95
|
taxons.select { |t| t.taxonomy.store_id == params[:store].id }
|
|
96
96
|
},
|
|
97
97
|
resource: Spree.api.taxon_serializer,
|
|
98
|
-
if: proc { params[:
|
|
99
|
-
params: {
|
|
98
|
+
if: proc { params[:expand]&.include?('taxons') },
|
|
99
|
+
params: { expand: [] }
|
|
100
100
|
|
|
101
101
|
many :public_metafields,
|
|
102
102
|
key: :metafields,
|
|
103
103
|
resource: Spree.api.metafield_serializer,
|
|
104
|
-
if: proc { params[:
|
|
104
|
+
if: proc { params[:expand]&.include?('metafields') }
|
|
105
105
|
end
|
|
106
106
|
end
|
|
107
107
|
end
|
|
@@ -51,27 +51,27 @@ module Spree
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
# Conditional associations
|
|
54
|
-
# Note: We pass empty
|
|
54
|
+
# Note: We pass empty expand to nested taxons to prevent infinite recursion
|
|
55
55
|
# (e.g., ancestors trying to load their own ancestors)
|
|
56
56
|
one :parent,
|
|
57
57
|
resource: Spree.api.taxon_serializer,
|
|
58
|
-
if: proc { params[:
|
|
59
|
-
params: {
|
|
58
|
+
if: proc { params[:expand]&.include?('parent') },
|
|
59
|
+
params: { expand: [] }
|
|
60
60
|
|
|
61
61
|
many :children,
|
|
62
62
|
resource: Spree.api.taxon_serializer,
|
|
63
|
-
if: proc { params[:
|
|
64
|
-
params: {
|
|
63
|
+
if: proc { params[:expand]&.include?('children') },
|
|
64
|
+
params: { expand: [] }
|
|
65
65
|
|
|
66
66
|
many :ancestors,
|
|
67
67
|
resource: Spree.api.taxon_serializer,
|
|
68
|
-
if: proc { params[:
|
|
69
|
-
params: {
|
|
68
|
+
if: proc { params[:expand]&.include?('ancestors') },
|
|
69
|
+
params: { expand: [] }
|
|
70
70
|
|
|
71
71
|
many :public_metafields,
|
|
72
72
|
key: :metafields,
|
|
73
73
|
resource: Spree.api.metafield_serializer,
|
|
74
|
-
if: proc { params[:
|
|
74
|
+
if: proc { params[:expand]&.include?('metafields') }
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
77
|
end
|
|
@@ -12,21 +12,21 @@ module Spree
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
# Conditional associations
|
|
15
|
-
# Note: We pass empty
|
|
15
|
+
# Note: We pass empty expand to nested taxons to prevent infinite recursion
|
|
16
16
|
one :root,
|
|
17
17
|
resource: Spree.api.taxon_serializer,
|
|
18
|
-
if: proc { params[:
|
|
19
|
-
params: {
|
|
18
|
+
if: proc { params[:expand]&.include?('root') },
|
|
19
|
+
params: { expand: [] }
|
|
20
20
|
|
|
21
21
|
many :taxons,
|
|
22
22
|
resource: Spree.api.taxon_serializer,
|
|
23
|
-
if: proc { params[:
|
|
24
|
-
params: {
|
|
23
|
+
if: proc { params[:expand]&.include?('taxons') },
|
|
24
|
+
params: { expand: [] }
|
|
25
25
|
|
|
26
26
|
many :public_metafields,
|
|
27
27
|
key: :metafields,
|
|
28
28
|
resource: Spree.api.metafield_serializer,
|
|
29
|
-
if: proc { params[:
|
|
29
|
+
if: proc { params[:expand]&.include?('metafields') }
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
|
@@ -72,14 +72,14 @@ module Spree
|
|
|
72
72
|
# Conditional associations
|
|
73
73
|
many :images,
|
|
74
74
|
resource: Spree.api.image_serializer,
|
|
75
|
-
if: proc { params[:
|
|
75
|
+
if: proc { params[:expand]&.include?('images') }
|
|
76
76
|
|
|
77
77
|
many :option_values, resource: Spree.api.option_value_serializer
|
|
78
78
|
|
|
79
79
|
many :public_metafields,
|
|
80
80
|
key: :metafields,
|
|
81
81
|
resource: Spree.api.metafield_serializer,
|
|
82
|
-
if: proc { params[:
|
|
82
|
+
if: proc { params[:expand]&.include?('metafields') }
|
|
83
83
|
end
|
|
84
84
|
end
|
|
85
85
|
end
|
|
@@ -2,16 +2,7 @@ module Spree
|
|
|
2
2
|
module Api
|
|
3
3
|
module V3
|
|
4
4
|
class FiltersAggregator
|
|
5
|
-
SORT_OPTION_IDS =
|
|
6
|
-
manual
|
|
7
|
-
best-selling
|
|
8
|
-
price-low-to-high
|
|
9
|
-
price-high-to-low
|
|
10
|
-
newest-first
|
|
11
|
-
oldest-first
|
|
12
|
-
name-a-z
|
|
13
|
-
name-z-a
|
|
14
|
-
].freeze
|
|
5
|
+
SORT_OPTION_IDS = Spree::Taxon::SORT_ORDERS
|
|
15
6
|
|
|
16
7
|
# @param scope [ActiveRecord::Relation] Base product scope (already filtered by store, availability, taxon, etc.)
|
|
17
8
|
# @param currency [String] Currency for price range
|
|
@@ -43,11 +34,10 @@ module Spree
|
|
|
43
34
|
end
|
|
44
35
|
|
|
45
36
|
def sort_options
|
|
46
|
-
SORT_OPTION_IDS.map
|
|
47
|
-
{ id: id, label: Spree.t("products_sort_options.#{id.underscore}") }
|
|
48
|
-
end
|
|
37
|
+
SORT_OPTION_IDS.map { |id| { id: id } }
|
|
49
38
|
end
|
|
50
39
|
|
|
40
|
+
|
|
51
41
|
def price_filter
|
|
52
42
|
# Remove ordering to avoid PostgreSQL DISTINCT + ORDER BY conflicts
|
|
53
43
|
prices = Spree::Price.for_products(@scope.reorder(''), @currency)
|
|
@@ -58,7 +48,6 @@ module Spree
|
|
|
58
48
|
{
|
|
59
49
|
id: 'price',
|
|
60
50
|
type: 'price_range',
|
|
61
|
-
label: Spree.t(:price),
|
|
62
51
|
min: min.to_f,
|
|
63
52
|
max: max.to_f,
|
|
64
53
|
currency: @currency
|
|
@@ -74,10 +63,9 @@ module Spree
|
|
|
74
63
|
{
|
|
75
64
|
id: 'availability',
|
|
76
65
|
type: 'availability',
|
|
77
|
-
label: Spree.t(:availability),
|
|
78
66
|
options: [
|
|
79
|
-
{ id: 'in_stock',
|
|
80
|
-
{ id: 'out_of_stock',
|
|
67
|
+
{ id: 'in_stock', count: in_stock_count },
|
|
68
|
+
{ id: 'out_of_stock', count: out_of_stock_count }
|
|
81
69
|
]
|
|
82
70
|
}
|
|
83
71
|
end
|
|
@@ -90,8 +78,8 @@ module Spree
|
|
|
90
78
|
{
|
|
91
79
|
id: option_type.prefixed_id,
|
|
92
80
|
type: 'option',
|
|
93
|
-
label: option_type.presentation,
|
|
94
81
|
name: option_type.name,
|
|
82
|
+
presentation: option_type.presentation,
|
|
95
83
|
options: values.map { |ov| option_value_data(option_type, ov) }
|
|
96
84
|
}
|
|
97
85
|
end
|
|
@@ -110,8 +98,8 @@ module Spree
|
|
|
110
98
|
|
|
111
99
|
{
|
|
112
100
|
id: option_value.prefixed_id,
|
|
113
|
-
label: option_value.presentation,
|
|
114
101
|
name: option_value.name,
|
|
102
|
+
presentation: option_value.presentation,
|
|
115
103
|
position: option_value.position,
|
|
116
104
|
count: count
|
|
117
105
|
}
|
|
@@ -135,7 +123,6 @@ module Spree
|
|
|
135
123
|
{
|
|
136
124
|
id: 'taxons',
|
|
137
125
|
type: 'taxon',
|
|
138
|
-
label: Spree.t(:category),
|
|
139
126
|
options: child_taxons.map { |t| taxon_option_data(t) }
|
|
140
127
|
}
|
|
141
128
|
end
|
|
@@ -145,7 +132,7 @@ module Spree
|
|
|
145
132
|
|
|
146
133
|
{
|
|
147
134
|
id: taxon.prefixed_id,
|
|
148
|
-
|
|
135
|
+
name: taxon.name,
|
|
149
136
|
permalink: taxon.permalink,
|
|
150
137
|
count: count
|
|
151
138
|
}
|
data/config/routes.rb
CHANGED
|
@@ -11,6 +11,14 @@ Spree::Core::Engine.add_routes do
|
|
|
11
11
|
# Store
|
|
12
12
|
resource :store, only: [:show]
|
|
13
13
|
|
|
14
|
+
# Markets
|
|
15
|
+
resources :markets, only: [:index, :show] do
|
|
16
|
+
collection do
|
|
17
|
+
get :resolve
|
|
18
|
+
end
|
|
19
|
+
resources :countries, only: [:index, :show], controller: 'markets/countries'
|
|
20
|
+
end
|
|
21
|
+
|
|
14
22
|
# Countries, Currencies, Locales (flat, market-aware)
|
|
15
23
|
resources :countries, only: [:index, :show]
|
|
16
24
|
resources :currencies, only: [:index]
|
|
@@ -107,6 +107,7 @@ module Spree
|
|
|
107
107
|
address_serializer: 'Spree::Api::V3::AddressSerializer',
|
|
108
108
|
customer_serializer: 'Spree::Api::V3::CustomerSerializer',
|
|
109
109
|
country_serializer: 'Spree::Api::V3::CountrySerializer',
|
|
110
|
+
market_serializer: 'Spree::Api::V3::MarketSerializer',
|
|
110
111
|
state_serializer: 'Spree::Api::V3::StateSerializer',
|
|
111
112
|
store_serializer: 'Spree::Api::V3::StoreSerializer',
|
|
112
113
|
wishlist_serializer: 'Spree::Api::V3::WishlistSerializer',
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: spree_api
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.4.0.
|
|
4
|
+
version: 5.4.0.beta4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vendo Connect Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-03-
|
|
11
|
+
date: 2026-03-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rswag-specs
|
|
@@ -86,14 +86,14 @@ dependencies:
|
|
|
86
86
|
requirements:
|
|
87
87
|
- - '='
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: 5.4.0.
|
|
89
|
+
version: 5.4.0.beta4
|
|
90
90
|
type: :runtime
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
94
|
- - '='
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: 5.4.0.
|
|
96
|
+
version: 5.4.0.beta4
|
|
97
97
|
description: Spree's API
|
|
98
98
|
email:
|
|
99
99
|
- hello@spreecommerce.org
|
|
@@ -109,6 +109,7 @@ files:
|
|
|
109
109
|
- app/controllers/concerns/spree/api/v3/jwt_authentication.rb
|
|
110
110
|
- app/controllers/concerns/spree/api/v3/locale_and_currency.rb
|
|
111
111
|
- app/controllers/concerns/spree/api/v3/order_concern.rb
|
|
112
|
+
- app/controllers/concerns/spree/api/v3/order_lock.rb
|
|
112
113
|
- app/controllers/concerns/spree/api/v3/resource_serializer.rb
|
|
113
114
|
- app/controllers/concerns/spree/api/v3/security_headers.rb
|
|
114
115
|
- app/controllers/spree/api/v3/base_controller.rb
|
|
@@ -126,6 +127,8 @@ files:
|
|
|
126
127
|
- app/controllers/spree/api/v3/store/customer/payment_setup_sessions_controller.rb
|
|
127
128
|
- app/controllers/spree/api/v3/store/digitals_controller.rb
|
|
128
129
|
- app/controllers/spree/api/v3/store/locales_controller.rb
|
|
130
|
+
- app/controllers/spree/api/v3/store/markets/countries_controller.rb
|
|
131
|
+
- app/controllers/spree/api/v3/store/markets_controller.rb
|
|
129
132
|
- app/controllers/spree/api/v3/store/orders/coupon_codes_controller.rb
|
|
130
133
|
- app/controllers/spree/api/v3/store/orders/line_items_controller.rb
|
|
131
134
|
- app/controllers/spree/api/v3/store/orders/payment_methods_controller.rb
|
|
@@ -173,6 +176,7 @@ files:
|
|
|
173
176
|
- app/serializers/spree/api/v3/invitation_serializer.rb
|
|
174
177
|
- app/serializers/spree/api/v3/line_item_serializer.rb
|
|
175
178
|
- app/serializers/spree/api/v3/locale_serializer.rb
|
|
179
|
+
- app/serializers/spree/api/v3/market_serializer.rb
|
|
176
180
|
- app/serializers/spree/api/v3/metafield_serializer.rb
|
|
177
181
|
- app/serializers/spree/api/v3/newsletter_subscriber_serializer.rb
|
|
178
182
|
- app/serializers/spree/api/v3/option_type_serializer.rb
|
|
@@ -235,9 +239,9 @@ licenses:
|
|
|
235
239
|
- BSD-3-Clause
|
|
236
240
|
metadata:
|
|
237
241
|
bug_tracker_uri: https://github.com/spree/spree/issues
|
|
238
|
-
changelog_uri: https://github.com/spree/spree/releases/tag/v5.4.0.
|
|
242
|
+
changelog_uri: https://github.com/spree/spree/releases/tag/v5.4.0.beta4
|
|
239
243
|
documentation_uri: https://docs.spreecommerce.org/
|
|
240
|
-
source_code_uri: https://github.com/spree/spree/tree/v5.4.0.
|
|
244
|
+
source_code_uri: https://github.com/spree/spree/tree/v5.4.0.beta4
|
|
241
245
|
post_install_message:
|
|
242
246
|
rdoc_options: []
|
|
243
247
|
require_paths:
|