spree_api 5.4.3 → 5.5.0.rc1

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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +19 -0
  3. data/app/controllers/concerns/spree/api/v3/admin/auth_cookies.rb +62 -0
  4. data/app/controllers/concerns/spree/api/v3/admin/subclassed_resource.rb +149 -0
  5. data/app/controllers/concerns/spree/api/v3/admin_authentication.rb +54 -0
  6. data/app/controllers/concerns/spree/api/v3/bulk_operations.rb +103 -0
  7. data/app/controllers/concerns/spree/api/v3/channel_resolution.rb +60 -0
  8. data/app/controllers/concerns/spree/api/v3/error_handler.rb +4 -0
  9. data/app/controllers/concerns/spree/api/v3/params_normalizer.rb +84 -0
  10. data/app/controllers/concerns/spree/api/v3/scoped_authorization.rb +88 -0
  11. data/app/controllers/concerns/spree/api/v3/store/search_provider_support.rb +35 -1
  12. data/app/controllers/spree/api/v3/admin/admin_users_controller.rb +97 -0
  13. data/app/controllers/spree/api/v3/admin/allowed_origins_controller.rb +25 -0
  14. data/app/controllers/spree/api/v3/admin/api_keys_controller.rb +55 -0
  15. data/app/controllers/spree/api/v3/admin/auth_controller.rb +134 -0
  16. data/app/controllers/spree/api/v3/admin/base_controller.rb +3 -17
  17. data/app/controllers/spree/api/v3/admin/categories_controller.rb +25 -0
  18. data/app/controllers/spree/api/v3/admin/channels_controller.rb +65 -0
  19. data/app/controllers/spree/api/v3/admin/countries_controller.rb +38 -0
  20. data/app/controllers/spree/api/v3/admin/coupon_codes_controller.rb +33 -0
  21. data/app/controllers/spree/api/v3/admin/custom_field_definitions_controller.rb +34 -0
  22. data/app/controllers/spree/api/v3/admin/custom_fields_controller.rb +108 -0
  23. data/app/controllers/spree/api/v3/admin/customer_groups_controller.rb +31 -0
  24. data/app/controllers/spree/api/v3/admin/customers/addresses_controller.rb +88 -0
  25. data/app/controllers/spree/api/v3/admin/customers/credit_cards_controller.rb +31 -0
  26. data/app/controllers/spree/api/v3/admin/customers/store_credits_controller.rb +93 -0
  27. data/app/controllers/spree/api/v3/admin/customers_controller.rb +119 -0
  28. data/app/controllers/spree/api/v3/admin/dashboard_controller.rb +44 -0
  29. data/app/controllers/spree/api/v3/admin/direct_uploads_controller.rb +40 -0
  30. data/app/controllers/spree/api/v3/admin/exports_controller.rb +89 -0
  31. data/app/controllers/spree/api/v3/admin/gift_card_batches_controller.rb +31 -0
  32. data/app/controllers/spree/api/v3/admin/gift_cards_controller.rb +33 -0
  33. data/app/controllers/spree/api/v3/admin/invitation_acceptances_controller.rb +138 -0
  34. data/app/controllers/spree/api/v3/admin/invitations_controller.rb +70 -0
  35. data/app/controllers/spree/api/v3/admin/markets_controller.rb +42 -0
  36. data/app/controllers/spree/api/v3/admin/me_controller.rb +69 -0
  37. data/app/controllers/spree/api/v3/admin/media_controller.rb +119 -0
  38. data/app/controllers/spree/api/v3/admin/option_types_controller.rb +34 -0
  39. data/app/controllers/spree/api/v3/admin/orders/adjustments_controller.rb +27 -0
  40. data/app/controllers/spree/api/v3/admin/orders/base_controller.rb +26 -0
  41. data/app/controllers/spree/api/v3/admin/orders/fulfillments_controller.rb +104 -0
  42. data/app/controllers/spree/api/v3/admin/orders/gift_cards_controller.rb +79 -0
  43. data/app/controllers/spree/api/v3/admin/orders/items_controller.rb +92 -0
  44. data/app/controllers/spree/api/v3/admin/orders/payments_controller.rb +90 -0
  45. data/app/controllers/spree/api/v3/admin/orders/refunds_controller.rb +53 -0
  46. data/app/controllers/spree/api/v3/admin/orders/store_credits_controller.rb +59 -0
  47. data/app/controllers/spree/api/v3/admin/orders_controller.rb +190 -0
  48. data/app/controllers/spree/api/v3/admin/payment_methods_controller.rb +73 -0
  49. data/app/controllers/spree/api/v3/admin/price_lists_controller.rb +156 -0
  50. data/app/controllers/spree/api/v3/admin/prices_controller.rb +129 -0
  51. data/app/controllers/spree/api/v3/admin/products/variants_controller.rb +48 -0
  52. data/app/controllers/spree/api/v3/admin/products_controller.rb +237 -0
  53. data/app/controllers/spree/api/v3/admin/promotion_actions_controller.rb +78 -0
  54. data/app/controllers/spree/api/v3/admin/promotion_rules_controller.rb +56 -0
  55. data/app/controllers/spree/api/v3/admin/promotions_controller.rb +78 -0
  56. data/app/controllers/spree/api/v3/admin/resource_controller.rb +29 -11
  57. data/app/controllers/spree/api/v3/admin/roles_controller.rb +29 -0
  58. data/app/controllers/spree/api/v3/admin/stock_items_controller.rb +35 -0
  59. data/app/controllers/spree/api/v3/admin/stock_locations_controller.rb +36 -0
  60. data/app/controllers/spree/api/v3/admin/stock_reservations_controller.rb +29 -0
  61. data/app/controllers/spree/api/v3/admin/stock_transfers_controller.rb +75 -0
  62. data/app/controllers/spree/api/v3/admin/store_controller.rb +53 -0
  63. data/app/controllers/spree/api/v3/admin/store_credit_categories_controller.rb +21 -0
  64. data/app/controllers/spree/api/v3/admin/tags_controller.rb +51 -0
  65. data/app/controllers/spree/api/v3/admin/tax_categories_controller.rb +21 -0
  66. data/app/controllers/spree/api/v3/admin/variants_controller.rb +33 -0
  67. data/app/controllers/spree/api/v3/admin/webhook_deliveries_controller.rb +49 -0
  68. data/app/controllers/spree/api/v3/admin/webhook_endpoints_controller.rb +75 -0
  69. data/app/controllers/spree/api/v3/resource_controller.rb +90 -8
  70. data/app/controllers/spree/api/v3/store/auth_controller.rb +8 -28
  71. data/app/controllers/spree/api/v3/store/base_controller.rb +6 -0
  72. data/app/controllers/spree/api/v3/store/carts_controller.rb +1 -0
  73. data/app/controllers/spree/api/v3/store/customers_controller.rb +6 -0
  74. data/app/controllers/spree/api/v3/store/newsletter_subscribers_controller.rb +77 -0
  75. data/app/controllers/spree/api/v3/store/products/filters_controller.rb +2 -2
  76. data/app/controllers/spree/api/v3/store/products_controller.rb +3 -3
  77. data/app/controllers/spree/api/v3/store/resource_controller.rb +10 -2
  78. data/app/jobs/spree/webhook_delivery_job.rb +5 -0
  79. data/app/models/spree/api_key_ability.rb +16 -0
  80. data/app/serializers/spree/api/v3/admin/address_serializer.rb +2 -6
  81. data/app/serializers/spree/api/v3/admin/adjustment_serializer.rb +3 -15
  82. data/app/serializers/spree/api/v3/admin/admin_user_serializer.rb +19 -3
  83. data/app/serializers/spree/api/v3/admin/allowed_origin_serializer.rb +2 -6
  84. data/app/serializers/spree/api/v3/admin/api_key_serializer.rb +42 -0
  85. data/app/serializers/spree/api/v3/admin/category_serializer.rb +4 -3
  86. data/app/serializers/spree/api/v3/admin/channel_serializer.rb +15 -0
  87. data/app/serializers/spree/api/v3/admin/country_serializer.rb +1 -1
  88. data/app/serializers/spree/api/v3/admin/coupon_code_serializer.rb +30 -0
  89. data/app/serializers/spree/api/v3/admin/credit_card_serializer.rb +4 -2
  90. data/app/serializers/spree/api/v3/admin/custom_field_definition_serializer.rb +21 -0
  91. data/app/serializers/spree/api/v3/admin/custom_field_serializer.rb +8 -3
  92. data/app/serializers/spree/api/v3/admin/customer_group_serializer.rb +27 -0
  93. data/app/serializers/spree/api/v3/admin/customer_serializer.rb +58 -2
  94. data/app/serializers/spree/api/v3/admin/dashboard_analytics_serializer.rb +143 -0
  95. data/app/serializers/spree/api/v3/admin/export_serializer.rb +40 -0
  96. data/app/serializers/spree/api/v3/admin/fulfillment_serializer.rb +2 -6
  97. data/app/serializers/spree/api/v3/admin/{asset_serializer.rb → gift_card_batch_serializer.rb} +1 -1
  98. data/app/serializers/spree/api/v3/admin/gift_card_serializer.rb +39 -4
  99. data/app/serializers/spree/api/v3/admin/invitation_serializer.rb +64 -0
  100. data/app/serializers/spree/api/v3/admin/line_item_serializer.rb +4 -16
  101. data/app/serializers/spree/api/v3/admin/media_serializer.rb +24 -2
  102. data/app/serializers/spree/api/v3/admin/option_type_serializer.rb +4 -1
  103. data/app/serializers/spree/api/v3/admin/option_value_serializer.rb +4 -1
  104. data/app/serializers/spree/api/v3/admin/order_serializer.rb +21 -6
  105. data/app/serializers/spree/api/v3/admin/payment_method_serializer.rb +11 -2
  106. data/app/serializers/spree/api/v3/admin/payment_serializer.rb +2 -6
  107. data/app/serializers/spree/api/v3/admin/payment_source_serializer.rb +4 -1
  108. data/app/serializers/spree/api/v3/admin/price_list_serializer.rb +51 -0
  109. data/app/serializers/spree/api/v3/admin/price_rule_serializer.rb +55 -0
  110. data/app/serializers/spree/api/v3/admin/price_serializer.rb +4 -0
  111. data/app/serializers/spree/api/v3/admin/product_publication_serializer.rb +11 -0
  112. data/app/serializers/spree/api/v3/admin/product_serializer.rb +34 -10
  113. data/app/serializers/spree/api/v3/admin/promotion_action_serializer.rb +71 -0
  114. data/app/serializers/spree/api/v3/admin/promotion_rule_serializer.rb +85 -0
  115. data/app/serializers/spree/api/v3/admin/promotion_serializer.rb +41 -0
  116. data/app/serializers/spree/api/v3/admin/refund_serializer.rb +4 -2
  117. data/app/serializers/spree/api/v3/admin/role_serializer.rb +17 -0
  118. data/app/serializers/spree/api/v3/admin/stock_item_serializer.rb +16 -1
  119. data/app/serializers/spree/api/v3/admin/stock_location_serializer.rb +11 -2
  120. data/app/serializers/spree/api/v3/admin/stock_reservation_serializer.rb +46 -0
  121. data/app/serializers/spree/api/v3/admin/stock_transfer_serializer.rb +37 -0
  122. data/app/serializers/spree/api/v3/admin/store_credit_category_serializer.rb +19 -0
  123. data/app/serializers/spree/api/v3/admin/store_credit_serializer.rb +11 -5
  124. data/app/serializers/spree/api/v3/admin/store_serializer.rb +55 -0
  125. data/app/serializers/spree/api/v3/admin/tax_category_serializer.rb +4 -2
  126. data/app/serializers/spree/api/v3/admin/variant_serializer.rb +37 -6
  127. data/app/serializers/spree/api/v3/admin/webhook_delivery_serializer.rb +45 -0
  128. data/app/serializers/spree/api/v3/admin/webhook_endpoint_serializer.rb +69 -0
  129. data/app/serializers/spree/api/v3/channel_serializer.rb +14 -0
  130. data/app/serializers/spree/api/v3/custom_field_serializer.rb +9 -10
  131. data/app/serializers/spree/api/v3/customer_serializer.rb +5 -0
  132. data/app/serializers/spree/api/v3/market_serializer.rb +2 -1
  133. data/app/serializers/spree/api/v3/media_serializer.rb +8 -6
  134. data/app/serializers/spree/api/v3/order_serializer.rb +6 -1
  135. data/app/serializers/spree/api/v3/payment_method_serializer.rb +11 -2
  136. data/app/serializers/spree/api/v3/product_publication_serializer.rb +22 -0
  137. data/app/serializers/spree/api/v3/product_serializer.rb +6 -1
  138. data/app/serializers/spree/api/v3/stock_reservation_serializer.rb +10 -0
  139. data/config/locales/en.yml +2 -0
  140. data/config/routes.rb +235 -1
  141. data/lib/spree/api/configuration.rb +2 -2
  142. data/lib/spree/api/dependencies.rb +25 -1
  143. data/lib/spree/api/openapi/path_sorter.rb +126 -0
  144. data/lib/spree/api/openapi/schema_helper.rb +185 -6
  145. metadata +96 -8
  146. data/app/serializers/spree/api/v3/admin/shipping_category_serializer.rb +0 -14
