spree_api 5.4.0.beta5 → 5.4.0.beta7
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/README.md +3 -3
- data/app/controllers/concerns/spree/api/v3/cart_resolvable.rb +45 -0
- data/app/controllers/concerns/spree/api/v3/error_handler.rb +20 -15
- data/app/controllers/concerns/spree/api/v3/order_lock.rb +4 -4
- data/app/controllers/spree/api/v3/store/carts/coupon_codes_controller.rb +57 -0
- data/app/controllers/spree/api/v3/store/{orders/line_items_controller.rb → carts/items_controller.rb} +18 -31
- data/app/controllers/spree/api/v3/store/carts/payment_methods_controller.rb +24 -0
- data/app/controllers/spree/api/v3/store/{orders → carts}/payment_sessions_controller.rb +14 -19
- data/app/controllers/spree/api/v3/store/carts/payments_controller.rb +72 -0
- data/app/controllers/spree/api/v3/store/carts/shipments_controller.rb +65 -0
- data/app/controllers/spree/api/v3/store/{orders → carts}/store_credits_controller.rb +9 -10
- data/app/controllers/spree/api/v3/store/carts_controller.rb +176 -0
- data/app/controllers/spree/api/v3/store/customer/orders_controller.rb +1 -1
- data/app/controllers/spree/api/v3/store/orders_controller.rb +21 -114
- data/app/controllers/spree/api/v3/webhooks/payments_controller.rb +52 -0
- data/app/serializers/spree/api/v3/admin/order_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/cart_promotion_serializer.rb +18 -0
- data/app/serializers/spree/api/v3/cart_serializer.rb +56 -0
- data/app/serializers/spree/api/v3/order_serializer.rb +7 -9
- data/config/locales/en.yml +4 -0
- data/config/routes.rb +21 -24
- data/lib/spree/api/dependencies.rb +5 -0
- data/lib/spree/api/openapi/schema_helper.rb +28 -0
- metadata +18 -15
- data/app/controllers/concerns/spree/api/v3/order_concern.rb +0 -46
- data/app/controllers/spree/api/v3/store/cart_controller.rb +0 -97
- data/app/controllers/spree/api/v3/store/orders/coupon_codes_controller.rb +0 -73
- data/app/controllers/spree/api/v3/store/orders/payment_methods_controller.rb +0 -43
- data/app/controllers/spree/api/v3/store/orders/payments_controller.rb +0 -45
- data/app/controllers/spree/api/v3/store/orders/shipments_controller.rb +0 -56
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module Store
|
|
5
|
+
class CartsController < Store::ResourceController
|
|
6
|
+
include Spree::Api::V3::CartResolvable
|
|
7
|
+
include Spree::Api::V3::OrderLock
|
|
8
|
+
|
|
9
|
+
skip_before_action :set_resource
|
|
10
|
+
prepend_before_action :require_authentication!, only: [:index, :associate]
|
|
11
|
+
|
|
12
|
+
# GET /api/v3/store/carts/:id
|
|
13
|
+
# Returns cart by prefixed ID
|
|
14
|
+
# Auto-advances the checkout state machine so that shipments and
|
|
15
|
+
# payment requirements are up-to-date (temporary until Spree 6 removes
|
|
16
|
+
# the state machine).
|
|
17
|
+
def show
|
|
18
|
+
@cart = find_cart
|
|
19
|
+
|
|
20
|
+
if @cart.ship_address_id.present? && @cart.shipments.empty?
|
|
21
|
+
ActiveRecord::Base.connected_to(role: :writing) do
|
|
22
|
+
with_order_lock { Spree::Checkout::Advance.call(order: @cart) }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
render_cart
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# POST /api/v3/store/carts
|
|
30
|
+
# Creates a new shopping cart (order)
|
|
31
|
+
# Can be created by guests or authenticated customers
|
|
32
|
+
def create
|
|
33
|
+
result = Spree::Carts::Create.call(
|
|
34
|
+
params: permitted_params.merge(
|
|
35
|
+
user: current_user,
|
|
36
|
+
store: current_store,
|
|
37
|
+
currency: current_currency,
|
|
38
|
+
locale: current_locale
|
|
39
|
+
)
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
if result.success?
|
|
43
|
+
@cart = result.value
|
|
44
|
+
render_cart(status: :created)
|
|
45
|
+
else
|
|
46
|
+
render_service_error(result.error.to_s)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# PATCH /api/v3/store/carts/:id
|
|
51
|
+
# Updates cart info (email, addresses, special instructions).
|
|
52
|
+
# Auto-advances to the next checkout step when possible.
|
|
53
|
+
def update
|
|
54
|
+
find_cart!
|
|
55
|
+
|
|
56
|
+
with_order_lock do
|
|
57
|
+
result = Spree::Carts::Update.call(
|
|
58
|
+
cart: @cart,
|
|
59
|
+
params: permitted_params
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
if result.success?
|
|
63
|
+
render_cart
|
|
64
|
+
else
|
|
65
|
+
render_service_error(result.error, code: ERROR_CODES[:validation_error])
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# DELETE /api/v3/store/carts/:id
|
|
71
|
+
# Deletes/abandons the cart
|
|
72
|
+
def destroy
|
|
73
|
+
find_cart!
|
|
74
|
+
|
|
75
|
+
result = Spree.cart_destroy_service.call(order: @cart)
|
|
76
|
+
|
|
77
|
+
if result.success?
|
|
78
|
+
head :no_content
|
|
79
|
+
else
|
|
80
|
+
render_service_error(result.error.to_s)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# PATCH /api/v3/store/carts/:id/associate
|
|
85
|
+
# Associates a guest cart with the currently authenticated user
|
|
86
|
+
# Requires: JWT authentication + cart ID in URL
|
|
87
|
+
def associate
|
|
88
|
+
@cart = find_cart_for_association
|
|
89
|
+
|
|
90
|
+
result = Spree.cart_associate_service.call(guest_order: @cart, user: current_user, guest_only: true)
|
|
91
|
+
|
|
92
|
+
if result.success?
|
|
93
|
+
render_cart
|
|
94
|
+
else
|
|
95
|
+
render_service_error(result.error.to_s)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# POST /api/v3/store/carts/:id/complete
|
|
100
|
+
# Completes the checkout — returns Order (not Cart).
|
|
101
|
+
# Idempotent: if the cart is already completed, falls back to the
|
|
102
|
+
# orders scope and returns the completed order.
|
|
103
|
+
def complete
|
|
104
|
+
find_cart!
|
|
105
|
+
|
|
106
|
+
result = Spree::Dependencies.carts_complete_service.constantize.call(cart: @cart)
|
|
107
|
+
|
|
108
|
+
if result.success?
|
|
109
|
+
@cart = result.value
|
|
110
|
+
render_order
|
|
111
|
+
else
|
|
112
|
+
render_service_error(
|
|
113
|
+
result.error.to_s.presence || 'Could not complete checkout',
|
|
114
|
+
code: ERROR_CODES[:cart_cannot_complete]
|
|
115
|
+
)
|
|
116
|
+
end
|
|
117
|
+
rescue ActiveRecord::RecordNotFound
|
|
118
|
+
@cart = current_store.orders.complete.find_by_prefix_id!(params[:id])
|
|
119
|
+
authorize!(:show, @cart, cart_token)
|
|
120
|
+
|
|
121
|
+
render_order
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
protected
|
|
125
|
+
|
|
126
|
+
def model_class
|
|
127
|
+
Spree::Order
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def serializer_class
|
|
131
|
+
Spree.api.cart_serializer
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def scope
|
|
135
|
+
current_store.carts.where(user: current_user).order(updated_at: :desc)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
private
|
|
139
|
+
|
|
140
|
+
def permitted_params
|
|
141
|
+
params.permit(
|
|
142
|
+
:email,
|
|
143
|
+
:special_instructions,
|
|
144
|
+
:currency,
|
|
145
|
+
:locale,
|
|
146
|
+
:ship_address_id,
|
|
147
|
+
:bill_address_id,
|
|
148
|
+
ship_address: address_params,
|
|
149
|
+
bill_address: address_params,
|
|
150
|
+
metadata: {},
|
|
151
|
+
items: item_params
|
|
152
|
+
)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def address_params
|
|
156
|
+
[
|
|
157
|
+
:id, :firstname, :lastname, :address1, :address2,
|
|
158
|
+
:city, :zipcode, :phone, :company,
|
|
159
|
+
:country_iso, :state_abbr, :state_name, :quick_checkout
|
|
160
|
+
]
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def item_params
|
|
164
|
+
[:variant_id, :quantity, { metadata: {}, options: {} }]
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Find incomplete cart for associate action.
|
|
168
|
+
# Only finds guest carts (no user) or carts already owned by current user (idempotent).
|
|
169
|
+
def find_cart_for_association
|
|
170
|
+
current_store.carts.where(user: [nil, current_user]).find_by_prefix_id!(params[:id])
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
@@ -2,133 +2,40 @@ module Spree
|
|
|
2
2
|
module Api
|
|
3
3
|
module V3
|
|
4
4
|
module Store
|
|
5
|
-
class OrdersController <
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
class OrdersController < Store::BaseController
|
|
6
|
+
# GET /api/v3/store/orders/:id
|
|
7
|
+
# Single order lookup — accessible via order token (guests) or JWT (authenticated users)
|
|
8
|
+
before_action :find_order!
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
before_action :set_resource, only: [:show, :update, :next, :advance, :complete]
|
|
12
|
-
|
|
13
|
-
# PATCH /api/v3/store/orders/:id
|
|
14
|
-
#
|
|
15
|
-
# Accepts flat parameters:
|
|
16
|
-
# {
|
|
17
|
-
# "email": "customer@example.com",
|
|
18
|
-
# "currency": "EUR",
|
|
19
|
-
# "ship_address": { "firstname": "John", "country_iso": "US", ... },
|
|
20
|
-
# "bill_address": { "firstname": "John", "country_iso": "US", ... }
|
|
21
|
-
# }
|
|
22
|
-
#
|
|
23
|
-
def update
|
|
24
|
-
with_order_lock do
|
|
25
|
-
result = Spree.order_update_service.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
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# PATCH /api/v3/store/orders/:id/next
|
|
39
|
-
def next
|
|
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
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# PATCH /api/v3/store/orders/:id/advance
|
|
52
|
-
def advance
|
|
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
|
|
61
|
-
end
|
|
10
|
+
def show
|
|
11
|
+
render json: serializer_class.new(@order, params: serializer_params).to_h
|
|
62
12
|
end
|
|
63
13
|
|
|
64
|
-
|
|
65
|
-
def complete
|
|
66
|
-
with_order_lock do
|
|
67
|
-
result = Spree.checkout_complete_service.call(order: @order)
|
|
14
|
+
private
|
|
68
15
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
render_service_error(result.error, code: ERROR_CODES[:order_already_completed])
|
|
73
|
-
end
|
|
74
|
-
end
|
|
16
|
+
def find_order!
|
|
17
|
+
@order = scope.find_by_prefix_id!(params[:id])
|
|
18
|
+
authorize!(:show, @order, order_token)
|
|
75
19
|
end
|
|
76
20
|
|
|
77
|
-
protected
|
|
78
|
-
|
|
79
|
-
# Override scope to avoid accessible_by (Order permissions use blocks)
|
|
80
21
|
def scope
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
# override authorize_resource! to pass the order token
|
|
92
|
-
# Maps custom checkout actions to appropriate permissions
|
|
93
|
-
def authorize_resource!(resource = @resource, action = action_name.to_sym)
|
|
94
|
-
mapped_action = case action
|
|
95
|
-
when :next, :advance, :complete
|
|
96
|
-
:update # Checkout actions require update (non-completed order)
|
|
97
|
-
else
|
|
98
|
-
action
|
|
99
|
-
end
|
|
100
|
-
authorize!(mapped_action, resource, order_token)
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def model_class
|
|
104
|
-
Spree::Order
|
|
22
|
+
base = current_store.orders.complete
|
|
23
|
+
|
|
24
|
+
if current_user.present?
|
|
25
|
+
base.where(user: current_user)
|
|
26
|
+
elsif order_token.present?
|
|
27
|
+
base.where(token: order_token)
|
|
28
|
+
else
|
|
29
|
+
base.none
|
|
30
|
+
end
|
|
105
31
|
end
|
|
106
32
|
|
|
107
33
|
def serializer_class
|
|
108
34
|
Spree.api.order_serializer
|
|
109
35
|
end
|
|
110
36
|
|
|
111
|
-
def
|
|
112
|
-
|
|
113
|
-
:email,
|
|
114
|
-
:currency,
|
|
115
|
-
:locale,
|
|
116
|
-
:special_instructions,
|
|
117
|
-
:ship_address_id,
|
|
118
|
-
:bill_address_id,
|
|
119
|
-
ship_address: address_params,
|
|
120
|
-
bill_address: address_params,
|
|
121
|
-
metadata: {},
|
|
122
|
-
line_items: [:variant_id, :quantity, { metadata: {}, options: {} }]
|
|
123
|
-
)
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def address_params
|
|
127
|
-
[
|
|
128
|
-
:id, :firstname, :lastname, :address1, :address2,
|
|
129
|
-
:city, :zipcode, :phone, :company,
|
|
130
|
-
:country_iso, :state_abbr, :state_name, :quick_checkout
|
|
131
|
-
]
|
|
37
|
+
def order_token
|
|
38
|
+
request.headers['x-spree-token']
|
|
132
39
|
end
|
|
133
40
|
end
|
|
134
41
|
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module Webhooks
|
|
5
|
+
class PaymentsController < ActionController::API
|
|
6
|
+
include ActionController::RateLimiting
|
|
7
|
+
|
|
8
|
+
RATE_LIMIT_RESPONSE = -> {
|
|
9
|
+
[429, { 'Content-Type' => 'application/json', 'Retry-After' => '60' },
|
|
10
|
+
[{ error: { code: 'rate_limit_exceeded', message: 'Too many requests' } }.to_json]]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
rate_limit to: 120, within: 1.minute,
|
|
14
|
+
store: Rails.cache,
|
|
15
|
+
by: -> { request.remote_ip },
|
|
16
|
+
with: RATE_LIMIT_RESPONSE
|
|
17
|
+
|
|
18
|
+
# POST /api/v3/webhooks/payments/:payment_method_id
|
|
19
|
+
#
|
|
20
|
+
# Verifies the webhook signature synchronously (returns 401 if invalid),
|
|
21
|
+
# then enqueues async processing and returns 200 immediately.
|
|
22
|
+
def create
|
|
23
|
+
payment_method = Spree::PaymentMethod.find_by_prefix_id!(params[:payment_method_id])
|
|
24
|
+
|
|
25
|
+
# Signature verification must be synchronous — invalid = 401
|
|
26
|
+
result = payment_method.parse_webhook_event(request.raw_post, request.headers)
|
|
27
|
+
|
|
28
|
+
# Unsupported event — acknowledge receipt
|
|
29
|
+
return head :ok if result.nil?
|
|
30
|
+
|
|
31
|
+
# Process asynchronously — gateways have timeout limits and will
|
|
32
|
+
# retry on timeouts, so we must return 200 quickly.
|
|
33
|
+
Spree::Payments::HandleWebhookJob.perform_later(
|
|
34
|
+
payment_method_id: payment_method.id,
|
|
35
|
+
action: result[:action].to_s,
|
|
36
|
+
payment_session_id: result[:payment_session].id
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
head :ok
|
|
40
|
+
rescue Spree::PaymentMethod::WebhookSignatureError
|
|
41
|
+
head :unauthorized
|
|
42
|
+
rescue ActiveRecord::RecordNotFound
|
|
43
|
+
head :not_found
|
|
44
|
+
rescue StandardError => e
|
|
45
|
+
Rails.error.report(e, source: 'spree.webhooks.payments')
|
|
46
|
+
head :ok
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -43,8 +43,8 @@ module Spree
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
# Override inherited associations to use admin serializers
|
|
46
|
-
many :order_promotions, resource: Spree.api.admin_order_promotion_serializer, if: proc { expand?('
|
|
47
|
-
many :line_items, resource: Spree.api.admin_line_item_serializer, if: proc { expand?('
|
|
46
|
+
many :order_promotions, key: :promotions, resource: Spree.api.admin_order_promotion_serializer, if: proc { expand?('promotions') }
|
|
47
|
+
many :line_items, key: :items, resource: Spree.api.admin_line_item_serializer, if: proc { expand?('items') }
|
|
48
48
|
many :shipments, resource: Spree.api.admin_shipment_serializer, if: proc { expand?('shipments') }
|
|
49
49
|
many :payments, resource: Spree.api.admin_payment_serializer, if: proc { expand?('payments') }
|
|
50
50
|
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
# Cart-facing promotion serializer.
|
|
5
|
+
# Same data as OrderPromotionSerializer but IDs use the cp_ prefix.
|
|
6
|
+
class CartPromotionSerializer < BaseSerializer
|
|
7
|
+
typelize name: :string, description: [:string, nullable: true], code: [:string, nullable: true],
|
|
8
|
+
amount: :string, display_amount: :string, promotion_id: :string
|
|
9
|
+
|
|
10
|
+
attribute :promotion_id do |cart_promotion|
|
|
11
|
+
cart_promotion.promotion&.prefixed_id
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
attributes :name, :description, :code, :amount, :display_amount
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
# Store API Cart Serializer
|
|
5
|
+
# Pre-purchase cart data with checkout progression info
|
|
6
|
+
class CartSerializer < BaseSerializer
|
|
7
|
+
typelize number: :string, current_step: :string, completed_steps: 'string[]', token: :string, email: [:string, nullable: true],
|
|
8
|
+
special_instructions: [:string, nullable: true], currency: :string, locale: [:string, nullable: true], item_count: :number,
|
|
9
|
+
requirements: 'Array<{step: string, field: string, message: string}>',
|
|
10
|
+
item_total: :string, display_item_total: :string,
|
|
11
|
+
ship_total: :string, display_ship_total: :string,
|
|
12
|
+
adjustment_total: :string, display_adjustment_total: :string,
|
|
13
|
+
promo_total: :string, display_promo_total: :string,
|
|
14
|
+
tax_total: :string, display_tax_total: :string,
|
|
15
|
+
included_tax_total: :string, display_included_tax_total: :string,
|
|
16
|
+
additional_tax_total: :string, display_additional_tax_total: :string,
|
|
17
|
+
total: :string, display_total: :string,
|
|
18
|
+
bill_address: { nullable: true }, ship_address: { nullable: true }
|
|
19
|
+
|
|
20
|
+
# Override ID to use cart_ prefix
|
|
21
|
+
attribute :id do |order|
|
|
22
|
+
"cart_#{Spree::PrefixedId::SQIDS.encode([order.id])}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
attributes :number, :token, :email, :special_instructions,
|
|
26
|
+
:currency, :locale, :item_count,
|
|
27
|
+
:item_total, :display_item_total, :ship_total, :display_ship_total,
|
|
28
|
+
:adjustment_total, :display_adjustment_total, :promo_total, :display_promo_total,
|
|
29
|
+
:tax_total, :display_tax_total, :included_tax_total, :display_included_tax_total,
|
|
30
|
+
:additional_tax_total, :display_additional_tax_total, :total, :display_total,
|
|
31
|
+
created_at: :iso8601, updated_at: :iso8601
|
|
32
|
+
|
|
33
|
+
attribute :current_step do |order|
|
|
34
|
+
order.current_checkout_step
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
attribute :completed_steps do |order|
|
|
38
|
+
order.completed_checkout_steps
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
attribute :requirements do |order|
|
|
42
|
+
Spree::Checkout::Requirements.new(order).call
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
many :cart_promotions, key: :promotions, resource: Spree.api.cart_promotion_serializer
|
|
46
|
+
many :line_items, key: :items, resource: Spree.api.line_item_serializer
|
|
47
|
+
many :shipments, resource: Spree.api.shipment_serializer
|
|
48
|
+
many :payments, resource: Spree.api.payment_serializer
|
|
49
|
+
one :bill_address, resource: Spree.api.address_serializer
|
|
50
|
+
one :ship_address, resource: Spree.api.address_serializer
|
|
51
|
+
|
|
52
|
+
many :payment_methods, resource: Spree.api.payment_method_serializer
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -2,11 +2,11 @@ module Spree
|
|
|
2
2
|
module Api
|
|
3
3
|
module V3
|
|
4
4
|
# Store API Order Serializer
|
|
5
|
-
#
|
|
5
|
+
# Post-purchase order data (completed orders)
|
|
6
6
|
class OrderSerializer < BaseSerializer
|
|
7
|
-
typelize number: :string,
|
|
7
|
+
typelize number: :string, email: :string,
|
|
8
8
|
special_instructions: [:string, nullable: true], currency: :string, locale: [:string, nullable: true], item_count: :number,
|
|
9
|
-
|
|
9
|
+
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,
|
|
@@ -17,22 +17,20 @@ module Spree
|
|
|
17
17
|
total: :string, display_total: :string, completed_at: [:string, nullable: true],
|
|
18
18
|
bill_address: { nullable: true }, ship_address: { nullable: true }
|
|
19
19
|
|
|
20
|
-
attributes :number, :
|
|
21
|
-
:currency, :locale, :item_count, :
|
|
20
|
+
attributes :number, :email, :special_instructions,
|
|
21
|
+
:currency, :locale, :item_count, :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,
|
|
25
25
|
:additional_tax_total, :display_additional_tax_total, :total, :display_total,
|
|
26
26
|
completed_at: :iso8601, created_at: :iso8601, updated_at: :iso8601
|
|
27
27
|
|
|
28
|
-
many :order_promotions, resource: Spree.api.order_promotion_serializer
|
|
29
|
-
many :line_items, resource: Spree.api.line_item_serializer
|
|
28
|
+
many :order_promotions, key: :promotions, resource: Spree.api.order_promotion_serializer
|
|
29
|
+
many :line_items, key: :items, resource: Spree.api.line_item_serializer
|
|
30
30
|
many :shipments, resource: Spree.api.shipment_serializer
|
|
31
31
|
many :payments, resource: Spree.api.payment_serializer
|
|
32
32
|
one :bill_address, resource: Spree.api.address_serializer
|
|
33
33
|
one :ship_address, resource: Spree.api.address_serializer
|
|
34
|
-
|
|
35
|
-
many :payment_methods, resource: Spree.api.payment_method_serializer
|
|
36
34
|
end
|
|
37
35
|
end
|
|
38
36
|
end
|
data/config/locales/en.yml
CHANGED
|
@@ -24,6 +24,10 @@ en:
|
|
|
24
24
|
shipment_transfer_success: Variants successfully transferred
|
|
25
25
|
stock_location_required: A stock_location_id parameter must be provided in order to retrieve stock movements.
|
|
26
26
|
unauthorized: You are not authorized to perform that action.
|
|
27
|
+
v3:
|
|
28
|
+
payments:
|
|
29
|
+
session_required: This payment method requires a payment session. Use the payment sessions endpoint instead.
|
|
30
|
+
method_unavailable: This payment method is not available for this order.
|
|
27
31
|
v2:
|
|
28
32
|
cart:
|
|
29
33
|
no_coupon_code: No coupon code provided and the Order doesn't have any coupon code promotions applied
|
data/config/routes.rb
CHANGED
|
@@ -7,9 +7,6 @@ Spree::Core::Engine.add_routes do
|
|
|
7
7
|
post 'auth/refresh', to: 'auth#refresh'
|
|
8
8
|
post 'auth/oauth/callback', to: 'auth#oauth_callback'
|
|
9
9
|
|
|
10
|
-
# Customer registration
|
|
11
|
-
resources :customers, only: [:create]
|
|
12
|
-
|
|
13
10
|
# Markets
|
|
14
11
|
resources :markets, only: [:index, :show] do
|
|
15
12
|
collection do
|
|
@@ -33,46 +30,41 @@ Spree::Core::Engine.add_routes do
|
|
|
33
30
|
resources :products, only: [:index], controller: 'categories/products'
|
|
34
31
|
end
|
|
35
32
|
|
|
36
|
-
#
|
|
37
|
-
|
|
38
|
-
patch :associate
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# Orders - individual order management and checkout
|
|
42
|
-
resources :orders, only: [:show, :update] do
|
|
33
|
+
# Carts
|
|
34
|
+
resources :carts, only: [:index, :show, :create, :update, :destroy] do
|
|
43
35
|
member do
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
patch :advance # Advance through all steps
|
|
47
|
-
patch :complete # Complete the order
|
|
36
|
+
patch :associate
|
|
37
|
+
post :complete
|
|
48
38
|
end
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
resources :
|
|
53
|
-
resources :
|
|
54
|
-
resources :
|
|
55
|
-
resources :payment_methods, only: [:index], controller: 'orders/payment_methods'
|
|
56
|
-
resources :payment_sessions, only: [:create, :show, :update], controller: 'orders/payment_sessions' do
|
|
39
|
+
resources :items, only: [:create, :update, :destroy], controller: 'carts/items'
|
|
40
|
+
resources :coupon_codes, only: [:create, :destroy], controller: 'carts/coupon_codes'
|
|
41
|
+
resources :shipments, only: [:index, :update], controller: 'carts/shipments'
|
|
42
|
+
resources :payment_methods, only: [:index], controller: 'carts/payment_methods'
|
|
43
|
+
resources :payments, only: [:index, :show, :create], controller: 'carts/payments'
|
|
44
|
+
resources :payment_sessions, only: [:create, :show, :update], controller: 'carts/payment_sessions' do
|
|
57
45
|
member do
|
|
58
46
|
patch :complete
|
|
59
47
|
end
|
|
60
48
|
end
|
|
61
|
-
|
|
49
|
+
resource :store_credits, only: [:create, :destroy], controller: 'carts/store_credits'
|
|
62
50
|
end
|
|
63
51
|
|
|
52
|
+
# Orders (single order lookup, guest-accessible via order token)
|
|
53
|
+
resources :orders, only: [:show]
|
|
54
|
+
|
|
64
55
|
# Customer (current user profile)
|
|
56
|
+
resources :customers, only: [:create]
|
|
65
57
|
get 'customer', to: 'customers#show'
|
|
66
58
|
patch 'customer', to: 'customers#update'
|
|
67
59
|
|
|
68
60
|
# Customer nested resources
|
|
69
61
|
namespace :customer, path: 'customer' do
|
|
62
|
+
resources :orders, only: [:index, :show]
|
|
70
63
|
resources :addresses, only: [:index, :show, :create, :update, :destroy] do
|
|
71
64
|
member do
|
|
72
65
|
patch :mark_as_default
|
|
73
66
|
end
|
|
74
67
|
end
|
|
75
|
-
resources :orders, only: [:index]
|
|
76
68
|
resources :credit_cards, only: [:index, :show, :destroy]
|
|
77
69
|
resources :gift_cards, only: [:index, :show]
|
|
78
70
|
resources :payment_setup_sessions, only: [:create, :show] do
|
|
@@ -92,6 +84,11 @@ Spree::Core::Engine.add_routes do
|
|
|
92
84
|
get 'digitals/:token', to: 'digitals#show', as: :digital_download
|
|
93
85
|
|
|
94
86
|
end
|
|
87
|
+
|
|
88
|
+
# Webhooks (outside of store namespace — no API key authentication)
|
|
89
|
+
namespace :webhooks do
|
|
90
|
+
post 'payments/:payment_method_id', to: 'payments#create', as: :payment_webhook
|
|
91
|
+
end
|
|
95
92
|
end
|
|
96
93
|
end
|
|
97
94
|
end
|
|
@@ -4,6 +4,7 @@ module Spree
|
|
|
4
4
|
module Api
|
|
5
5
|
class ApiDependencies
|
|
6
6
|
INJECTION_POINTS_WITH_DEFAULTS = {
|
|
7
|
+
# Legacy API v2 dependencies - will be removed in Spree 6
|
|
7
8
|
# cart services
|
|
8
9
|
storefront_cart_create_service: -> { Spree::Dependencies.cart_create_service },
|
|
9
10
|
storefront_cart_add_item_service: -> { Spree::Dependencies.cart_add_item_service },
|
|
@@ -66,6 +67,8 @@ module Spree
|
|
|
66
67
|
storefront_estimated_shipment_serializer: 'Spree::V2::Storefront::EstimatedShippingRateSerializer',
|
|
67
68
|
storefront_store_serializer: 'Spree::V2::Storefront::StoreSerializer',
|
|
68
69
|
storefront_policy_serializer: 'Spree::V2::Storefront::PolicySerializer',
|
|
70
|
+
storefront_post_category_serializer: 'Spree::V2::Storefront::PostCategorySerializer',
|
|
71
|
+
storefront_post_serializer: 'Spree::V2::Storefront::PostSerializer',
|
|
69
72
|
storefront_order_serializer: 'Spree::V2::Storefront::OrderSerializer',
|
|
70
73
|
storefront_variant_serializer: 'Spree::V2::Storefront::VariantSerializer',
|
|
71
74
|
storefront_image_serializer: 'Spree::V2::Storefront::ImageSerializer',
|
|
@@ -96,6 +99,7 @@ module Spree
|
|
|
96
99
|
image_serializer: 'Spree::Api::V3::ImageSerializer',
|
|
97
100
|
option_type_serializer: 'Spree::Api::V3::OptionTypeSerializer',
|
|
98
101
|
option_value_serializer: 'Spree::Api::V3::OptionValueSerializer',
|
|
102
|
+
cart_serializer: 'Spree::Api::V3::CartSerializer',
|
|
99
103
|
order_serializer: 'Spree::Api::V3::OrderSerializer',
|
|
100
104
|
line_item_serializer: 'Spree::Api::V3::LineItemSerializer',
|
|
101
105
|
payment_serializer: 'Spree::Api::V3::PaymentSerializer',
|
|
@@ -116,6 +120,7 @@ module Spree
|
|
|
116
120
|
shipping_rate_serializer: 'Spree::Api::V3::ShippingRateSerializer',
|
|
117
121
|
stock_location_serializer: 'Spree::Api::V3::StockLocationSerializer',
|
|
118
122
|
category_serializer: 'Spree::Api::V3::CategorySerializer',
|
|
123
|
+
cart_promotion_serializer: 'Spree::Api::V3::CartPromotionSerializer',
|
|
119
124
|
order_promotion_serializer: 'Spree::Api::V3::OrderPromotionSerializer',
|
|
120
125
|
digital_link_serializer: 'Spree::Api::V3::DigitalLinkSerializer',
|
|
121
126
|
gift_card_serializer: 'Spree::Api::V3::GiftCardSerializer',
|