spree_api 6.0.2 → 6.0.3

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/concerns/spree/api/v3/admin/embed_permissions.rb +5 -2
  3. data/app/controllers/spree/api/v3/admin/products_controller.rb +56 -0
  4. data/app/serializers/spree/api/v3/admin/admin_user_serializer.rb +2 -2
  5. data/app/serializers/spree/api/v3/admin/delivery_profile_serializer.rb +2 -1
  6. data/app/serializers/spree/api/v3/admin/fulfillment_serializer.rb +1 -1
  7. data/app/serializers/spree/api/v3/admin/import_serializer.rb +1 -1
  8. data/app/serializers/spree/api/v3/admin/invitation_serializer.rb +2 -2
  9. data/app/serializers/spree/api/v3/admin/price_rule_serializer.rb +3 -1
  10. data/app/serializers/spree/api/v3/admin/product_serializer.rb +8 -0
  11. data/app/serializers/spree/api/v3/admin/promotion_action_serializer.rb +2 -2
  12. data/app/serializers/spree/api/v3/admin/promotion_rule_serializer.rb +4 -1
  13. data/app/serializers/spree/api/v3/admin/promotion_serializer.rb +13 -0
  14. data/app/serializers/spree/api/v3/admin/return_serializer.rb +1 -1
  15. data/app/serializers/spree/api/v3/admin/seller_requirement_status_serializer.rb +3 -2
  16. data/app/serializers/spree/api/v3/admin/seller_serializer.rb +2 -2
  17. data/app/serializers/spree/api/v3/fulfillment_serializer.rb +1 -1
  18. data/app/serializers/spree/api/v3/seller/import_serializer.rb +1 -1
  19. data/app/serializers/spree/api/v3/seller/invitation_serializer.rb +2 -2
  20. data/app/serializers/spree/api/v3/seller/product_serializer.rb +8 -0
  21. data/app/serializers/spree/api/v3/seller/requirement_status_serializer.rb +3 -2
  22. data/config/initializers/typelizer.rb +8 -19
  23. data/config/routes.rb +5 -0
  24. data/lib/spree/api/admin_document.rb +284 -0
  25. data/lib/spree/api/agent_operations.rb +300 -0
  26. data/lib/spree/api/agent_resource_map.rb +32 -7
  27. data/lib/spree/api/agent_write_schemas.rb +15 -51
  28. data/lib/spree/api/engine.rb +14 -1
  29. data/lib/spree/api/enum_types.rb +4 -1
  30. data/lib/spree/api/openapi/schema_helper.rb +3 -3
  31. data/lib/spree/api/sdk_types.rb +190 -0
  32. data/lib/spree/api/sdk_types_task.rb +68 -0
  33. data/lib/spree/api/testing_support/agent_tools.rb +35 -0
  34. data/lib/spree/api/testing_support/agent_tools_contract.rb +110 -0
  35. data/lib/spree/api/testing_support/deterministic_openapi.rb +147 -0
  36. data/lib/spree/api/testing_support/filter_parameters.rb +99 -0
  37. data/lib/spree/api/testing_support/openapi.rb +232 -0
  38. data/lib/spree/api/testing_support/openapi_tasks.rb +21 -0
  39. data/lib/spree/api/typelizer_generation.rb +39 -11
  40. data/lib/tasks/openapi.rake +5 -0
  41. data/lib/tasks/sdk_types.rake +6 -0
  42. data/lib/typelizer/open_enums.rb +13 -1
  43. data/openapi/admin.yaml +1540 -33
  44. metadata +20 -9
  45. data/lib/spree/api/agent_workflow_endpoints.rb +0 -113
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3bc1eebac54270cff24aa58f2319414c1d2c3d3e2b62bc73ed1a99b3dcc8cef3
4
- data.tar.gz: 63c9e47df2e22549f57a66be0af2bf781d35d44cfb42f70a7edacdc932f60dd2
3
+ metadata.gz: 3f1aae2e30afb2db5577e3315cd2779ab8f273bfa114b7e369f7c0c8a519214d
4
+ data.tar.gz: 15e89346921cf2a0f21bdccd6050e7f4854d0aea5d17d0ef666d853ea475f769
5
5
  SHA512:
