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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/app/controllers/concerns/spree/api/v3/cart_resolvable.rb +45 -0
  4. data/app/controllers/concerns/spree/api/v3/error_handler.rb +20 -15
  5. data/app/controllers/concerns/spree/api/v3/order_lock.rb +4 -4
  6. data/app/controllers/spree/api/v3/store/carts/coupon_codes_controller.rb +57 -0
  7. data/app/controllers/spree/api/v3/store/{orders/line_items_controller.rb → carts/items_controller.rb} +18 -31
  8. data/app/controllers/spree/api/v3/store/carts/payment_methods_controller.rb +24 -0
  9. data/app/controllers/spree/api/v3/store/{orders → carts}/payment_sessions_controller.rb +14 -19
  10. data/app/controllers/spree/api/v3/store/carts/payments_controller.rb +72 -0
  11. data/app/controllers/spree/api/v3/store/carts/shipments_controller.rb +65 -0
  12. data/app/controllers/spree/api/v3/store/{orders → carts}/store_credits_controller.rb +9 -10
  13. data/app/controllers/spree/api/v3/store/carts_controller.rb +176 -0
  14. data/app/controllers/spree/api/v3/store/customer/orders_controller.rb +1 -1
  15. data/app/controllers/spree/api/v3/store/orders_controller.rb +21 -114
  16. data/app/controllers/spree/api/v3/webhooks/payments_controller.rb +52 -0
  17. data/app/serializers/spree/api/v3/admin/order_serializer.rb +2 -2
  18. data/app/serializers/spree/api/v3/cart_promotion_serializer.rb +18 -0
  19. data/app/serializers/spree/api/v3/cart_serializer.rb +56 -0
  20. data/app/serializers/spree/api/v3/order_serializer.rb +7 -9
  21. data/config/locales/en.yml +4 -0
  22. data/config/routes.rb +21 -24
  23. data/lib/spree/api/dependencies.rb +5 -0
  24. data/lib/spree/api/openapi/schema_helper.rb +28 -0
  25. metadata +18 -15
  26. data/app/controllers/concerns/spree/api/v3/order_concern.rb +0 -46
  27. data/app/controllers/spree/api/v3/store/cart_controller.rb +0 -97
  28. data/app/controllers/spree/api/v3/store/orders/coupon_codes_controller.rb +0 -73
  29. data/app/controllers/spree/api/v3/store/orders/payment_methods_controller.rb +0 -43
  30. data/app/controllers/spree/api/v3/store/orders/payments_controller.rb +0 -45
  31. 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
@@ -25,7 +25,7 @@ module Spree
25
25
  end
26
26
 
27
27
  def scope
28
- super.for_store(current_store)
28
+ super.for_store(current_store).complete
29
29
  end
30
30
  end
31
31
  end
@@ -2,133 +2,40 @@ module Spree
2
2
  module Api
3
3
  module V3
4
4
  module Store
5
- class OrdersController < ResourceController
6
- include Spree::Api::V3::OrderConcern
7
- include Spree::Api::V3::OrderLock
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
- # Skip base controller's set_resource and define our own complete list
10
- skip_before_action :set_resource
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
- # PATCH /api/v3/store/orders/:id/complete
65
- def complete
66
- with_order_lock do
67
- result = Spree.checkout_complete_service.call(order: @order)
14
+ private
68
15
 
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
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
- order_scope
82
- end
83
-
84
- # Override set_resource to scope lookup by user or order token (IDOR prevention)
85
- def set_resource
86
- @order = order_scope.find_by_prefix_id!(params[:id])
87
- @resource = @order
88
- authorize_resource!(@order)
89
- end
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 order_params
112
- params.permit(
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?('order_promotions') }
47
- many :line_items, resource: Spree.api.admin_line_item_serializer, if: proc { expand?('line_items') }
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
- # Customer-facing order data
5
+ # Post-purchase order data (completed orders)
6
6
  class OrderSerializer < BaseSerializer
7
- typelize number: :string, state: :string, checkout_steps: 'string[]', token: :string, email: [:string, nullable: true],
7
+ typelize number: :string, email: :string,
8
8
  special_instructions: [:string, nullable: true], currency: :string, locale: [:string, nullable: true], item_count: :number,
9
- state_lock_version: :number, shipment_state: [:string, nullable: true], payment_state: [:string, nullable: true],
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, :state, :checkout_steps, :token, :email, :special_instructions,
21
- :currency, :locale, :item_count, :state_lock_version, :shipment_state, :payment_state,
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
@@ -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
- # Cart
37
- resource :cart, only: [:show, :create], controller: 'cart' do
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
- # State transitions
45
- patch :next # Move to next checkout step
46
- patch :advance # Advance through all steps
47
- patch :complete # Complete the order
36
+ patch :associate
37
+ post :complete
48
38
  end
49
-
50
- # Nested resources - all require order access
51
- resource :store_credits, only: [:create, :destroy], controller: 'orders/store_credits'
52
- resources :line_items, only: [:create, :update, :destroy], controller: 'orders/line_items'
53
- resources :coupon_codes, only: [:create, :destroy], controller: 'orders/coupon_codes'
54
- resources :payments, only: [:index, :show], controller: 'orders/payments'
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
- resources :shipments, only: [:index, :show, :update], controller: 'orders/shipments'
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',