spree_api 5.4.0.beta6 → 5.4.0.beta8

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 (43) 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 +22 -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/{orders → carts}/payments_controller.rb +18 -29
  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/customer/password_resets_controller.rb +89 -0
  16. data/app/controllers/spree/api/v3/store/orders_controller.rb +21 -114
  17. data/app/controllers/spree/api/v3/store/products_controller.rb +1 -1
  18. data/app/controllers/spree/api/v3/webhooks/payments_controller.rb +52 -0
  19. data/app/serializers/spree/api/v3/admin/allowed_origin_serializer.rb +21 -0
  20. data/app/serializers/spree/api/v3/admin/media_serializer.rb +17 -0
  21. data/app/serializers/spree/api/v3/admin/order_serializer.rb +2 -2
  22. data/app/serializers/spree/api/v3/admin/product_serializer.rb +8 -4
  23. data/app/serializers/spree/api/v3/admin/variant_serializer.rb +8 -3
  24. data/app/serializers/spree/api/v3/base_serializer.rb +1 -1
  25. data/app/serializers/spree/api/v3/cart_promotion_serializer.rb +18 -0
  26. data/app/serializers/spree/api/v3/cart_serializer.rb +56 -0
  27. data/app/serializers/spree/api/v3/media_serializer.rb +60 -0
  28. data/app/serializers/spree/api/v3/order_serializer.rb +7 -9
  29. data/app/serializers/spree/api/v3/product_serializer.rb +10 -6
  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 +23 -24
  33. data/lib/spree/api/configuration.rb +1 -0
  34. data/lib/spree/api/dependencies.rb +4 -2
  35. data/lib/spree/api/openapi/schema_helper.rb +28 -0
  36. metadata +22 -17
  37. data/app/controllers/concerns/spree/api/v3/order_concern.rb +0 -46
  38. data/app/controllers/spree/api/v3/store/cart_controller.rb +0 -97
  39. data/app/controllers/spree/api/v3/store/orders/coupon_codes_controller.rb +0 -73
  40. data/app/controllers/spree/api/v3/store/orders/payment_methods_controller.rb +0 -43
  41. data/app/controllers/spree/api/v3/store/orders/shipments_controller.rb +0 -56
  42. data/app/serializers/spree/api/v3/admin/image_serializer.rb +0 -10
  43. data/app/serializers/spree/api/v3/image_serializer.rb +0 -43
@@ -0,0 +1,60 @@
1
+ module Spree
2
+ module Api
3
+ module V3
4
+ class MediaSerializer < BaseSerializer
5
+ typelize position: :number, alt: [:string, nullable: true],
6
+ product_id: [:string, nullable: true],
7
+ variant_ids: [:string, multi: true],
8
+ media_type: :string,
9
+ focal_point_x: [:number, nullable: true],
10
+ focal_point_y: [:number, nullable: true],
11
+ external_video_url: [:string, nullable: true],
12
+ original_url: [:string, nullable: true], mini_url: [:string, nullable: true],
13
+ small_url: [:string, nullable: true], medium_url: [:string, nullable: true],
14
+ large_url: [:string, nullable: true], xlarge_url: [:string, nullable: true],
15
+ og_image_url: [:string, nullable: true]
16
+
17
+ attribute :product_id do |asset|
18
+ asset.product&.prefixed_id
19
+ end
20
+
21
+ # Returns prefixed IDs of variants this media is associated with.
22
+ # Currently: single variant via viewable (legacy). In 6.0: multiple via VariantMedia join table.
23
+ attribute :variant_ids do |asset|
24
+ if asset.viewable_type == 'Spree::Variant'
25
+ [asset.viewable&.prefixed_id].compact
26
+ else
27
+ []
28
+ end
29
+ end
30
+
31
+ attributes :position, :alt, :media_type,
32
+ :focal_point_x, :focal_point_y, :external_video_url,
33
+ created_at: :iso8601, updated_at: :iso8601
34
+
35
+ attribute :original_url do |asset|
36
+ image_url_for(asset)
37
+ end
38
+
39
+ # Dynamically define attributes for each configured image variant
40
+ # Uses named variants from Spree::Config.product_image_variant_sizes
41
+ # (e.g., mini, small, medium, large, xlarge)
42
+ Spree::Config.product_image_variant_sizes.each_key do |variant_name|
43
+ attribute :"#{variant_name}_url" do |asset|
44
+ variant_url(asset, variant_name)
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def variant_url(asset, variant_name)
51
+ return nil unless asset&.attachment&.attached?
52
+
53
+ Rails.application.routes.url_helpers.cdn_image_url(
54
+ asset.attachment.variant(variant_name)
55
+ )
56
+ end
57
+ end
58
+ end
59
+ end
60
+ 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
@@ -40,9 +40,9 @@ module Spree
40
40
  product.default_variant&.prefixed_id