6
- metadata.gz: 4dc86cc7163081943b538408538ff9499ca25848f6bd3656933a8b79cc172d5a629e7cea4b0b22f5c55e22ba7a7b2fa342f8c360155b0759b879876f21d67972
7
- data.tar.gz: ec1f8e51808bf0175f6c1ee135bc440cffcdff1e22eff9e920ac92e5d1610e22d8be00de38080d33acd629968b17c0f326b2c6a1651b3c7ee5643b7c5df52183
6
+ metadata.gz: 555454b4f93a2ec776ebd7a1c6ea407bbc359b10493768c838d29617b0d58011a024168a2f384c4e2ad21a983a2f31e3989afce90d864c6f272f5bc13b7253ae
7
+ data.tar.gz: 0f00cda28bba945fc65e7509cfd61bd5626af3c91957e2f6dea5819e078593a7aad38152e5439495019bfdaece73cfaf65751313a10604f6af4f864176f84cb1
@@ -13,7 +13,9 @@ module Spree
13
13
  #
14
14
  # Gift card codes are bearer credentials that ride along on every
15
15
  # order, so serializers show them in full only to a caller who may read
16
- # gift cards and masked to everyone else.
16
+ # gift cards and masked to everyone else. Customer records embedded in
17
+ # a rule (a promotion's or a price list's customer rule) are shown only
18
+ # to a caller who may read customers; the rule keeps its `customer_ids`.
17
19
  module EmbedPermissions
18
20
  extend ActiveSupport::Concern
19
21
 
@@ -44,7 +46,8 @@ module Spree
44
46
  end
45
47
 
46
48
  def serializer_params
47
- super.merge(gift_card_codes: holds_permission?('read_gift_cards'))
49
+ super.merge(gift_card_codes: holds_permission?('read_gift_cards'),
50
+ customer_records: holds_permission?('read_customers'))
48
51
  end
49
52
 
50
53
  private
@@ -156,6 +156,28 @@ module Spree
156
156
  run_review_workflow(Spree.product_reject_workflow, reason: params[:reason])
157
157
  end
158
158
 
159
+ # PATCH /api/v3/admin/products/:id/activate
160
+ #
161
+ # Puts one product on sale.
162
+ def activate
163
+ run_status_workflow(Spree.product_activate_workflow, 'active')
164
+ end
165
+
166
+ # PATCH /api/v3/admin/products/:id/archive
167
+ #
168
+ # Takes one product off sale, archived; activating it again puts it
169
+ # back on sale.
170
+ def archive
171
+ run_status_workflow(Spree.product_archive_workflow, 'archived')
172
+ end
173
+
174
+ # PATCH /api/v3/admin/products/:id/draft
175
+ #
176
+ # Takes one product off sale, back to a draft.
177
+ def draft
178
+ run_status_workflow(Spree.product_draft_workflow, 'draft')
179
+ end
180
+
159
181
  # POST /api/v3/admin/products/bulk_status_update
160
182
  # Body: { ids: [...], status: 'draft' | 'active' | 'archived' }
161
183
  def bulk_status_update
@@ -363,6 +385,40 @@ module Spree
363
385
 
364
386
  private
365
387
 
388
+ # Unlike bulk_status_update, which writes the column, these run the
389
+ # status workflow, so its hooks and its event fire. A product in
390
+ # review is refused: its next status is a decision, made through
391
+ # approve or reject (docs/plans/6.0-seller-product-submission.md).
392
+ #
393
+ # A product already in that status is answered as it is: running the
394
+ # workflow again would publish its event again, and every webhook
395
+ # subscriber would see the move twice.
396
+ def run_status_workflow(workflow, status)
397
+ @resource = find_resource
398
+ authorize!(:update, @resource)
399
+
400
+ return render json: serialize_resource(@resource) if @resource.status == status
401
+
402
+ if @resource.in_review?
403
+ return render_error(
404
+ code: 'product_in_review',
405
+ message: I18n.t('spree.errors.messages.product_in_review'),
406
+ status: :unprocessable_content
407
+ )
408
+ end
409
+
410
+ # Not under a row lock taken here: that would wrap the workflow in
411
+ # a transaction, and it publishes its event once its own
412
+ # transaction is done, which an outer one would no longer be.
413
+ result = workflow.call(product: @resource)
414
+
415
+ if result.success?
416
+ render json: serialize_resource(@resource.reload)
417
+ else
418
+ render_service_error(@resource.errors.presence || result.error)
419
+ end
420
+ end
421
+
366
422
  # Approving and rejecting are edits to the catalog, so they answer to