@@ -3,7 +3,10 @@ module Spree
3
3
  module V3
4
4
  module Admin
5
5
  class OptionTypeSerializer < V3::OptionTypeSerializer
6
- attributes created_at: :iso8601, updated_at: :iso8601
6
+ typelize metadata: 'Record<string, unknown>', filterable: :boolean
7
+
8
+ attributes :metadata, :filterable,
9
+ created_at: :iso8601, updated_at: :iso8601
7
10
 
8
11
  many :option_values,
9
12
  resource: Spree.api.admin_option_value_serializer,
@@ -3,7 +3,10 @@ module Spree
3
3
  module V3
4
4
  module Admin
5
5
  class OptionValueSerializer < V3::OptionValueSerializer
6
- attributes created_at: :iso8601, updated_at: :iso8601
6
+ typelize metadata: 'Record<string, unknown>'
7
+
8
+ attributes :metadata,
9
+ created_at: :iso8601, updated_at: :iso8601
7
10
 
8
11
  one :option_type,
9
12
  resource: Spree.api.admin_option_type_serializer,
@@ -6,25 +6,36 @@ module Spree
6
6
  # Full order data including admin-only fields
7
7
  class OrderSerializer < V3::OrderSerializer
8
8
 
9
- typelize last_ip_address: [:string, nullable: true],
9
+ typelize status: :string,
10
+ last_ip_address: [:string, nullable: true],
10
11
  considered_risky: :boolean, confirmation_delivered: :boolean,