41
41
  end
42
42
 
43
- # Main product image URL for listings (cached thumbnail)
43
+ # Main product image URL for listings (cached primary_media)
44
44
  attribute :thumbnail_url do |product|
45
- image_url_for(product.thumbnail)
45
+ image_url_for(product.primary_media)
46
46
  end
47
47
 
48
48
  attribute :tags do |product|
@@ -68,10 +68,14 @@ module Spree
68
68
  end
69
69
 
70
70
  # Conditional associations
71
- many :variant_images,
72
- key: :images,
73
- resource: Spree.api.image_serializer,
74
- if: proc { expand?('images') }
71
+ one :primary_media,
72
+ resource: Spree.api.media_serializer,
73
+ if: proc { expand?('primary_media') }
74
+
75
+ many :gallery_media,
76
+ key: :media,
77
+ resource: Spree.api.media_serializer,
78
+ if: proc { expand?('media') }
75
79
 
76
80
  many :variants,
77
81
  resource: Spree.api.variant_serializer,
@@ -5,8 +5,8 @@ module Spree
5
5
  # Customer-facing variant data with limited fields
6
6
  class VariantSerializer < BaseSerializer
7
7
  typelize product_id: :string, sku: [:string, nullable: true],
8
- is_master: :boolean, options_text: :string, track_inventory: :boolean, image_count: :number,
9
- thumbnail: [:string, nullable: true],
8
+ is_master: :boolean, options_text: :string, track_inventory: :boolean, media_count: :number,
9
+ thumbnail_url: [:string, nullable: true],
10
10
  purchasable: :boolean, in_stock: :boolean, backorderable: :boolean,
11
11
  weight: [:number, nullable: true], height: [:number, nullable: true], width: [:number, nullable: true], depth: [:number, nullable: true],
12
12
  price: 'Price',
@@ -16,12 +16,12 @@ module Spree
16
16
  variant.product&.prefixed_id
17
17
  end
18
18
 
19
- attributes :sku, :is_master, :options_text, :track_inventory, :image_count,
19
+ attributes :sku, :is_master, :options_text, :track_inventory, :media_count,
20
20
  created_at: :iso8601, updated_at: :iso8601
21
21
 
22
- # Main variant image URL for listings (cached thumbnail)
23
- attribute :thumbnail do |variant|
24
- image_url_for(variant.thumbnail)
22
+ # Main variant image URL for listings (cached primary_media)
23
+ attribute :thumbnail_url do |variant|
24
+ image_url_for(variant.primary_media)
25
25
  end
26
26
 
27
27
  attribute :purchasable do |variant|
@@ -70,9 +70,14 @@ module Spree
70
70
  end
71
71
 
72
72
  # Conditional associations
73
- many :images,
74
- resource: Spree.api.image_serializer,
75
- if: proc { expand?('images') }
73
+ one :primary_media,
74
+ resource: Spree.api.media_serializer,
75
+ if: proc { expand?('primary_media') }
76
+
77
+ many :gallery_media,
78
+ key: :media,
79
+ resource: Spree.api.media_serializer,
80
+ if: proc { expand?('media') }
76
81
 