367
423
  # the same key as any other product write.
368
424
  def run_review_workflow(workflow, **arguments)
@@ -9,8 +9,6 @@ module Spree
9
9
  full_name: [:string, nullable: true],
10
10
  selected_locale: [:string, nullable: true],
11
11
  avatar_url: [:string, nullable: true],
12
- roles: 'Array<{ id: string; name: string }>',
13
- stores: 'Array<{ id: string; name: string; code: string }>',
14
12
  status: [:string, enum: Spree::AdminUserMethods::STATUSES, enum_type_name: 'AdminUserStatus'],
15
13
  last_active_at: [:string, nullable: true],
16
14
  inviter: ['Actor', nullable: true]
@@ -45,6 +43,7 @@ module Spree
45
43
  # we fall back to `Spree::Current.store` if not.
46
44
  # Filtered in Ruby rather than with `for_resource`, so the staff
47
45
  # index's preloaded roles are used instead of a query per user.
46
+ typelize({ id: :string, name: :string }, multi: true)
48
47
  attribute :roles do |user, params|
49
48
  store = params&.dig(:store) || Spree::Current.store
50
49
  roles = user.spree_roles.to_a
@@ -57,6 +56,7 @@ module Spree
57
56
  # store switcher can offer all accessible stores. Read off the same
58
57
  # preloaded roles, and deduped/sorted in Ruby, so the staff index
59
58
  # spends no extra query per user.
59
+ typelize({ id: :string, name: :string, code: :string }, multi: true)
60
60
  attribute :stores do |user|
61
61
  stores = user.spree_roles.filter_map { |role| role.resource if role.resource.is_a?(Spree::Store) }
62
62
 
@@ -8,7 +8,6 @@ module Spree
8
8
  digital: :boolean,
9
9
  offers_pickup: :boolean, offers_shipping: :boolean,
10
10
  stock_location_ids: [:string, multi: true],
11
- origin_groups: ['Array<{ id: string; name: string | null; position: number | null; stock_location_ids: Array<string> }>'],
12
11
  products_count: :number, delivery_methods_count: :number,
13
12
  delivery_zones_count: :number
14
13
 
@@ -36,6 +35,8 @@ module Spree
36
35
 
37
36
  # Origin groups partition the profile's fulfillment origins; zones
38
37
  # and methods reference one. A null name renders as "All locations".
38
+ typelize({ id: :string, name: [:string, { nullable: true }], position: [:number, { nullable: true }],
39
+ stock_location_ids: 'string[]' }, multi: true)
39
40
  attribute :origin_groups do |record|
40
41
  record.delivery_origin_groups.map do |group|