11
12
  store_owner_notification_delivered: :boolean,
12
13
  internal_note: [:string, nullable: true], approver_id: [:string, nullable: true],
13
14
  canceler_id: [:string, nullable: true], created_by_id: [:string, nullable: true],
14
15
  customer_id: [:string, nullable: true],
16
+ preferred_stock_location_id: [:string, nullable: true],
15
17
  canceled_at: [:string, nullable: true], approved_at: [:string, nullable: true],
16
18
  payment_total: :string, display_payment_total: :string,
17
- metadata: 'Record<string, unknown> | null'
19
+ tags: [:string, multi: true],
20
+ metadata: 'Record<string, unknown>'
18
21
 
19
22
  # Admin-only attributes
20
- attributes :last_ip_address, :considered_risky,
23
+ attributes :status, :last_ip_address, :considered_risky,
21
24
  :confirmation_delivered, :store_owner_notification_delivered,
22
- :internal_note, :payment_total, :display_payment_total,
25
+ :payment_total, :display_payment_total, :metadata,
23
26
  canceled_at: :iso8601, approved_at: :iso8601,
24
27
  created_at: :iso8601, updated_at: :iso8601
25
28
 
26
- attribute :metadata do |order|
27
- order.metadata.presence
29
+ attribute :preferred_stock_location_id do |order|
30
+ order.preferred_stock_location&.prefixed_id
31
+ end
32
+
33
+ attribute :tags do |order|
34
+ order.tag_list.to_a
35
+ end
36
+
37
+ attribute :internal_note do |order|
38
+ order.internal_note&.to_plain_text.presence
28
39
  end
