spree_api 5.4.0.beta7 → 5.4.0.beta9

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/spree/api/v3/error_handler.rb +3 -0
  3. data/app/controllers/spree/api/v3/store/auth_controller.rb +62 -19
  4. data/app/controllers/spree/api/v3/store/carts/{shipments_controller.rb → fulfillments_controller.rb} +13 -13
  5. data/app/controllers/spree/api/v3/store/customer/password_resets_controller.rb +91 -0
  6. data/app/controllers/spree/api/v3/store/customers_controller.rb +6 -2
  7. data/app/controllers/spree/api/v3/store/products_controller.rb +1 -1
  8. data/app/serializers/spree/api/v3/admin/address_serializer.rb +2 -2
  9. data/app/serializers/spree/api/v3/admin/allowed_origin_serializer.rb +21 -0
  10. data/app/serializers/spree/api/v3/admin/credit_card_serializer.rb +2 -2
  11. data/app/serializers/spree/api/v3/admin/{shipping_method_serializer.rb → delivery_method_serializer.rb} +1 -1
  12. data/app/serializers/spree/api/v3/admin/delivery_rate_serializer.rb +11 -0
  13. data/app/serializers/spree/api/v3/admin/{shipment_serializer.rb → fulfillment_serializer.rb} +3 -3
  14. data/app/serializers/spree/api/v3/admin/media_serializer.rb +17 -0
  15. data/app/serializers/spree/api/v3/admin/order_serializer.rb +5 -4
  16. data/app/serializers/spree/api/v3/admin/product_serializer.rb +8 -9
  17. data/app/serializers/spree/api/v3/admin/store_credit_serializer.rb +2 -2
  18. data/app/serializers/spree/api/v3/admin/variant_serializer.rb +8 -3
  19. data/app/serializers/spree/api/v3/base_serializer.rb +1 -1
  20. data/app/serializers/spree/api/v3/cart_serializer.rb +11 -3
  21. data/app/serializers/spree/api/v3/{shipping_method_serializer.rb → delivery_method_serializer.rb} +1 -1
  22. data/app/serializers/spree/api/v3/{shipping_rate_serializer.rb → delivery_rate_serializer.rb} +4 -4
  23. data/app/serializers/spree/api/v3/fulfillment_serializer.rb +45 -0
  24. data/app/serializers/spree/api/v3/gift_card_serializer.rb +2 -2
  25. data/app/serializers/spree/api/v3/media_serializer.rb +60 -0
  26. data/app/serializers/spree/api/v3/newsletter_subscriber_serializer.rb +2 -2
  27. data/app/serializers/spree/api/v3/order_serializer.rb +21 -5
  28. data/app/serializers/spree/api/v3/payment_serializer.rb +6 -2
  29. data/app/serializers/spree/api/v3/product_serializer.rb +10 -11
  30. data/app/serializers/spree/api/v3/variant_serializer.rb +14 -9
  31. data/config/locales/en.yml +3 -0
  32. data/config/routes.rb +4 -1
  33. data/lib/spree/api/configuration.rb +2 -0
  34. data/lib/spree/api/dependencies.rb +14 -8
  35. data/lib/spree/api/openapi/schema_helper.rb +31 -1
  36. metadata +17 -15
  37. data/app/serializers/spree/api/v3/admin/image_serializer.rb +0 -10
  38. data/app/serializers/spree/api/v3/admin/shipping_rate_serializer.rb +0 -11
  39. data/app/serializers/spree/api/v3/image_serializer.rb +0 -43
  40. data/app/serializers/spree/api/v3/shipment_serializer.rb +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f27a3d636c9e7fdac4e297ba4820d97f91831b4124a1b6aafcc734b4f3906bc
4
- data.tar.gz: a436eac6eee920191894f256c587c12f852b5b86f3a978d6af43f032cff1908b
3
+ metadata.gz: 7630000b76a8d6596d6a94e2e5ef3b928ad55035995a777d79a855da0b83e707
4
+ data.tar.gz: 5621ebbdb257e9c69518e3ad71a9368954c0fbf7db6ad7a3b4adb237b00cb83b
5
5
  SHA512:
6
- metadata.gz: adce2c15462e5c368813c95419047c83e686254e93af752832e370a2ed19aa7f5893659ed8b79c982bbe37294695b245d87671d196d93e92d759b9d8fe79caa9
7
- data.tar.gz: 1cdec354c04bd65e731b2ee0309170e597012047ede52184ca0cbe2f8323d9af4c0f5ed967cb13fade6c74c3a1206aa058a803992c983b1ae351fc887f77b934
6
+ metadata.gz: ecdbc7f8b2e6792a1e8641ebaabfcc69423705f032435bb960ff3f2ae36eb19c89dc224b8af79278b3e74536ca95112442139278e847cca9710f437300d9395e
7
+ data.tar.gz: 8264257bdf243e8bc504880ceed1f99233baaf09bf6e7264714ab9395b59429e0c9c553269012015d9e870dd3dc797b19224d204b7a33518681878533200e71e
@@ -12,7 +12,10 @@ module Spree
12
12
  access_denied: 'access_denied',
13
13
  invalid_token: 'invalid_token',
14
14
  invalid_provider: 'invalid_provider',
15
+ invalid_refresh_token: 'invalid_refresh_token',
15
16
  current_password_invalid: 'current_password_invalid',
17
+ password_reset_token_invalid: 'password_reset_token_invalid',
18
+ redirect_url_not_allowed: 'redirect_url_not_allowed',
16
19
 
17
20
  # Resource errors
18
21
  record_not_found: 'record_not_found',
@@ -7,9 +7,9 @@ module Spree
7
7
  rate_limit to: Spree::Api::Config[:rate_limit_login], within: Spree::Api::Config[:rate_limit_window].seconds, store: Rails.cache, only: :create, with: RATE_LIMIT_RESPONSE
8
8
  rate_limit to: Spree::Api::Config[:rate_limit_refresh], within: Spree::Api::Config[:rate_limit_window].seconds, store: Rails.cache, only: :refresh, with: RATE_LIMIT_RESPONSE
9
9
  rate_limit to: Spree::Api::Config[:rate_limit_oauth], within: Spree::Api::Config[:rate_limit_window].seconds, store: Rails.cache, only: :oauth_callback, with: RATE_LIMIT_RESPONSE
10
+ rate_limit to: Spree::Api::Config[:rate_limit_refresh], within: Spree::Api::Config[:rate_limit_window].seconds, store: Rails.cache, only: :logout, with: RATE_LIMIT_RESPONSE
10
11
 
11
- skip_before_action :authenticate_user, only: [:create, :oauth_callback]
12
- prepend_before_action :require_authentication!, only: [:refresh]
12
+ skip_before_action :authenticate_user, only: [:create, :refresh, :oauth_callback]
13
13
 
14
14
  # POST /api/v3/store/auth/login
15
15
  # Supports multiple authentication providers via :provider param
@@ -23,11 +23,7 @@ module Spree
23
23
 
24
24
  if result.success?
25
25
  user = result.value
26
- token = generate_jwt(user)
27
- render json: {
28
- token: token,
29
- user: user_serializer.new(user, params: serializer_params).to_h
30
- }
26
+ render json: auth_response(user)
31
27
  else