41
42
  {
@@ -17,7 +17,6 @@ module Spree
17
17
  tax_total: [:string, nullable: false]
18
18
 
19
19
  typelize metadata: 'Record<string, unknown>',
20
- documents: "Array<{ kind: string; url: string }>",
21
20
  provider_generates_labels: :boolean,
22
21
  order_id: [:string, nullable: true],
23
22
  stock_location_id: [:string, nullable: true]
@@ -31,6 +30,7 @@ module Spree
31
30
 
32
31
  # Customs forms and other paperwork the provider produced beside the
33
32
  # label; the labels themselves are listed under +labels+.
33
+ typelize({ kind: :string, url: :string }, multi: true)
34
34
  attribute :documents do |fulfillment|
35
35
  fulfillment.provider.documents(fulfillment).map(&:as_json)
36
36
  end
@@ -10,7 +10,6 @@ module Spree
10
10
  failed_rows_count: :number,
11
11
  processing_errors: [:string, nullable: true],
12
12
  delimiter: :string,
13
- schema_fields: 'Array<{ name: string; label: string; required: boolean }>',
14
13
  csv_headers: [:string, multi: true],
15
14
  sample_row: 'Record<string, string | null>',
16
15
  original_filename: [:string, nullable: true],
@@ -58,6 +57,7 @@ module Spree
58
57
  import.rows_status_counts['failed'] || 0
59
58
  end
60
59
 
60
+ typelize({ name: :string, label: :string, required: :boolean }, multi: true)
61
61
  attribute :schema_fields do |import|
62
62
  import.schema_fields.map do |field|
63
63
  { name: field[:name], label: field[:label], required: field[:required].present? }
@@ -13,8 +13,7 @@ module Spree
13
13
  role_name: :string,
14
14
  inviter_email: :string,
15
15
  expires_at: :string,
16
- invitee_exists: :boolean,
17
- store: '{ id: string; name: string }'
16
+ invitee_exists: :boolean
18
17
 
19
18
  attributes :email, :status,
20
19
  created_at: :iso8601, updated_at: :iso8601, expires_at: :iso8601
@@ -43,6 +42,7 @@ module Spree
43
42
  # Minimal store identity for the unauthenticated acceptance page's
44
43
  # title ("Join <store>"). Full Store would over-expose internals to
45
44
  # a public landing page; this is the smallest shape that renders.
45
+ typelize({ id: :string, name: :string })
46
46
  attribute :store do |invitation|
47
47
  { id: invitation.store.prefixed_id, name: invitation.store.name }
48
48
  end
@@ -34,10 +34,12 @@ module Spree
34
34
  resource: proc { Spree.api.admin_channel_serializer },
35
35
  if: proc { |rule| rule.respond_to?(:channels) }
36
36
 
37
+ # Only for a caller who may read customers; see the promotion rule
38
+ # serializer.
37
39
  many :users,
38
40
  key: :customers,
39
41
  resource: proc { Spree.api.admin_customer_serializer },
40
- if: proc { |rule| rule.respond_to?(:users) }
42
+ if: proc { |rule| rule.respond_to?(:users) && params[:customer_records] }
41
43
  end
42
44
  end
43
45
  end
@@ -17,6 +17,7 @@ module Spree
17
17
  product_type_id: [:string, nullable: true],
18
18
  delivery_profile_id: [:string, nullable: true],
19
19
  seller_name: [:string, nullable: true],
20
+ total_on_hand: [:number, nullable: true],
20
21
  price: ['Price', nullable: true],
21
22
  deleted_at: [:string, nullable: true],
22
23
  metadata: 'Record<string, unknown>',
@@ -49,6 +50,13 @@ module Spree
49
50
 
50
51
  prefixed_id_attributes :product_type, :tax_category
51
52
 
53
+ # Null when any variant is not tracked: its stock is unlimited, which
54
+ # is not a number to send.
55
+ attribute :total_on_hand do |product|
56
+ total = product.total_on_hand
57
+ total.to_i unless total.infinite?
58
+ end
59
+
52
60
  attribute :price do |product|
53
61
  price = price_for(product.default_variant)
54
62
  Spree.api.admin_price_serializer.new(price, params: params).to_h if price&.persisted?
@@ -13,8 +13,7 @@ module Spree
13
13
  typelize type: [:string, comment: 'Action type. Built-in: create_adjustment, create_item_adjustments, create_line_items, free_shipping. Extensions may register more.'],
14
14
  promotion_id: :string,
15
15
  preferences: 'Record<string, unknown>',
16
- calculator: 'TypedPromotionCalculator | null',
17
- line_items: 'Array<{ variant_id: string; quantity: number }> | null'
16
+ calculator: 'TypedPromotionCalculator | null'
18
17
 
19
18
  attributes created_at: :iso8601, updated_at: :iso8601
20
19
 
@@ -44,6 +43,7 @@ module Spree
44
43
  # Line items the action will add for CreateLineItems. variant_id
45
44
  # is prefixed for consistency with the rest of the API. Null on
46
45
  # actions that don't have the association.
46
+ typelize({ variant_id: :string, quantity: :number }, multi: true, nullable: true)
47
47
  attribute :line_items do |action|
48
48
  next nil unless action.respond_to?(:promotion_action_line_items)
49
49
 
@@ -61,9 +61,12 @@ module Spree
61
61
  resource: proc { Spree.api.admin_category_serializer },
62
62
  if: proc { |rule| rule.respond_to?(:categories) }
63
63
 
64
+ # Only for a caller who may read customers: a promotion is readable
65
+ # under `read_promotions`, and a customer rule would otherwise carry
66
+ # every targeted customer's email and notes along with it.
64
67
  many :customers,
65
68
  resource: proc { Spree.api.admin_customer_serializer },
66
- if: proc { |rule| rule.respond_to?(:customers) }
69
+ if: proc { |rule| rule.respond_to?(:customers) && params[:customer_records] }
67
70
 
68
71
  many :customer_groups,
69
72
  resource: proc { Spree.api.admin_customer_group_serializer },
@@ -34,6 +34,19 @@ module Spree
34
34
  attribute :rule_ids do |promotion|
35
35
  promotion.promotion_rules.map(&:prefixed_id)
36
36
  end
37
+
38
+ # The rows under the same names the write accepts, on request: a
39
+ # reader holding only `rule_ids` cannot tell what a promotion does
40
+ # without a request per rule.
41
+ many :promotion_rules,
42
+ key: :rules,
43
+ resource: proc { Spree.api.admin_promotion_rule_serializer },
44
+ if: proc { expand?('rules') }
45
+
46
+ many :promotion_actions,
47
+ key: :actions,
48
+ resource: proc { Spree.api.admin_promotion_action_serializer },
49
+ if: proc { expand?('actions') }
37
50
  end
38
51
  end
39
52
  end
@@ -11,7 +11,6 @@ module Spree
11
11
 
12
12
  typelize memo: [:string, nullable: true],
13
13
  metadata: 'Record<string, unknown>',
14
- documents: "Array<{ kind: string; url: string }>",
15
14
  stock_location_id: [:string, nullable: true],
16
15
  created_by_id: [:string, nullable: true],
17
16
  created_by_type: [:string, nullable: true, enum: Spree::Actor::BUILT_IN_KINDS, enum_type_name: 'ActorKind'],
@@ -39,6 +38,7 @@ module Spree
39
38
 
40
39
  # Paperwork the provider produced beside the label: a cross-border
41
40
  # return is declared like any other export.
41
+ typelize({ kind: :string, url: :string }, multi: true)
42
42
  attribute :documents do |return_record|
43
43
  return_record.provider.documents(return_record).map(&:as_json)
44
44
  end
@@ -14,10 +14,11 @@ module Spree
14
14
  description: [:string, nullable: true],
15
15
  required: :boolean, position: :number, status: [:string, enum: Spree::SellerRequirementStatus::STATUSES, enum_type_name: 'SellerRequirementState'],
16
16
  blocking: :boolean, action_url: [:string, nullable: true],
17
- blocker: ['{ state: string; message: string | null } | null'],
18
17
  required_policy_name: [:string, nullable: true]
19
18
 
20
- attributes :id, :kind, :name, :description, :required, :position, :status, :action_url, :blocker
19
+ attributes :id, :kind, :name, :description, :required, :position, :status, :action_url
20
+ typelize({ state: :string, message: [:string, { nullable: true }] }, nullable: true)
21
+ attribute :blocker, &:blocker
21
22
 
22
23
  # Whether this stands between the seller and approval. Serialized
23
24
  # rather than left to each client to derive, so the dashboard's
@@ -20,7 +20,6 @@ module Spree
20
20
  deleted_at: [:string, nullable: true],
21
21
  on_holiday: :boolean, sellable: :boolean,
22
22
  products_count: :number, users_count: :number,
23
- onboarding_progress: '{ done: number; total: number }',
24
23
  onboarding_complete: :boolean,
25
24
  metadata: 'Record<string, unknown> | null'
26
25
 
@@ -63,7 +62,8 @@ module Spree
63
62
  # requirements themselves, with their submissions, stay on the
64
63
  # heavier `onboarding` action; a list of sellers needs the number,
65
64
  # not the rows behind it.
66
- attributes :onboarding_progress
65
+ typelize({ done: :number, total: :number })
66
+ attribute :onboarding_progress, &:onboarding_progress
67
67
 
68
68
  attribute :onboarding_complete, &:onboarding_complete?
69
69
 
@@ -7,7 +7,6 @@ module Spree
7
7
  fulfillment_type: [:string, enum: %w[shipping digital pickup pickup_point], enum_type_name: 'FulfillmentType'],
8
8
  tracking: [:string, nullable: true], tracking_url: [:string, nullable: true],
9
9
  fulfilled_at: [:string, nullable: true], delivered_at: [:string, nullable: true], unpriced: :boolean,
10
- items: 'Array<{ item_id: string; variant_id: string; quantity: number }>',
11
10
  pickup_point_data: ['Record<string, unknown>', nullable: true],
12
11
  selected_delivery_rate_id: [:string, nullable: true]
13
12
 
@@ -40,6 +39,7 @@ module Spree
40
39
 
41
40
  # Which items (and how many) are in this fulfillment.
42
41
  # A line item can be split across fulfillments with different quantities.
42
+ typelize({ item_id: :string, variant_id: :string, quantity: :number }, multi: true)
43
43
  attribute :items do |fulfillment|
44
44
  fulfillment.manifest.filter_map do |item|
45
45
  next unless item.line_item
@@ -16,7 +16,6 @@ module Spree
16
16
  failed_rows_count: :number,
17
17
  processing_errors: [:string, nullable: true],
18
18
  delimiter: :string,
19
- schema_fields: 'Array<{ name: string; label: string; required: boolean }>',
20
19
  csv_headers: [:string, multi: true],
21
20
  sample_row: 'Record<string, string | null>',
22
21
  original_filename: [:string, nullable: true],
@@ -52,6 +51,7 @@ module Spree
52
51
  import.rows_status_counts['failed'] || 0
53
52
  end
54
53
 
54
+ typelize({ name: :string, label: :string, required: :boolean }, multi: true)
55
55
  attribute :schema_fields do |import|
56
56
  import.schema_fields.map do |field|
57
57
  { name: field[:name], label: field[:label], required: field[:required].present? }
@@ -7,8 +7,7 @@ module Spree
7
7
  expires_at: [:string, nullable: true],
8
8
  accepted_at: [:string, nullable: true],
9
9
  inviter_email: :string,
10
- invitee_exists: [:boolean, optional: true],
11
- seller: '{ id: string; name: string }'
10
+ invitee_exists: [:boolean, optional: true]
12
11
 
13
12
  attributes :email,
14
13
  created_at: :iso8601, expires_at: :iso8601, accepted_at: :iso8601
@@ -29,6 +28,7 @@ module Spree
29
28
 
30
29
  # The smallest shape the acceptance page's title ("Join <seller>")
31
30
  # needs; the page is public, so nothing more of the seller goes out.
31
+ typelize({ id: :string, name: :string })
32
32
  attribute :seller do |invitation|
33
33
  { id: invitation.resource.prefixed_id, name: invitation.resource.name }
34
34
  end
@@ -18,12 +18,20 @@ module Spree
18
18
  typelize status: [:string, enum: Spree::Product.statuses, enum_type_name: 'ProductStatus'], metadata: 'Record<string, unknown>',
19
19
  product_type_id: [:string, nullable: true],
20
20
  delivery_profile_id: [:string, nullable: true],
21
+ total_on_hand: [:number, nullable: true],
21
22
  submission: ['ProductSubmission', nullable: true]
22
23
 
23
24
  attributes :status, :metadata, created_at: :iso8601, updated_at: :iso8601
24
25
 
25
26
  prefixed_id_attributes :product_type, :delivery_profile
26
27
 
28
+ # Null when any variant is not tracked: its stock is unlimited, which
29
+ # is not a number to send.
30
+ attribute :total_on_hand do |product|
31
+ total = product.total_on_hand
32
+ total.to_i unless total.infinite?
33
+ end
34
+
27
35
  many :variants,
28
36
  resource: proc { Spree.api.seller_variant_serializer },
29
37
  if: proc { expand?('variants') }
@@ -10,13 +10,14 @@ module Spree
10
10
  description: [:string, nullable: true],
11
11
  required: :boolean, position: :number, status: [:string, enum: Spree::SellerRequirementStatus::STATUSES, enum_type_name: 'SellerRequirementState'],
12
12
  blocking: :boolean, action_url: [:string, nullable: true],
13
- blocker: ['{ state: string; message: string | null } | null'],
14
13
  accepts_submissions: :boolean, requires_file: :boolean,
15
14
  accepted_content_types: [:string, multi: true],
16
15
  required_policy_name: [:string, nullable: true],
17
16
  terms_html: [:string, nullable: true]
18
17
 
19
- attributes :id, :kind, :name, :description, :required, :position, :status, :action_url, :blocker
18
+ attributes :id, :kind, :name, :description, :required, :position, :status, :action_url
19
+ typelize({ state: :string, message: [:string, { nullable: true }] }, nullable: true)
20
+ attribute :blocker, &:blocker
20
21
 
21
22
  attribute :blocking, &:blocking?
22
23
 
@@ -1,6 +1,8 @@
1
- # Disable automatic type generation on boot — types are generated manually
2
- # via `bundle exec rake typelizer:generate`. Set ENABLE_TYPELIZER=1 to enable.
3
- ENV["DISABLE_TYPELIZER"] ||= "true" unless ENV["ENABLE_TYPELIZER"]
1
+ # Types are generated only by `bundle exec rake typelizer:generate`, which sets
2
+ # TYPELIZER=true before booting; the engine's `spree.api.typelizer` initializer
3
+ # keeps Typelizer from generating on its own.
4
+
5
+ require 'spree/api/typelizer_generation'
4
6
 
5
7
  Rails.application.config.after_initialize do
6
8
  api_root = Spree::Api::Engine.root
@@ -10,22 +12,11 @@ Rails.application.config.after_initialize do
10
12
  config.comments = true
11
13
  config.listen = false
12
14
 
13
- # Teach typelizer's Alba plugin about custom Alba types (see alba.rb);
14
- # unmapped typed attributes crash generation.
15
- config.plugin_configs = {
16
- alba: {
17
- ts_mapper: Typelizer::SerializerPlugins::Alba::ALBA_TS_MAPPER.merge(
18
- 'iso8601' => { type: :string },
19
- 'string' => { type: :string }
20
- )
21
- }
22
- }
15
+ config.plugin_configs = Spree::Api::TypelizerGeneration.plugin_configs
23
16
 
24
17
  # Serializers that exist only for the Admin API. Event serializers stay in:
25
18
  # they describe the `data` of the typed webhook events the Store SDK ships.
26
- store_excluded = %w[
27
- Asset CartPromotion OrderPromotion Report TaxCategory
28
- ].to_set
19
+ store_excluded = Spree::Api::TypelizerGeneration::STORE_EXCLUDED
29
20
 
30
21
  # Store SDK — no prefix, package provides namespace
31
22
  config.writer(:store) do |c|
@@ -74,9 +65,7 @@ Rails.application.config.after_initialize do
74
65
  # branch; Category and CustomField are not, but the store product
75
66
  # serializer this branch inherits references them, so their types still
76
67
  # have to exist in the package.
77
- store_nested_for_seller = %w[
78
- Category CustomField OptionType OptionValue Seller
79
- ].to_set
68
+ store_nested_for_seller = Spree::Api::TypelizerGeneration::SELLER_STORE_TYPES
80
69
 
81
70
  config.writer(:seller) do |c|
82
71
  c.output_dir = api_root.join('../../packages/seller-sdk/src/types/generated')
data/config/routes.rb CHANGED
@@ -366,6 +366,11 @@ Spree::Core::Engine.add_routes do
366
366
  # (docs/plans/6.0-seller-product-submission.md).
367
367
  patch :approve
368
368
  patch :reject
369
+ # One product's status, through the workflow that publishes its
370
+ # event; bulk_status_update writes the column for many at once.
371
+ patch :activate
372
+ patch :archive
373
+ patch :draft
369
374
  end
370
375
  collection do
371
376
  post :bulk_status_update