29
40
 
30
41
  attribute :approver_id do |order|
@@ -53,6 +64,10 @@ module Spree
53
64
  one :shipping_address, resource: Spree.api.admin_address_serializer, if: proc { expand?('shipping_address') }
54
65
  one :gift_card, resource: Spree.api.admin_gift_card_serializer
55
66
  one :market, resource: Spree.api.admin_market_serializer
67
+ one :channel, resource: Spree.api.admin_channel_serializer, if: proc { expand?('channel') }
68
+ one :preferred_stock_location,
69
+ resource: Spree.api.admin_stock_location_serializer,
70
+ if: proc { expand?('preferred_stock_location') }
56
71
 
57
72
  many :payment_methods, resource: Spree.api.admin_payment_method_serializer, if: proc { expand?('payment_methods') }
58
73
 
@@ -3,10 +3,19 @@ module Spree
3
3
  module V3
4
4
  module Admin
5
5
  class PaymentMethodSerializer < V3::PaymentMethodSerializer
6
- typelize active: :boolean, auto_capture: [:boolean, nullable: true]
6
+ typelize active: :boolean,
7
+ auto_capture: [:boolean, nullable: true],
8
+ storefront_visible: :boolean,
9
+ position: :number,
10
+ metadata: 'Record<string, unknown>',
11
+ preferences: 'Record<string, unknown>',
12
+ preference_schema: "Array<{ key: string; type: string; default: unknown }>"
7
13
 
8
- attributes :active, :auto_capture,
14
+ attributes :metadata, :active, :auto_capture, :storefront_visible, :position,
9
15
  created_at: :iso8601, updated_at: :iso8601
16
+
17
+ attribute :preferences, &:serialized_preferences
18
+ attribute :preference_schema, &:serialized_preference_schema
10
19
  end
11
20
  end
12
21
  end
@@ -3,20 +3,16 @@ module Spree
3
3
  module V3
4
4
  module Admin
5
5
  class PaymentSerializer < V3::PaymentSerializer
6
- typelize metadata: 'Record<string, unknown> | null',
6
+ typelize metadata: 'Record<string, unknown>',
7
7
  captured_amount: :string,
8
8
  order_id: [:string, nullable: true],
9
9
  avs_response: [:string, nullable: true],
10
10
  cvv_response_code: [:string, nullable: true],
11
11
  cvv_response_message: [:string, nullable: true]
12
12
 
13
- attributes :avs_response, :cvv_response_code, :cvv_response_message,
13
+ attributes :metadata, :avs_response, :cvv_response_code, :cvv_response_message,
14
14
  created_at: :iso8601, updated_at: :iso8601
15
15
 
16
- attribute :metadata do |payment|
17
- payment.metadata.presence
18
- end
19
-
20
16
  attribute :captured_amount do |payment|
21
17
  payment.captured_amount.to_s
22
18
  end
@@ -3,7 +3,10 @@ module Spree
3
3
  module V3
4
4
  module Admin
5
5
  class PaymentSourceSerializer < V3::PaymentSourceSerializer
6
- attributes created_at: :iso8601, updated_at: :iso8601
6
+ typelize metadata: 'Record<string, unknown>'
7
+
8
+ attributes :metadata,
9
+ created_at: :iso8601, updated_at: :iso8601
7
10
  end