77
82
  many :option_values, resource: Spree.api.option_value_serializer
78
83
 
@@ -7,6 +7,9 @@ en:
7
7
  invalid_resource: Invalid resource. Please fix errors and try again.
8
8
  invalid_taxonomy_id: Invalid taxonomy id.
9
9
  current_password_invalid: Current password is invalid or missing
10
+ password_reset_requested: If an account exists for that email, password reset instructions have been sent.
11
+ password_reset_token_invalid: Password reset token is invalid or has expired.
12
+ redirect_url_not_allowed: The redirect URL is not from an allowed origin for this store.
10
13
  must_specify_api_key: You must specify an API key.
11
14
  negative_quantity: quantity is negative
12
15
  order:
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,43 @@ 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, :create], 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 :password_resets, only: [:create, :update]
63
+
64
+ resources :orders, only: [:index, :show]
70
65
  resources :addresses, only: [:index, :show, :create, :update, :destroy] do
71
66
  member do
72
67
  patch :mark_as_default
73
68
  end
74
69
  end
75
- resources :orders, only: [:index]
76
70
  resources :credit_cards, only: [:index, :show, :destroy]
77
71
  resources :gift_cards, only: [:index, :show]
78
72
  resources :payment_setup_sessions, only: [:create, :show] do
@@ -92,6 +86,11 @@ Spree::Core::Engine.add_routes do
92
86
  get 'digitals/:token', to: 'digitals#show', as: :digital_download
93
87
 
94
88
  end
89
+
90
+ # Webhooks (outside of store namespace — no API key authentication)
91
+ namespace :webhooks do
92
+ post 'payments/:payment_method_id', to: 'payments#create', as: :payment_webhook
93
+ end
95
94
  end
96
95
  end
97
96
  end
@@ -19,6 +19,7 @@ module Spree
19
19
  preference :rate_limit_register, :integer, default: 3 # per IP
20
20
  preference :rate_limit_refresh, :integer, default: 10 # per IP
21
21
  preference :rate_limit_oauth, :integer, default: 5 # per IP
22
+ preference :rate_limit_password_reset, :integer, default: 3 # per IP
22
23
 
23
24
  # Request body size limit in bytes
24
25
  preference :max_request_body_size, :integer, default: 102_400 # 100KB
@@ -96,9 +96,10 @@ module Spree
96
96
  price_serializer: 'Spree::Api::V3::PriceSerializer',
97
97
  product_serializer: 'Spree::Api::V3::ProductSerializer',
98
98
  variant_serializer: 'Spree::Api::V3::VariantSerializer',
99
- image_serializer: 'Spree::Api::V3::ImageSerializer',
99
+ media_serializer: 'Spree::Api::V3::MediaSerializer',
100
100
  option_type_serializer: 'Spree::Api::V3::OptionTypeSerializer',
101
101
  option_value_serializer: 'Spree::Api::V3::OptionValueSerializer',
102
+ cart_serializer: 'Spree::Api::V3::CartSerializer',
102
103
  order_serializer: 'Spree::Api::V3::OrderSerializer',
103
104
  line_item_serializer: 'Spree::Api::V3::LineItemSerializer',
104
105
  payment_serializer: 'Spree::Api::V3::PaymentSerializer',
@@ -119,6 +120,7 @@ module Spree
119
120
  shipping_rate_serializer: 'Spree::Api::V3::ShippingRateSerializer',
120
121
  stock_location_serializer: 'Spree::Api::V3::StockLocationSerializer',
121
122
  category_serializer: 'Spree::Api::V3::CategorySerializer',
123
+ cart_promotion_serializer: 'Spree::Api::V3::CartPromotionSerializer',
122
124
  order_promotion_serializer: 'Spree::Api::V3::OrderPromotionSerializer',
123
125
  digital_link_serializer: 'Spree::Api::V3::DigitalLinkSerializer',