32
28
  render_error(
33
29
  code: ERROR_CODES[:authentication_failed],
@@ -38,21 +34,55 @@ module Spree
38
34
  end
39
35
 
40
36
  # POST /api/v3/store/auth/refresh
37
+ # Accepts: { "refresh_token": "rt_xxx" }
38
+ # Returns new access JWT + rotated refresh token
41
39
  def refresh
42
- token = generate_jwt(current_user)
40
+ refresh_token_value = params[:refresh_token]
41
+
42
+ if refresh_token_value.blank?
43
+ return render_error(
44
+ code: ERROR_CODES[:invalid_refresh_token],
45
+ message: 'refresh_token is required',
46
+ status: :unauthorized
47
+ )
48
+ end
49
+
50
+ refresh_token = Spree::RefreshToken.active.find_by(token: refresh_token_value)
51
+
52
+ if refresh_token.nil?
53
+ return render_error(
54
+ code: ERROR_CODES[:invalid_refresh_token],
55
+ message: 'Invalid or expired refresh token',
56
+ status: :unauthorized
57
+ )
58
+ end
59
+
60
+ user = refresh_token.user
61
+ new_refresh_token = refresh_token.rotate!(request_env: request_env_for_token)
62
+
43
63
  render json: {
44
- token: token,
45
- user: user_serializer.new(current_user, params: serializer_params).to_h
64
+ token: generate_jwt(user),
65
+ refresh_token: new_refresh_token.token,
66
+ user: user_serializer.new(user, params: serializer_params).to_h
46
67
  }
47
68
  end
48
69
 
70
+ # POST /api/v3/store/auth/logout
71
+ # Accepts: { "refresh_token": "rt_xxx" }
72
+ # Revokes the refresh token
73
+ def logout
74
+ refresh_token_value = params[:refresh_token]
75
+
76
+ if refresh_token_value.present?
77
+ Spree::RefreshToken.find_by(token: refresh_token_value)&.destroy
78
+ end
79
+
80
+ head :no_content
81
+ end
82
+
49
83
  # POST /api/v3/store/auth/oauth/callback
50
84
  # OAuth callback endpoint for server-side OAuth flows
51
85
  def oauth_callback
52
- # This endpoint is designed for OAuth flows where the server
53
- # exchanges the authorization code for an access token
54
- # For client-side flows, use the regular /login endpoint with id_token
55
-
56
86
  strategy = authentication_strategy
57
87
  return unless strategy # Error already rendered by determine_strategy
58
88
 
@@ -60,11 +90,7 @@ module Spree
60
90
 
61
91
  if result.success?
62
92
  user = result.value
63
- token = generate_jwt(user)
64
- render json: {
65
- token: token,
66
- user: user_serializer.new(user, params: serializer_params).to_h
67
- }
93
+ render json: auth_response(user)
68
94
  else
69
95
  render_error(
70
96
  code: ERROR_CODES[:authentication_failed],
@@ -88,6 +114,23 @@ module Spree
88
114
 
89
115
  private
90
116
 
117
+ def auth_response(user)
118
+ refresh_token = Spree::RefreshToken.create_for(user, request_env: request_env_for_token)
119
+
120
+ {
121
+ token: generate_jwt(user),
122
+ refresh_token: refresh_token.token,
123
+ user: user_serializer.new(user, params: serializer_params).to_h
124
+ }
125
+ end
126
+
127
+ def request_env_for_token
128
+ {
129
+ ip_address: request.remote_ip,
130
+ user_agent: request.user_agent&.truncate(255)
131
+ }
132
+ end
133
+
91
134
  def authentication_strategy
92
135
  strategy_class = determine_strategy
93
136
  strategy_class.new(
@@ -3,31 +3,31 @@ module Spree
3
3
  module V3
4
4
  module Store
5
5
  module Carts
6
- class ShipmentsController < Store::BaseController
6
+ class FulfillmentsController < Store::BaseController
7
7
  include Spree::Api::V3::CartResolvable
8
8
  include Spree::Api::V3::OrderLock
9
9
 
10
10
  before_action :find_cart!
11
11
 
12
- # GET /api/v3/store/carts/:cart_id/shipments
12
+ # GET /api/v3/store/carts/:cart_id/fulfillments
13
13
  def index
14
- shipments = @cart.shipments.includes(shipping_rates: :shipping_method)
14
+ fulfillments = @cart.shipments.includes(shipping_rates: :shipping_method)
15
15
  render json: {
16
- data: shipments.map { |s| Spree.api.shipment_serializer.new(s, params: serializer_params).to_h },
17
- meta: { count: shipments.size }
16
+ data: fulfillments.map { |s| Spree.api.fulfillment_serializer.new(s, params: serializer_params).to_h },
17
+ meta: { count: fulfillments.size }
18
18
  }
19
19
  end
20
20
 
21
- # PATCH /api/v3/store/carts/:cart_id/shipments/:id
22
- # Select a shipping rate for a specific shipment
21
+ # PATCH /api/v3/store/carts/:cart_id/fulfillments/:id
22
+ # Select a delivery rate for a specific fulfillment
23
23
  def update
24
24
  with_order_lock do
25
- shipment = @cart.shipments.find_by_prefix_id!(params[:id])
25
+ fulfillment = @cart.shipments.find_by_prefix_id!(params[:id])
26
26
 
27
- if permitted_params[:selected_shipping_rate_id].present?
28
- shipping_rate = shipment.shipping_rates.find_by_prefix_id!(permitted_params[:selected_shipping_rate_id])
29
- shipment.selected_shipping_rate_id = shipping_rate.id
30
- shipment.save!
27
+ if permitted_params[:selected_delivery_rate_id].present?
28
+ delivery_rate = fulfillment.shipping_rates.find_by_prefix_id!(permitted_params[:selected_delivery_rate_id])
29
+ fulfillment.selected_shipping_rate_id = delivery_rate.id
30
+ fulfillment.save!
31
31
  end
32
32
 
33
33
  # Auto-advance (e.g. delivery → payment) after rate selection.
@@ -41,7 +41,7 @@ module Spree
41
41
  private
42
42
 
43
43
  def permitted_params
44
- params.permit(:selected_shipping_rate_id)
44
+ params.permit(:selected_delivery_rate_id)
45
45
  end
46
46
 
47
47
  # Temporary — Spree 6 removes the checkout state machine.
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Api
5
+ module V3
6
+ module Store
7
+ module Customer
8
+ class PasswordResetsController < Store::BaseController
9
+ rate_limit to: Spree::Api::Config[:rate_limit_password_reset],
10
+ within: Spree::Api::Config[:rate_limit_window].seconds,
11
+ store: Rails.cache,
12
+ with: RATE_LIMIT_RESPONSE
13
+
14
+ skip_before_action :authenticate_user
15
+
16
+ # POST /api/v3/store/customer/password_resets
17
+ def create
18
+ redirect_url = params[:redirect_url]
19
+
20
+ # Validate redirect_url against allowed origins (secure by default).
21
+ # If no allowed origins are configured, redirect_url is silently ignored
22
+ # to prevent open redirect / token exfiltration attacks.
23
+ if redirect_url.present?
24
+ if current_store.allowed_origins.exists? && current_store.allowed_origin?(redirect_url)
25
+ # redirect_url is valid — keep it
26
+ else
27
+ redirect_url = nil
28
+ end
29
+ end
30
+
31
+ user = Spree.user_class.find_by(email: params[:email])
32
+
33
+ if user
34
+ token = user.generate_token_for(:password_reset)
35
+ event_payload = { reset_token: token, email: user.email }
36
+ event_payload[:redirect_url] = redirect_url if redirect_url.present?
37
+ user.publish_event('customer.password_reset_requested', event_payload)
38
+ end
39
+
40
+ # Always return 202 to prevent email enumeration
41
+ render json: { message: Spree.t(:password_reset_requested, scope: :api) }, status: :accepted
42
+ end
43
+
44
+ # PATCH /api/v3/store/customer/password_resets/:id
45
+ def update
46
+ user = Spree.user_class.find_by_password_reset_token(params[:id])
47
+
48
+ unless user
49
+ return render_error(
50
+ code: ERROR_CODES[:password_reset_token_invalid],
51
+ message: Spree.t(:password_reset_token_invalid, scope: :api),
52
+ status: :unprocessable_content
53
+ )
54
+ end
55
+
56
+ if user.update(password: params[:password], password_confirmation: params[:password_confirmation])
57
+ jwt = generate_jwt(user)
58
+ refresh_token = Spree::RefreshToken.create_for(user, request_env: { ip_address: request.remote_ip, user_agent: request.user_agent&.truncate(255) })
59
+ user.publish_event('customer.password_reset')
60
+
61
+ render json: {
62
+ token: jwt,
63
+ refresh_token: refresh_token.token,
64
+ user: serializer_class.new(user, params: serializer_params).to_h
65
+ }
66
+ else
67
+ render_errors(user.errors)
68
+ end
69
+ end
70
+
71
+ protected
72
+
73
+ def serializer_class
74
+ Spree.api.customer_serializer
75
+ end
76
+
77
+ def serializer_params
78
+ {
79
+ store: current_store,
80
+ locale: current_locale,
81
+ currency: current_currency,
82
+ user: nil,
83
+ includes: []
84
+ }
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -13,9 +13,13 @@ module Spree
13
13
  user = Spree.user_class.new(create_params)
14
14
 
15
15
  if user.save
16
- token = generate_jwt(user)
16
+ refresh_token = Spree::RefreshToken.create_for(user, request_env: {
17
+ ip_address: request.remote_ip,
18
+ user_agent: request.user_agent&.truncate(255)
19
+ })
17
20
  render json: {
18
- token: token,
21
+ token: generate_jwt(user),
22
+ refresh_token: refresh_token.token,
19
23
  user: user_serializer.new(user, params: serializer_params).to_h
20
24
  }, status: :created
21
25
  else
@@ -41,7 +41,7 @@ module Spree
41
41
  # these scopes are not automatically picked by ar_lazy_preload gem and we need to explicitly include them
42
42
  def scope_includes
43
43
  [
44
- thumbnail: [attachment_attachment: :blob],
44
+ primary_media: [attachment_attachment: :blob],
45
45
  master: [:prices, stock_items: :stock_location],
46
46
  variants: [:prices, stock_items: :stock_location]
47
47
  ]
@@ -4,13 +4,13 @@ module Spree
4
4
  module Admin
5
5
  class AddressSerializer < V3::AddressSerializer
6
6
  typelize label: [:string, nullable: true],
7
- user_id: [:string, nullable: true],
7
+ customer_id: [:string, nullable: true],
8
8
  metadata: 'Record<string, unknown> | null'
9
9
 
10
10
  attributes :label,
11
11
  created_at: :iso8601, updated_at: :iso8601
12
12
 
13
- attribute :user_id do |address|
13
+ attribute :customer_id do |address|
14
14
  address.user&.prefixed_id
15
15
  end
16
16
 
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Api
5
+ module V3
6
+ module Admin
7
+ class AllowedOriginSerializer < V3::BaseSerializer
8
+ typelize store_id: :string
9
+
10
+ attributes :id, :origin
11
+
12
+ attribute :store_id do |allowed_origin|
13
+ allowed_origin.store&.prefixed_id
14
+ end
15
+
16
+ attributes created_at: :iso8601, updated_at: :iso8601
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -3,10 +3,10 @@ module Spree
3
3
  module V3
4
4
  module Admin
5
5
  class CreditCardSerializer < V3::CreditCardSerializer
6
- typelize user_id: [:string, nullable: true],
6
+ typelize customer_id: [:string, nullable: true],
7
7
  payment_method_id: [:string, nullable: true]
8
8
 
9
- attribute :user_id do |credit_card|
9
+ attribute :customer_id do |credit_card|
10
10
  credit_card.user&.prefixed_id
11
11
  end
12
12
 
@@ -2,7 +2,7 @@ module Spree
2
2
  module Api
3
3
  module V3
4
4
  module Admin
5
- class ShippingMethodSerializer < V3::ShippingMethodSerializer
5
+ class DeliveryMethodSerializer < V3::DeliveryMethodSerializer
6
6
  attributes created_at: :iso8601, updated_at: :iso8601
7
7
  end
8
8
  end
@@ -0,0 +1,11 @@
1
+ module Spree
2
+ module Api
3
+ module V3
4
+ module Admin
5
+ class DeliveryRateSerializer < V3::DeliveryRateSerializer
6
+ one :shipping_method, key: :delivery_method, resource: Spree.api.admin_delivery_method_serializer, if: proc { expand?('delivery_method') }
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -2,7 +2,7 @@ module Spree
2
2
  module Api
3
3
  module V3
4
4
  module Admin
5
- class ShipmentSerializer < V3::ShipmentSerializer
5
+ class FulfillmentSerializer < V3::FulfillmentSerializer
6
6
  typelize metadata: 'Record<string, unknown> | null',
7
7
  order_id: [:string, nullable: true],
8
8
  stock_location_id: [:string, nullable: true],
@@ -26,9 +26,9 @@ module Spree
26
26
  end
27
27
 
28
28
  # Override inherited associations to use admin serializers
29
- one :shipping_method, resource: Spree.api.admin_shipping_method_serializer, if: proc { expand?('shipping_method') }
29
+ one :shipping_method, key: :delivery_method, resource: Spree.api.admin_delivery_method_serializer, if: proc { expand?('delivery_method') }
30
30
  one :stock_location, resource: Spree.api.admin_stock_location_serializer, if: proc { expand?('stock_location') }
31
- many :shipping_rates, resource: Spree.api.admin_shipping_rate_serializer, if: proc { expand?('shipping_rates') }
31
+ many :shipping_rates, key: :delivery_rates, resource: Spree.api.admin_delivery_rate_serializer, if: proc { expand?('delivery_rates') }
32
32
 
33
33
  one :order,
34
34
  resource: Spree.api.admin_order_serializer,
@@ -0,0 +1,17 @@
1
+ module Spree
2
+ module Api
3
+ module V3
4
+ module Admin
5
+ class MediaSerializer < V3::MediaSerializer
6
+ typelize viewable_type: :string, viewable_id: :string
7
+
8
+ attribute :viewable_id do |asset|
9
+ asset.viewable&.prefixed_id
10
+ end
11
+
12
+ attributes :viewable_type
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -11,7 +11,7 @@ module Spree
11
11
  store_owner_notification_delivered: :boolean,
12
12
  internal_note: [:string, nullable: true], approver_id: [:string, nullable: true],
13
13
  canceler_id: [:string, nullable: true], created_by_id: [:string, nullable: true],
14
- user_id: [:string, nullable: true],
14
+ customer_id: [:string, nullable: true],
15
15
  canceled_at: [:string, nullable: true], approved_at: [:string, nullable: true],
16
16
  payment_total: :string, display_payment_total: :string,
17
17
  metadata: 'Record<string, unknown> | null'
@@ -38,14 +38,14 @@ module Spree
38
38
  order.created_by&.prefixed_id
39
39
  end
40
40
 
41
- attribute :user_id do |order|
41
+ attribute :customer_id do |order|
42
42
  order.user&.prefixed_id
43
43
  end
44
44
 
45
45
  # Override inherited associations to use admin serializers
46
46
  many :order_promotions, key: :promotions, resource: Spree.api.admin_order_promotion_serializer, if: proc { expand?('promotions') }
47
47
  many :line_items, key: :items, resource: Spree.api.admin_line_item_serializer, if: proc { expand?('items') }
48
- many :shipments, resource: Spree.api.admin_shipment_serializer, if: proc { expand?('shipments') }
48
+ many :shipments, key: :fulfillments, resource: Spree.api.admin_fulfillment_serializer, if: proc { expand?('fulfillments') }
49
49
  many :payments, resource: Spree.api.admin_payment_serializer, if: proc { expand?('payments') }
50
50
 
51
51
  one :bill_address, resource: Spree.api.admin_address_serializer, if: proc { expand?('bill_address') }
@@ -54,8 +54,9 @@ module Spree
54
54
  many :payment_methods, resource: Spree.api.admin_payment_method_serializer, if: proc { expand?('payment_methods') }
55
55
 
56
56
  one :user,
57
+ key: :customer,
57
58
  resource: Spree.api.admin_customer_serializer,
58
- if: proc { expand?('user') }
59
+ if: proc { expand?('customer') }
59
60
 
60
61
  one :approver,
61
62
  resource: Spree.api.admin_customer_serializer,
@@ -32,15 +32,14 @@ module Spree
32
32
  resource: Spree.api.admin_variant_serializer,
33
33
  if: proc { expand?('default_variant') }
34
34
 
35
- one :master,
36
- key: :master_variant,
37
- resource: Spree.api.admin_variant_serializer,
38
- if: proc { expand?('master_variant') }
39
-
40
- many :variant_images,
41
- key: :images,
42
- resource: Spree.api.admin_image_serializer,
43
- if: proc { expand?('images') }
35
+ one :primary_media,
36
+ resource: Spree.api.admin_media_serializer,
37
+ if: proc { expand?('primary_media') }
38
+
39
+ many :gallery_media,
40
+ key: :media,
41
+ resource: Spree.api.admin_media_serializer,
42
+ if: proc { expand?('media') }
44
43
 
45
44
  many :option_types,
46
45
  resource: Spree.api.admin_option_type_serializer,
@@ -3,11 +3,11 @@ module Spree
3
3
  module V3
4
4
  module Admin
5
5
  class StoreCreditSerializer < V3::StoreCreditSerializer
6
- typelize user_id: [:string, nullable: true],
6
+ typelize customer_id: [:string, nullable: true],
7
7
  created_by_id: [:string, nullable: true],
8
8
  metadata: 'Record<string, unknown> | null'
9
9
 
10
- attribute :user_id do |store_credit|
10
+ attribute :customer_id do |store_credit|
11
11
  store_credit.user&.prefixed_id
12
12
  end
13
13
 
@@ -20,9 +20,14 @@ module Spree
20
20
  end
21
21
 
22
22
  # Override inherited associations to use admin serializers
23
- many :images,
24
- resource: Spree.api.admin_image_serializer,
25
- if: proc { expand?('images') }
23
+ one :primary_media,
24
+ resource: Spree.api.admin_media_serializer,
25
+ if: proc { expand?('primary_media') }
26
+
27
+ many :gallery_media,
28
+ key: :media,
29
+ resource: Spree.api.admin_media_serializer,
30
+ if: proc { expand?('media') }
26
31
 
27
32
  many :option_values, resource: Spree.api.admin_option_value_serializer
28
33
 
@@ -38,7 +38,7 @@ module Spree
38
38
  end
39
39
 
40
40
  # Check if an association should be expanded
41
- # Supports dot notation: expand?('variants') matches both 'variants' and 'variants.images'
41
+ # Supports dot notation: expand?('variants') matches both 'variants' and 'variants.media'
42
42
  def expand?(name)
43
43
  name = name.to_s
44
44
  expands.any? { |e| e == name || e.start_with?("#{name}.") }
@@ -8,7 +8,7 @@ module Spree
8
8
  special_instructions: [:string, nullable: true], currency: :string, locale: [:string, nullable: true], item_count: :number,
9
9
  requirements: 'Array<{step: string, field: string, message: string}>',
10
10
  item_total: :string, display_item_total: :string,
11
- ship_total: :string, display_ship_total: :string,
11
+ delivery_total: :string, display_delivery_total: :string,
12
12
  adjustment_total: :string, display_adjustment_total: :string,
13
13
  promo_total: :string, display_promo_total: :string,
14
14
  tax_total: :string, display_tax_total: :string,
@@ -24,12 +24,20 @@ module Spree
24
24
 
25
25
  attributes :number, :token, :email, :special_instructions,
26
26
  :currency, :locale, :item_count,
27
- :item_total, :display_item_total, :ship_total, :display_ship_total,
27
+ :item_total, :display_item_total,
28
28
  :adjustment_total, :display_adjustment_total, :promo_total, :display_promo_total,
29
29
  :tax_total, :display_tax_total, :included_tax_total, :display_included_tax_total,
30
30
  :additional_tax_total, :display_additional_tax_total, :total, :display_total,
31
31
  created_at: :iso8601, updated_at: :iso8601
32
32
 
33
+ attribute :delivery_total do |order|
34
+ order.ship_total
35
+ end
36
+
37
+ attribute :display_delivery_total do |order|
38
+ order.display_ship_total.to_s
39
+ end
40
+
33
41
  attribute :current_step do |order|
34
42
  order.current_checkout_step
35
43
  end
@@ -44,7 +52,7 @@ module Spree
44
52
 
45
53
  many :cart_promotions, key: :promotions, resource: Spree.api.cart_promotion_serializer
46
54
  many :line_items, key: :items, resource: Spree.api.line_item_serializer
47
- many :shipments, resource: Spree.api.shipment_serializer
55
+ many :shipments, key: :fulfillments, resource: Spree.api.fulfillment_serializer
48
56
  many :payments, resource: Spree.api.payment_serializer
49
57
  one :bill_address, resource: Spree.api.address_serializer
50
58
  one :ship_address, resource: Spree.api.address_serializer
@@ -1,7 +1,7 @@
1
1
  module Spree
2
2
  module Api
3
3
  module V3
4
- class ShippingMethodSerializer < BaseSerializer
4
+ class DeliveryMethodSerializer < BaseSerializer
5
5
  typelize name: :string, code: [:string, nullable: true]
6
6
 
7
7
  attributes :name, :code
@@ -1,11 +1,11 @@
1
1
  module Spree
2
2
  module Api
3
3
  module V3
4
- class ShippingRateSerializer < BaseSerializer
5
- typelize name: :string, selected: :boolean, shipping_method_id: :string,
4
+ class DeliveryRateSerializer < BaseSerializer
5
+ typelize name: :string, selected: :boolean, delivery_method_id: :string,
6
6
  cost: :string, display_cost: :string
7
7
 
8
- attribute :shipping_method_id do |shipping_rate|
8
+ attribute :delivery_method_id do |shipping_rate|
9
9
  shipping_rate.shipping_method&.prefixed_id
10
10
  end
11
11
 
@@ -15,7 +15,7 @@ module Spree
15
15
  shipping_rate.display_cost.to_s
16
16
  end
17
17
 
18
- one :shipping_method, resource: Spree.api.shipping_method_serializer
18
+ one :shipping_method, key: :delivery_method, resource: Spree.api.delivery_method_serializer
19
19
  end
20
20
  end
21
21
  end