8
11
  end
9
12
  end
@@ -0,0 +1,51 @@
1
+ module Spree
2
+ module Api
3
+ module V3
4
+ module Admin
5
+ # Serializes Spree::PriceList for the admin pricing surface.
6
+ # Price lists are admin-only — there's no Store API counterpart;
7
+ # storefront callers only ever see the *resolved* price (see
8
+ # PriceSerializer#price_list_id), never the list itself.
9
+ class PriceListSerializer < V3::BaseSerializer
10
+ typelize name: :string,
11
+ description: 'string | null',
12
+ status: :string,
13
+ position: :number,
14
+ starts_at: 'string | null',
15
+ ends_at: 'string | null',
16
+ deleted_at: 'string | null',
17
+ match_policy: :string,
18
+ currently_active: :boolean,
19
+ products_count: :number,
20
+ prices_count: :number,
21
+ product_ids: [:string, multi: true]
22
+
23
+ attributes :name, :description, :status, :position, :match_policy,
24
+ starts_at: :iso8601, ends_at: :iso8601, deleted_at: :iso8601,
25
+ created_at: :iso8601, updated_at: :iso8601
26
+
27
+ attribute :currently_active, &:currently_active?
28
+
29
+ # Cheap counts so the index can render "12 products / 36 prices"
30
+ # without forcing each row to expand the children.
31
+ attribute :products_count do |pl|
32
+ pl.products.count
33
+ end
34
+
35
+ attribute :prices_count do |pl|
36
+ pl.prices.count
37
+ end
38
+
39
+ # Prefixed product ids in the list — drives the SPA's
40
+ # Products picker pre-fill, and is the same payload the
41
+ # client ships back on PATCH to reconcile membership.
42
+ attribute :product_ids, &:product_prefixed_ids
43
+
44
+ many :price_rules,
45
+ resource: Spree.api.admin_price_rule_serializer,
46
+ if: proc { expand?('price_rules') }
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,55 @@
1
+ module Spree
2
+ module Api
3
+ module V3
4
+ module Admin
5
+ # Serializes Spree::PriceRule (STI subclasses live under Spree::PriceRules).
6
+ # Same shape as PromotionRuleSerializer so the SPA can drive both
7
+ # editors from one generic preference-form component.
8
+ class PriceRuleSerializer < V3::BaseSerializer
9
+ typelize type: :string,
10
+ price_list_id: :string,
11
+ preferences: 'Record<string, unknown>',
12
+ preference_schema: 'Array<{ key: string; type: string; default: unknown }>',
13
+ label: :string,
14
+ description: 'string | null'
15
+
16
+ attributes created_at: :iso8601, updated_at: :iso8601
17
+
18
+ attribute :type do |rule|
19
+ rule.class.api_type
20
+ end
21
+
22
+ attribute :price_list_id do |rule|
23
+ rule.price_list&.prefixed_id
24
+ end
25
+
26
+ attribute :preferences, &:serialized_preferences
27
+ attribute :preference_schema, &:serialized_preference_schema
28
+
29
+ attribute :label do |rule|
30
+ rule.class.respond_to?(:human_name) ? rule.class.human_name : rule.class.to_s.demodulize
31
+ end
32
+
33
+ attribute :description do |rule|
34
+ rule.class.respond_to?(:description) ? rule.class.description : nil
35
+ end
36
+
37
+ # Embeds skip rules that don't carry the association (e.g.
38
+ # VolumeRule has no markets/customers — the keys are omitted).
39
+ many :markets,
40
+ resource: Spree.api.admin_market_serializer,
41
+ if: proc { |rule| rule.respond_to?(:markets) }
42
+
43
+ many :customer_groups,
44
+ resource: Spree.api.admin_customer_group_serializer,
45
+ if: proc { |rule| rule.respond_to?(:customer_groups) }
46
+
47
+ many :users,
48
+ key: :customers,
49
+ resource: Spree.api.admin_customer_serializer,
50
+ if: proc { |rule| rule.respond_to?(:users) }
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -14,6 +14,10 @@ module Spree
14
14
  end
15
15
 
16
16
  attributes created_at: :iso8601, updated_at: :iso8601
17
+
18
+ one :variant,
19
+ resource: Spree.api.admin_variant_serializer,
20
+ if: proc { expand?('variant') }
17
21
  end
18
22
  end
19
23
  end
@@ -0,0 +1,11 @@
1
+ module Spree
2
+ module Api
3
+ module V3
4
+ module Admin
5
+ class ProductPublicationSerializer < V3::ProductPublicationSerializer
6
+ attributes created_at: :iso8601, updated_at: :iso8601
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -7,21 +7,33 @@ module Spree
7
7
  # Extends the store serializer with additional attributes
8
8
  class ProductSerializer < V3::ProductSerializer
9
9
 