124
126
  gift_card_serializer: 'Spree::Api::V3::GiftCardSerializer',
@@ -159,7 +161,7 @@ module Spree
159
161
  admin_line_item_serializer: 'Spree::Api::V3::Admin::LineItemSerializer',
160
162
  admin_option_type_serializer: 'Spree::Api::V3::Admin::OptionTypeSerializer',
161
163
  admin_option_value_serializer: 'Spree::Api::V3::Admin::OptionValueSerializer',
162
- admin_image_serializer: 'Spree::Api::V3::Admin::ImageSerializer',
164
+ admin_media_serializer: 'Spree::Api::V3::Admin::MediaSerializer',
163
165
  admin_asset_serializer: 'Spree::Api::V3::Admin::AssetSerializer',
164
166
  admin_stock_item_serializer: 'Spree::Api::V3::Admin::StockItemSerializer',
165
167
  admin_shipment_serializer: 'Spree::Api::V3::Admin::ShipmentSerializer',
@@ -84,6 +84,15 @@ module Spree
84
84
  user: { '$ref' => '#/components/schemas/Customer' }
85
85
  },
86
86
  required: %w[token user]
87
+ },
88
+ CheckoutRequirement: {
89
+ type: :object,
90
+ properties: {
91
+ step: { type: :string, description: 'Checkout step this requirement belongs to', example: 'payment' },
92
+ field: { type: :string, description: 'Field that needs to be satisfied', example: 'payment' },
93
+ message: { type: :string, description: 'Human-readable requirement message', example: 'Add a payment method' }
94
+ },
95
+ required: %w[step field message]
87
96
  }
88
97
  }
89
98
  end
@@ -110,10 +119,29 @@ module Spree
110
119
  s[:'x-typelizer'] = true
111
120
  strip_null_from_enums(s)
112
121
  end
122
+ patch_cart_schema(schemas)
113
123
  schemas
114
124
  end
115
125
  end
116
126
 
127
+ # Typelizer cannot represent Array<{...}> inline object types in OpenAPI,
128
+ # so we patch them to reference manually-defined component schemas.
129
+ def patch_cart_schema(schemas)
130
+ cart = schemas['Cart'] || schemas[:Cart]
131
+ return unless cart
132
+
133
+ props = cart[:properties]
134
+ return unless props
135
+
136
+ req_key = props.key?('requirements') ? 'requirements' : :requirements
137
+ if props[req_key]
138
+ props[req_key] = {
139
+ type: :array,
140
+ items: { '$ref' => '#/components/schemas/CheckoutRequirement' }
141
+ }
142
+ end
143
+ end
144
+
117
145
  # Typelizer adds nil to enum arrays for nullable fields.
118
146
  # OpenAPI 3.0 handles nullability via `nullable: true`, so the nil entry is redundant
119
147
  # and causes issues with code generators.
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.beta6
4
+ version: 5.4.0.beta8
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 00:00:00.000000000 Z
11
+ date: 2026-03-16 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.beta6
89
+ version: 5.4.0.beta8
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.beta6
96
+ version: 5.4.0.beta8
97
97
  description: Spree's API
98
98
  email:
99
99
  - hello@spreecommerce.org
@@ -104,12 +104,12 @@ files:
104
104
  - README.md
105
105
  - Rakefile
106
106
  - app/controllers/concerns/spree/api/v3/api_key_authentication.rb
107
+ - app/controllers/concerns/spree/api/v3/cart_resolvable.rb
107
108
  - app/controllers/concerns/spree/api/v3/error_handler.rb
108
109
  - app/controllers/concerns/spree/api/v3/http_caching.rb
109
110
  - app/controllers/concerns/spree/api/v3/idempotent.rb
110
111
  - app/controllers/concerns/spree/api/v3/jwt_authentication.rb
111
112
  - app/controllers/concerns/spree/api/v3/locale_and_currency.rb
112
- - app/controllers/concerns/spree/api/v3/order_concern.rb
113
113
  - app/controllers/concerns/spree/api/v3/order_lock.rb