10
- # Additional type hints for admin-only computed attributes
11
- typelize status: :string, make_active_at: [:string, nullable: true], discontinue_on: [:string, nullable: true],
12
- cost_price: [:string, nullable: true], cost_currency: [:string, nullable: true],
13
- deleted_at: [:string, nullable: true]
10
+ typelize status: :string,
11
+ tax_category_id: [:string, nullable: true],
12
+ price: ['Price', nullable: true],
13
+ deleted_at: [:string, nullable: true],
14
+ metadata: 'Record<string, unknown>'
14
15
 
15
- # Admin-only attributes
16
- attributes :status, :make_active_at, :discontinue_on, deleted_at: :iso8601,
16
+ attributes :status,
17
+ :metadata, deleted_at: :iso8601,
17
18
  created_at: :iso8601, updated_at: :iso8601
18
19
 
19
- attribute :cost_price do |product|
20
- product.master&.cost_price
20
+ attribute :tax_category_id do |product|
21
+ product.tax_category&.prefixed_id
21
22
  end
22
23
 
23
- attribute :cost_currency do |product|
24
- product.master&.cost_currency
24
+ attribute :price do |product|
25
+ price = price_for(product.default_variant)
26
+ Spree.api.admin_price_serializer.new(price, params: params).to_h if price&.persisted?
27
+ end
28
+
29
+ attribute :original_price do |product|
30
+ variant = product.default_variant
31
+ calculated = price_for(variant)
32
+ base = price_in(variant)
33
+
34
+ if calculated.present? && base.present? && calculated.id != base.id
35
+ Spree.api.admin_price_serializer.new(base, params: params).to_h
36
+ end
25
37
  end
26
38
 
27
39
  # Admin uses admin variant serializer
@@ -46,6 +58,10 @@ module Spree
46
58
  resource: Spree.api.admin_option_type_serializer,
47
59
  if: proc { expand?('option_types') }
48
60
 
61
+ many :option_values,
62
+ resource: Spree.api.admin_option_value_serializer,
63
+ if: proc { expand?('option_values') }
64
+
49
65
  many :taxons,
50
66
  proc { |taxons, params|
51
67
  taxons.select { |t| t.taxonomy.store_id == params[:store].id }
@@ -58,6 +74,14 @@ module Spree
58
74
  key: :custom_fields,
59
75
  resource: Spree.api.admin_custom_field_serializer,
60
76
  if: proc { expand?('custom_fields') }
77
+
78
+ many :product_publications,
79
+ resource: Spree.api.admin_product_publication_serializer,
80
+ if: proc { expand?('product_publications') }
81
+
82
+ many :channels,
83
+ resource: Spree.api.admin_channel_serializer,
84
+ if: proc { expand?('channels') }
61
85
  end
62
86
  end
63
87
  end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Api
5
+ module V3
6
+ module Admin
7
+ # Serializes Spree::PromotionAction (and its STI subclasses) for the
8
+ # admin promotion editor. The shape is intentionally generic so a
9
+ # single component can render any subclass — `preferences` is the
10
+ # current value hash, `preference_schema` describes its fields.
11
+ class PromotionActionSerializer < BaseSerializer
12
+ typelize type: :string,
13
+ promotion_id: :string,
14
+ preferences: 'Record<string, unknown>',
15
+ preference_schema: "Array<{ key: string; type: string; default: unknown }>",
16
+ label: :string,
17
+ calculator: "{ type: string; label: string; preferences: Record<string, unknown>; preference_schema: Array<{ key: string; type: string; default: unknown }> } | null",
18
+ line_items: 'Array<{ variant_id: string; quantity: number }> | null'
19
+
20
+ attributes created_at: :iso8601, updated_at: :iso8601
21
+
22
+ attribute :type do |action|
23
+ action.class.api_type
24
+ end
25
+
26
+ attribute :promotion_id do |action|
27
+ action.promotion&.prefixed_id
28
+ end
29
+
30
+ attribute :preferences, &:serialized_preferences
31
+ attribute :preference_schema, &:serialized_preference_schema
32
+
33
+ attribute :label do |action|
34
+ action.respond_to?(:human_name) ? action.human_name : action.type.to_s.demodulize
35
+ end
36
+
37
+ # Calculator is exposed as a nested object so the SPA can render
38
+ # the calculator picker + its own preference fields. Null for
39
+ # actions that don't include CalculatedAdjustments. The SPA
40
+ # formats the row summary itself off `label` + `preferences` —
41
+ # see the action-summary helper in the admin promotion editor.
42
+ attribute :calculator do |action|
43
+ next nil unless action.respond_to?(:calculator) && action.calculator
44
+
45
+ calc = action.calculator
46
+ {
47
+ type: calc.class.api_type,
48
+ label: calc.class.respond_to?(:description) ? calc.class.description : calc.class.to_s.demodulize.titleize,
49
+ preferences: calc.serialized_preferences,
50
+ preference_schema: calc.serialized_preference_schema
51
+ }
52
+ end
53
+
54
+ # Line items the action will add for CreateLineItems. variant_id
55
+ # is prefixed for consistency with the rest of the API. Null on
56
+ # actions that don't have the association.
57
+ attribute :line_items do |action|
58
+ next nil unless action.respond_to?(:promotion_action_line_items)
59
+
60
+ action.promotion_action_line_items.map do |item|
61
+ {
62
+ variant_id: item.variant&.prefixed_id,
63
+ quantity: item.quantity
64
+ }
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Api
5
+ module V3
6
+ module Admin
7
+ # Serializes Spree::PromotionRule (and its STI subclasses) for the
8
+ # admin promotion editor. Same shape as PromotionAction so the
9
+ # frontend renders both with the same generic component.
10
+ class PromotionRuleSerializer < BaseSerializer
11
+ typelize type: :string,
12
+ promotion_id: :string,
13
+ preferences: 'Record<string, unknown>',
14
+ preference_schema: "Array<{ key: string; type: string; default: unknown }>",
15
+ label: :string,
16
+ product_ids: 'Array<string> | null',
17
+ category_ids: 'Array<string> | null',
18
+ customer_ids: 'Array<string> | null'
19
+
20
+ attributes created_at: :iso8601, updated_at: :iso8601
21
+
22
+ attribute :type do |rule|
23
+ rule.class.api_type
24
+ end
25
+
26
+ attribute :promotion_id do |rule|
27
+ rule.promotion&.prefixed_id
28
+ end
29
+
30
+ attribute :preferences, &:serialized_preferences
31
+ attribute :preference_schema, &:serialized_preference_schema
32
+
33
+ attribute :label do |rule|
34
+ rule.respond_to?(:human_name) ? rule.human_name : rule.class.to_s.demodulize
35
+ end
36
+
37
+ # Association IDs for rules that wire products/taxons/users through
38
+ # join tables. Returned as prefixed IDs to match the rest of the
39
+ # API; null on rules that don't have the association. The matching
40
+ # `products`/`categories`/`customers` collections below embed the
41
+ # full records via their admin serializers so the SPA can render
42
+ # names + extra info without an extra round-trip.
43
+ attribute :product_ids do |rule|
44
+ rule.products.map(&:prefixed_id) if rule.respond_to?(:products)
45
+ end
46
+
47
+ attribute :category_ids do |rule|
48
+ rule.taxons.map(&:prefixed_id) if rule.respond_to?(:taxons)
49
+ end
50
+
51
+ attribute :customer_ids do |rule|
52
+ rule.users.map(&:prefixed_id) if rule.respond_to?(:users)
53
+ end
54
+
55
+ # Embed the related records so promotion-row summaries can render
56
+ # names + extra info without a separate fetch. Rules that don't
57
+ # carry a given collection (e.g. an ItemTotal rule has no
58
+ # products) skip via `if:` and the key is omitted from the
59
+ # payload.
60
+ many :products,
61
+ resource: Spree.api.admin_product_serializer,
62
+ if: proc { |rule| rule.respond_to?(:products) }
63
+
64
+ many :taxons,
65
+ key: :categories,
66
+ resource: Spree.api.admin_category_serializer,
67
+ if: proc { |rule| rule.respond_to?(:taxons) }
68
+
69
+ many :users,
70
+ key: :customers,
71
+ resource: Spree.api.admin_customer_serializer,
72
+ if: proc { |rule| rule.respond_to?(:users) }
73
+
74
+ many :customer_groups,
75
+ resource: Spree.api.admin_customer_group_serializer,
76
+ if: proc { |rule| rule.respond_to?(:customer_groups) }
77
+
78
+ many :countries,
79
+ resource: Spree.api.admin_country_serializer,
80
+ if: proc { |rule| rule.respond_to?(:countries) }
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Api
5
+ module V3
6
+ module Admin
7
+ # Admin Promotion serializer — adds operational fields the Store API
8
+ # never exposes (multi-codes counts, usage stats, internal promotion
9
+ # category, store assignments, timestamps).
10
+ class PromotionSerializer < V3::PromotionSerializer
11
+ typelize starts_at: [:string, nullable: true],
12
+ expires_at: [:string, nullable: true],
13
+ usage_limit: [:number, nullable: true],
14
+ match_policy: "'all' | 'any'",
15
+ path: [:string, nullable: true],
16
+ kind: "'coupon_code' | 'automatic'",
17
+ multi_codes: :boolean,
18
+ number_of_codes: [:number, nullable: true],
19
+ code_prefix: [:string, nullable: true],
20
+ promotion_category_id: [:string, nullable: true],
21
+ metadata: 'Record<string, unknown>',
22
+ action_ids: 'string[]',
23
+ rule_ids: 'string[]'
24
+
25
+ attributes :starts_at, :expires_at, :usage_limit, :match_policy,
26
+ :path, :kind, :multi_codes, :number_of_codes, :code_prefix,
27
+ :promotion_category_id, :metadata,
28
+ created_at: :iso8601, updated_at: :iso8601
29
+
30
+ attribute :action_ids do |promotion|
31
+ promotion.promotion_actions.map(&:prefixed_id)
32
+ end
33
+
34
+ attribute :rule_ids do |promotion|
35
+ promotion.promotion_rules.map(&:prefixed_id)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -5,9 +5,11 @@ module Spree
5
5
  class RefundSerializer < V3::RefundSerializer
6
6
  typelize payment_id: [:string, nullable: true],
7
7
  refund_reason_id: [:string, nullable: true],
8
- reimbursement_id: [:string, nullable: true]
8
+ reimbursement_id: [:string, nullable: true],
9
+ metadata: 'Record<string, unknown>'
9
10
 
10
- attributes created_at: :iso8601, updated_at: :iso8601
11
+ attributes :metadata,
12
+ created_at: :iso8601, updated_at: :iso8601
11
13
 
12
14
  one :payment,
13
15
  resource: Spree.api.admin_payment_serializer,
@@ -0,0 +1,17 @@
1
+ module Spree
2
+ module Api
3
+ module V3
4
+ module Admin
5
+ # Admin API serializer for {Spree::Role}. Read-only — used to populate
6
+ # the role picker on the staff invite/edit forms. Spree core ships
7
+ # with a single `admin` role today; richer role/permission management
8
+ # is on the roadmap.
9
+ class RoleSerializer < V3::BaseSerializer
10
+ typelize name: :string
11
+
12
+ attributes :name, created_at: :iso8601, updated_at: :iso8601
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -3,7 +3,22 @@ module Spree
3
3
  module V3
4
4
  module Admin
5
5
  class StockItemSerializer < V3::StockItemSerializer
6
- attributes created_at: :iso8601, updated_at: :iso8601
6
+ typelize metadata: 'Record<string, unknown>',
7
+ allocated_count: :number, available_count: :number
8
+
9
+ attributes :metadata,
10
+ created_at: :iso8601, updated_at: :iso8601
11
+
12
+ # Units already allocated to pending shipments. Always 0 in 5.5;
13
+ # 6.0 Typed Stock Movements wires it up.
14
+ attribute :allocated_count do |stock_item|
15
+ stock_item.allocated_count.to_i
16
+ end
17
+
18
+ # Physical stock minus allocated units (per stock_item).
19
+ attribute :available_count do |stock_item|
20
+ stock_item.available_count.to_i
21
+ end
7
22
 
8
23
  one :stock_location,
9
24
  resource: Spree.api.admin_stock_location_serializer,
@@ -4,9 +4,18 @@ module Spree
4
4
  module Admin
5
5
  class StockLocationSerializer < V3::StockLocationSerializer
6
6
  typelize active: :boolean, default: :boolean, backorderable_default: :boolean,
7
- propagate_all_variants: :boolean
7
+ propagate_all_variants: :boolean, pickup_enabled: :boolean,
8
+ admin_name: [:string, nullable: true],
9
+ address2: [:string, nullable: true], state_name: [:string, nullable: true],
10
+ phone: [:string, nullable: true], company: [:string, nullable: true],
11
+ kind: :string, pickup_stock_policy: :string,
12
+ pickup_ready_in_minutes: [:number, nullable: true],
13
+ pickup_instructions: [:string, nullable: true]
8
14
 
9
- attributes :active, :default, :backorderable_default, :propagate_all_variants,
15
+ attributes :admin_name, :address2, :state_name, :phone, :company,
16
+ :active, :default, :backorderable_default, :propagate_all_variants,
17
+ :kind, :pickup_enabled, :pickup_stock_policy,
18
+ :pickup_ready_in_minutes, :pickup_instructions,
10
19
  created_at: :iso8601, updated_at: :iso8601
11
20
  end
12
21
  end
@@ -0,0 +1,46 @@
1
+ module Spree
2
+ module Api
3
+ module V3
4
+ module Admin
5
+ class StockReservationSerializer < V3::StockReservationSerializer
6
+ typelize stock_item_id: :string,
7
+ line_item_id: :string,
8
+ order_id: :string,
9
+ variant_id: [:string, nullable: true],
10
+ stock_location_id: [:string, nullable: true],
11
+ quantity: :number,
12
+ expires_at: :string,
13
+ active: :boolean
14
+
15
+ attribute :stock_item_id do |reservation|
16
+ reservation.stock_item.prefixed_id
17
+ end
18
+
19
+ attribute :line_item_id do |reservation|
20
+ reservation.line_item.prefixed_id
21
+ end
22
+
23
+ attribute :order_id do |reservation|
24
+ reservation.order.prefixed_id
25
+ end
26
+
27
+ attribute :variant_id do |reservation|
28
+ reservation.stock_item&.variant&.prefixed_id
29
+ end
30
+
31
+ attribute :stock_location_id do |reservation|
32
+ reservation.stock_item&.stock_location&.prefixed_id
33
+ end
34
+
35
+ attributes :quantity, expires_at: :iso8601
36
+
37
+ attribute :active do |reservation|
38
+ reservation.active?
39
+ end
40
+
41
+ attributes created_at: :iso8601, updated_at: :iso8601
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end