114
114
  - app/controllers/concerns/spree/api/v3/rate_limit_headers.rb
115
115
  - app/controllers/concerns/spree/api/v3/resource_serializer.rb
@@ -120,7 +120,14 @@ files:
120
120
  - app/controllers/spree/api/v3/resource_controller.rb
121
121
  - app/controllers/spree/api/v3/store/auth_controller.rb
122
122
  - app/controllers/spree/api/v3/store/base_controller.rb
123
- - app/controllers/spree/api/v3/store/cart_controller.rb
123
+ - app/controllers/spree/api/v3/store/carts/coupon_codes_controller.rb
124
+ - app/controllers/spree/api/v3/store/carts/items_controller.rb
125
+ - app/controllers/spree/api/v3/store/carts/payment_methods_controller.rb
126
+ - app/controllers/spree/api/v3/store/carts/payment_sessions_controller.rb
127
+ - app/controllers/spree/api/v3/store/carts/payments_controller.rb
128
+ - app/controllers/spree/api/v3/store/carts/shipments_controller.rb
129
+ - app/controllers/spree/api/v3/store/carts/store_credits_controller.rb
130
+ - app/controllers/spree/api/v3/store/carts_controller.rb
124
131
  - app/controllers/spree/api/v3/store/categories/products_controller.rb
125
132
  - app/controllers/spree/api/v3/store/categories_controller.rb
126
133
  - app/controllers/spree/api/v3/store/countries_controller.rb
@@ -129,38 +136,34 @@ files:
129
136
  - app/controllers/spree/api/v3/store/customer/credit_cards_controller.rb
130
137
  - app/controllers/spree/api/v3/store/customer/gift_cards_controller.rb
131
138
  - app/controllers/spree/api/v3/store/customer/orders_controller.rb
139
+ - app/controllers/spree/api/v3/store/customer/password_resets_controller.rb
132
140
  - app/controllers/spree/api/v3/store/customer/payment_setup_sessions_controller.rb
133
141
  - app/controllers/spree/api/v3/store/customers_controller.rb
134
142
  - app/controllers/spree/api/v3/store/digitals_controller.rb
135
143
  - app/controllers/spree/api/v3/store/locales_controller.rb
136
144
  - app/controllers/spree/api/v3/store/markets/countries_controller.rb
137
145
  - app/controllers/spree/api/v3/store/markets_controller.rb
138
- - app/controllers/spree/api/v3/store/orders/coupon_codes_controller.rb
139
- - app/controllers/spree/api/v3/store/orders/line_items_controller.rb
140
- - app/controllers/spree/api/v3/store/orders/payment_methods_controller.rb
141
- - app/controllers/spree/api/v3/store/orders/payment_sessions_controller.rb
142
- - app/controllers/spree/api/v3/store/orders/payments_controller.rb
143
- - app/controllers/spree/api/v3/store/orders/shipments_controller.rb
144
- - app/controllers/spree/api/v3/store/orders/store_credits_controller.rb
145
146
  - app/controllers/spree/api/v3/store/orders_controller.rb
146
147
  - app/controllers/spree/api/v3/store/products/filters_controller.rb
147
148
  - app/controllers/spree/api/v3/store/products_controller.rb
148
149
  - app/controllers/spree/api/v3/store/resource_controller.rb
149
150
  - app/controllers/spree/api/v3/store/wishlist_items_controller.rb
150
151
  - app/controllers/spree/api/v3/store/wishlists_controller.rb
152
+ - app/controllers/spree/api/v3/webhooks/payments_controller.rb
151
153
  - app/jobs/spree/api_keys/mark_as_used.rb
152
154
  - app/jobs/spree/webhook_delivery_job.rb
153
155
  - app/serializers/spree/api/v3/address_serializer.rb
154
156
  - app/serializers/spree/api/v3/admin/address_serializer.rb
155
157
  - app/serializers/spree/api/v3/admin/adjustment_serializer.rb
156
158
  - app/serializers/spree/api/v3/admin/admin_user_serializer.rb
159
+ - app/serializers/spree/api/v3/admin/allowed_origin_serializer.rb
157
160
  - app/serializers/spree/api/v3/admin/asset_serializer.rb
158
161
  - app/serializers/spree/api/v3/admin/category_serializer.rb
159
162
  - app/serializers/spree/api/v3/admin/credit_card_serializer.rb
160
163
  - app/serializers/spree/api/v3/admin/customer_serializer.rb
161
164
  - app/serializers/spree/api/v3/admin/digital_link_serializer.rb
162
- - app/serializers/spree/api/v3/admin/image_serializer.rb
163
165
  - app/serializers/spree/api/v3/admin/line_item_serializer.rb
166
+ - app/serializers/spree/api/v3/admin/media_serializer.rb
164
167
  - app/serializers/spree/api/v3/admin/metafield_serializer.rb
165
168
  - app/serializers/spree/api/v3/admin/option_type_serializer.rb
166
169
  - app/serializers/spree/api/v3/admin/option_value_serializer.rb
@@ -185,6 +188,8 @@ files:
185
188
  - app/serializers/spree/api/v3/admin/variant_serializer.rb
186
189
  - app/serializers/spree/api/v3/asset_serializer.rb
187
190
  - app/serializers/spree/api/v3/base_serializer.rb
191
+ - app/serializers/spree/api/v3/cart_promotion_serializer.rb
192
+ - app/serializers/spree/api/v3/cart_serializer.rb
188
193
  - app/serializers/spree/api/v3/category_serializer.rb
189
194
  - app/serializers/spree/api/v3/country_serializer.rb
190
195
  - app/serializers/spree/api/v3/credit_card_serializer.rb
@@ -196,13 +201,13 @@ files:
196
201
  - app/serializers/spree/api/v3/export_serializer.rb
197
202
  - app/serializers/spree/api/v3/gift_card_batch_serializer.rb
198
203
  - app/serializers/spree/api/v3/gift_card_serializer.rb
199
- - app/serializers/spree/api/v3/image_serializer.rb
200
204
  - app/serializers/spree/api/v3/import_row_serializer.rb
201
205
  - app/serializers/spree/api/v3/import_serializer.rb
202
206
  - app/serializers/spree/api/v3/invitation_serializer.rb
203
207
  - app/serializers/spree/api/v3/line_item_serializer.rb
204
208
  - app/serializers/spree/api/v3/locale_serializer.rb
205
209
  - app/serializers/spree/api/v3/market_serializer.rb
210
+ - app/serializers/spree/api/v3/media_serializer.rb
206
211
  - app/serializers/spree/api/v3/metafield_serializer.rb
207
212
  - app/serializers/spree/api/v3/newsletter_subscriber_serializer.rb
208
213
  - app/serializers/spree/api/v3/option_type_serializer.rb
@@ -263,9 +268,9 @@ licenses:
263
268
  - BSD-3-Clause
264
269
  metadata:
265
270
  bug_tracker_uri: https://github.com/spree/spree/issues
266
- changelog_uri: https://github.com/spree/spree/releases/tag/v5.4.0.beta6
271
+ changelog_uri: https://github.com/spree/spree/releases/tag/v5.4.0.beta8
267
272
  documentation_uri: https://docs.spreecommerce.org/
268
- source_code_uri: https://github.com/spree/spree/tree/v5.4.0.beta6
273
+ source_code_uri: https://github.com/spree/spree/tree/v5.4.0.beta8
269
274
  post_install_message:
270
275
  rdoc_options: []
271
276
  require_paths:
@@ -1,46 +0,0 @@
1
- module Spree
2
- module Api
3
- module V3
4
- module OrderConcern
5
- extend ActiveSupport::Concern
6
-
7
- # Allow access to order via order token for guests or authenticated users
8
- # Expects @parent to be set to the order
9
- def authorize_order_access!
10
- authorize!(:update, @parent, order_token)
11
- end
12
-
13
- def set_parent
14
- return if params[:order_id].blank?
15
-
16
- @parent = order_scope.find_by_prefix_id!(params[:order_id])
17
- end
18
-
19
- def order_scope
20
- base = current_store.orders
21
- base = if current_user
22
- base.where(user: current_user)
23
- elsif order_token.present?
24
- base.where(token: order_token)
25
- else
26
- base.none
27
- end
28
- base.preload_associations_lazily
29
- end
30
-
31
- protected
32
-
33
- # Render the parent order as JSON using the order serializer.
34
- # Use this when sub-resource mutations should return the updated order
35
- # (e.g., line items, coupon codes, store credits).
36
- def render_order(status: :ok)
37
- render json: Spree.api.order_serializer.new(@parent.reload, params: serializer_params).to_h, status: status
38
- end
39
-
40
- def order_token
41
- request.headers['x-spree-order-token']
42
- end
43
- end
44
- end
45
- end
46
- end
@@ -1,97 +0,0 @@
1
- module Spree
2
- module Api
3
- module V3
4
- module Store
5
- class CartController < Store::BaseController
6
- include Spree::Api::V3::OrderConcern
7
-
8
- before_action :require_authentication!, only: [:associate]
9
-
10
- # POST /api/v3/store/cart
11
- # Creates a new shopping cart (order)
12
- # Can be created by guests or authenticated customers
13
- def create
14
- result = Spree.cart_create_service.call(
15
- user: current_user,
16
- store: current_store,
17
- currency: current_currency,
18
- locale: current_locale,
19
- metadata: cart_params[:metadata] || {},
20
- line_items: cart_params[:line_items] || []
21
- )
22
-
23
- if result.success?
24
- @cart = result.value
25
- render json: serialize_resource(@cart), status: :created
26
- else
27
- render_service_error(result.error.to_s)
28
- end
29
- end
30
-
31
- # GET /api/v3/store/cart
32
- # Returns current incomplete order (cart)
33
- # Returns 404 if no cart exists - use POST /cart to create one
34
- # Authorize via order_token param or JWT Bearer token
35
- def show
36
- @cart = find_cart
37
-
38
- render json: serialize_resource(@cart)
39
- end
40
-
41
- # PATCH /api/v3/store/cart/associate
42
- # Associates a guest cart with the currently authenticated user
43
- # Requires: JWT authentication + order token (header or param)
44
- def associate
45
- @cart = find_cart_by_token
46
-
47
- result = Spree.cart_associate_service.call(guest_order: @cart, user: current_user, guest_only: true)
48
-
49
- if result.success?
50
- render json: serialize_resource(@cart)
51
- else
52
- render_service_error(result.error.to_s)
53
- end
54
- end
55
-
56
- protected
57
-
58
- def serializer_class
59
- Spree.api.order_serializer
60
- end
61
-
62
- private
63
-
64
- def cart_params
65
- params.permit(
66
- metadata: {},
67
- line_items: [:variant_id, :quantity, { metadata: {}, options: {} }]
68
- )
69
- end
70
-
71
- # Find incomplete cart by order token for associate action
72
- # Only finds guest carts (no user) or carts already owned by current user (idempotent)
73
- def find_cart_by_token
74
- current_store.orders.incomplete.where(user: [ nil, current_user ]).find_by!(token: order_token)
75
- end
76
-
77
- def find_cart
78
- scope = current_store.orders.incomplete
79
-
80
- # Try order_token first (guest checkout)
81
- if order_token.present?
82
- return scope.find_by!(token: order_token)
83
- end
84
-
85
- # Then try JWT authenticated user
86
- if current_user.present?
87
- cart = scope.where(user: current_user).order(created_at: :desc).first
88
- return cart if cart
89
- end
90
-
91
- raise ActiveRecord::RecordNotFound.new(nil, 'Spree::Order')
92
- end
93
- end
94
- end
95
- end
96
- end
97
- end