spree_api 6.0.2 → 6.0.4
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.
- checksums.yaml +4 -4
- data/app/controllers/concerns/spree/api/v3/admin/embed_permissions.rb +5 -2
- data/app/controllers/concerns/spree/api/v3/idempotent.rb +10 -1
- data/app/controllers/concerns/spree/api/v3/security_headers.rb +3 -0
- data/app/controllers/spree/api/v3/admin/base_controller.rb +31 -0
- data/app/controllers/spree/api/v3/admin/companies/memberships_controller.rb +21 -4
- data/app/controllers/spree/api/v3/admin/diagnostics_controller.rb +46 -0
- data/app/controllers/spree/api/v3/admin/me_controller.rb +0 -13
- data/app/controllers/spree/api/v3/admin/media_controller.rb +10 -0
- data/app/controllers/spree/api/v3/admin/orders/items_controller.rb +6 -2
- data/app/controllers/spree/api/v3/admin/products_controller.rb +56 -0
- data/app/controllers/spree/api/v3/admin/sellers/invitations_controller.rb +39 -3
- data/app/controllers/spree/api/v3/admin/sellers/team_controller.rb +1 -3
- data/app/controllers/spree/api/v3/admin/sellers_controller.rb +24 -1
- data/app/controllers/spree/api/v3/admin/stock_levels_controller.rb +15 -1
- data/app/controllers/spree/api/v3/admin/updates_controller.rb +4 -15
- data/app/controllers/spree/api/v3/seller/products/media_controller.rb +46 -0
- data/app/controllers/spree/api/v3/seller/products_controller.rb +4 -2
- data/app/controllers/spree/api/v3/seller/profile_controller.rb +13 -5
- data/app/controllers/spree/api/v3/store/carts_controller.rb +10 -7
- data/app/serializers/spree/api/v3/admin/admin_user_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/admin/company_membership_serializer.rb +4 -0
- data/app/serializers/spree/api/v3/admin/delivery_profile_serializer.rb +2 -1
- data/app/serializers/spree/api/v3/admin/diagnostics_serializer.rb +30 -0
- data/app/serializers/spree/api/v3/admin/fulfillment_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/import_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/invitation_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/admin/line_item_serializer.rb +6 -1
- data/app/serializers/spree/api/v3/admin/price_rule_serializer.rb +3 -1
- data/app/serializers/spree/api/v3/admin/product_serializer.rb +8 -0
- data/app/serializers/spree/api/v3/admin/promotion_action_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/admin/promotion_rule_serializer.rb +4 -1
- data/app/serializers/spree/api/v3/admin/promotion_serializer.rb +13 -0
- data/app/serializers/spree/api/v3/admin/return_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/seller_requirement_status_serializer.rb +3 -2
- data/app/serializers/spree/api/v3/admin/seller_serializer.rb +12 -2
- data/app/serializers/spree/api/v3/fulfillment_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/product_category_serializer.rb +26 -0
- data/app/serializers/spree/api/v3/product_collection_serializer.rb +26 -0
- data/app/serializers/spree/api/v3/seller/import_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/seller/invitation_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/seller/order_line_item_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/seller/product_serializer.rb +8 -0
- data/app/serializers/spree/api/v3/seller/requirement_status_serializer.rb +3 -2
- data/config/initializers/typelizer.rb +8 -19
- data/config/routes.rb +8 -1
- data/lib/spree/api/admin_document.rb +284 -0
- data/lib/spree/api/agent_operations.rb +300 -0
- data/lib/spree/api/agent_resource_map.rb +74 -14
- data/lib/spree/api/agent_write_schemas.rb +15 -51
- data/lib/spree/api/dependencies.rb +1 -1
- data/lib/spree/api/engine.rb +14 -1
- data/lib/spree/api/enum_types.rb +4 -1
- data/lib/spree/api/openapi/schema_helper.rb +3 -3
- data/lib/spree/api/sdk_types.rb +190 -0
- data/lib/spree/api/sdk_types_task.rb +68 -0
- data/lib/spree/api/testing_support/agent_tools.rb +35 -0
- data/lib/spree/api/testing_support/agent_tools_contract.rb +110 -0
- data/lib/spree/api/testing_support/deterministic_openapi.rb +147 -0
- data/lib/spree/api/testing_support/filter_parameters.rb +99 -0
- data/lib/spree/api/testing_support/openapi.rb +233 -0
- data/lib/spree/api/testing_support/openapi_tasks.rb +21 -0
- data/lib/spree/api/testing_support/sdk_method.rb +34 -0
- data/lib/spree/api/typelizer_generation.rb +39 -11
- data/lib/tasks/openapi.rake +5 -0
- data/lib/tasks/sdk_types.rake +6 -0
- data/lib/typelizer/open_enums.rb +13 -1
- data/openapi/admin.yaml +2241 -318
- data/openapi/store.yaml +125 -125
- metadata +26 -9
- data/lib/spree/api/agent_workflow_endpoints.rb +0 -113
|
@@ -129,17 +129,20 @@ module Spree
|
|
|
129
129
|
end
|
|
130
130
|
end
|
|
131
131
|
|
|
132
|
-
#
|
|
133
|
-
#
|
|
132
|
+
# Abandons a cart after checking its completion claim under the row lock.
|
|
133
|
+
#
|
|
134
|
+
# @return [void]
|
|
134
135
|
def destroy
|
|
135
136
|
find_cart!
|
|
136
137
|
|
|
137
|
-
|
|
138
|
+
with_order_lock do
|
|
139
|
+
result = Spree.cart_destroy_service.call(cart: @cart)
|
|
138
140
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
141
|
+
if result.success?
|
|
142
|
+
head :no_content
|
|
143
|
+
else
|
|
144
|
+
render_service_error(result.error.to_s)
|
|
145
|
+
end
|
|
143
146
|
end
|
|
144
147
|
end
|
|
145
148
|
|
|
@@ -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
|
|
|
@@ -4,6 +4,10 @@ module Spree
|
|
|
4
4
|
module Admin
|
|
5
5
|
class CompanyMembershipSerializer < V3::CompanyMembershipSerializer
|
|
6
6
|
attributes created_at: :iso8601, updated_at: :iso8601
|
|
7
|
+
|
|
8
|
+
# The member as a customer, so a list can show their name, not only
|
|
9
|
+
# the email.
|
|
10
|
+
one :customer, resource: proc { Spree.api.admin_customer_serializer }, if: proc { expand?('customer') }
|
|
7
11
|
end
|
|
8
12
|
end
|
|
9
13
|
end
|
|
@@ -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
|
{
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module Admin
|
|
5
|
+
# The diagnostics report (Spree::Diagnostics::Report). A computed
|
|
6
|
+
# value rather than a record, so it carries no id. `errors[].error_class`
|
|
7
|
+
# is an exception's class name on purpose: it is what a maintainer
|
|
8
|
+
# reads in a bug report, not a value any client branches on.
|
|
9
|
+
class DiagnosticsSerializer < V3::BaseSerializer
|
|
10
|
+
typelize generated_at: :string,
|
|
11
|
+
spree_version: :string,
|
|
12
|
+
markdown: :string,
|
|
13
|
+
issue_url: :string,
|
|
14
|
+
issue_prefilled: :boolean,
|
|
15
|
+
sections: 'Array<{ key: string; title: string; rows: Array<{ label: string; value: string }> }>',
|
|
16
|
+
errors: 'Array<{ error_class: string; source: string | null; frames: string[]; ' \
|
|
17
|
+
'request_id: string | null; count: number; first_seen_at: string; last_seen_at: string }>'
|
|
18
|
+
|
|
19
|
+
_attributes.delete(:id)
|
|
20
|
+
|
|
21
|
+
attributes :spree_version, :sections, :errors, generated_at: :iso8601
|
|
22
|
+
|
|
23
|
+
attribute(:markdown, &:to_markdown)
|
|
24
|
+
attribute(:issue_url, &:issue_url)
|
|
25
|
+
attribute(:issue_prefilled, &:issue_prefilled?)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -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
|
|
@@ -28,7 +28,8 @@ module Spree
|
|
|
28
28
|
price_list_id: [:string, nullable: true],
|
|
29
29
|
price_list_name: [:string, nullable: true],
|
|
30
30
|
catalog_id: [:string, nullable: true],
|
|
31
|
-
catalog_name: [:string, nullable: true]
|
|
31
|
+
catalog_name: [:string, nullable: true],
|
|
32
|
+
product_id: [:string, nullable: true]
|
|
32
33
|
|
|
33
34
|
# price_source is operational provenance — admin-only, never on the
|
|
34
35
|
# store serializer.
|
|
@@ -66,6 +67,10 @@ module Spree
|
|
|
66
67
|
|
|
67
68
|
prefixed_id_attributes :tax_category
|
|
68
69
|
|
|
70
|
+
# So an order page can link each line to its product without
|
|
71
|
+
# expanding the variant.
|
|
72
|
+
prefixed_id_attributes :product
|
|
73
|
+
|
|
69
74
|
# Override inherited associations to use admin serializers
|
|
70
75
|
many :option_values, resource: proc { Spree.api.admin_option_value_serializer }
|
|
71
76
|
many :digital_links, resource: proc { Spree.api.admin_digital_link_serializer }
|
|
@@ -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
|
|
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
|
|
|
@@ -56,6 +55,11 @@ module Spree
|
|
|
56
55
|
# so the minimum-products requirement asks the same question free.
|
|
57
56
|
attributes :products_count
|
|
58
57
|
|
|
58
|
+
# What is live and what waits on the operator's review, read in the
|
|
59
|
+
# same query as the total above.
|
|
60
|
+
typelize(Spree::Product::ALL_STATUSES.to_h { |status| [status.to_sym, :number] })
|
|
61
|
+
attribute :products_count_by_status, &:products_count_by_status
|
|
62
|
+
|
|
59
63
|
attributes :users_count
|
|
60
64
|
|
|
61
65
|
# How far through the marketplace's checklist this seller is — what
|
|
@@ -63,7 +67,8 @@ module Spree
|
|
|
63
67
|
# requirements themselves, with their submissions, stay on the
|
|
64
68
|
# heavier `onboarding` action; a list of sellers needs the number,
|
|
65
69
|
# not the rows behind it.
|
|
66
|
-
|
|
70
|
+
typelize({ done: :number, total: :number })
|
|
71
|
+
attribute :onboarding_progress, &:onboarding_progress
|
|
67
72
|
|
|
68
73
|
attribute :onboarding_complete, &:onboarding_complete?
|
|
69
74
|
|
|
@@ -78,6 +83,11 @@ module Spree
|
|
|
78
83
|
resource: proc { Spree.api.admin_address_serializer },
|
|
79
84
|
if: proc { |seller| seller.returns_address.present? }
|
|
80
85
|
|
|
86
|
+
# The stock location the returns address is read from. The address
|
|
87
|
+
# is not the seller's own to write — it is edited on this location.
|
|
88
|
+
typelize returns_location_id: [:string, nullable: true]
|
|
89
|
+
prefixed_id_attributes :returns_location
|
|
90
|
+
|
|
81
91
|
expandable_custom_fields admin: true
|
|
82
92
|
end
|
|
83
93
|
end
|
|
@@ -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
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
class ProductCategorySerializer < BaseSerializer
|
|
5
|
+
typelize product_id: [:string, nullable: true],
|
|
6
|
+
category_id: [:string, nullable: true]
|
|
7
|
+
|
|
8
|
+
attribute :product_id do |product_category|
|
|
9
|
+
prefixed_id_for(Spree::Product, product_category.product_id)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
attribute :category_id do |product_category|
|
|
13
|
+
prefixed_id_for(Spree::Category, product_category.category_id)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def prefixed_id_for(klass, id)
|
|
19
|
+
return nil if id.nil?
|
|
20
|
+
|
|
21
|
+
"#{klass._prefix_id_prefix}_#{Spree::PrefixedId::SQIDS.encode([id])}"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
class ProductCollectionSerializer < BaseSerializer
|
|
5
|
+
typelize product_id: [:string, nullable: true],
|
|
6
|
+
collection_id: [:string, nullable: true]
|
|
7
|
+
|
|
8
|
+
attribute :product_id do |product_collection|
|
|
9
|
+
prefixed_id_for(Spree::Product, product_collection.product_id)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
attribute :collection_id do |product_collection|
|
|
13
|
+
prefixed_id_for(Spree::Collection, product_collection.collection_id)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def prefixed_id_for(klass, id)
|
|
19
|
+
return nil if id.nil?
|
|
20
|
+
|
|
21
|
+
"#{klass._prefix_id_prefix}_#{Spree::PrefixedId::SQIDS.encode([id])}"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -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
|
|
@@ -13,7 +13,7 @@ module Spree
|
|
|
13
13
|
class OrderLineItemSerializer < V3::BaseSerializer
|
|
14
14
|
typelize name: :string, sku: [:string, nullable: true], options_text: [:string, nullable: true],
|
|
15
15
|
quantity: :number, currency: [:string, enum: Spree::Money::Rounding::CURRENCY_CODES, enum_type_name: 'CurrencyCode'], variant_id: [:string, nullable: true],
|
|
16
|
-
thumbnail_url: [:string, nullable: true]
|
|
16
|
+
thumbnail_url: [:string, nullable: true], product_id: [:string, nullable: true]
|
|
17
17
|
|
|
18
18
|
attributes :name, :options_text, :quantity, :currency
|
|
19
19
|
|
|
@@ -22,7 +22,7 @@ module Spree
|
|
|
22
22
|
money_attributes :discounted_amount,
|
|
23
23
|
:additional_tax_total, :total
|
|
24
24
|
|
|
25
|
-
prefixed_id_attributes :variant
|
|
25
|
+
prefixed_id_attributes :variant, :product
|
|
26
26
|
|
|
27
27
|
# How a seller finds the item on their own shelf.
|
|
28
28
|
attribute :sku do |line_item|
|
|
@@ -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
|
|
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
|
-
#
|
|
2
|
-
#
|
|
3
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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
|
@@ -285,6 +285,7 @@ Spree::Core::Engine.add_routes do
|
|
|
285
285
|
patch 'me', to: 'me#update'
|
|
286
286
|
|
|
287
287
|
resource :updates, only: :show
|
|
288
|
+
resource :diagnostics, only: :show
|
|
288
289
|
|
|
289
290
|
# Store Settings
|
|
290
291
|
resource :store, only: [:show, :update], controller: 'store' do
|
|
@@ -366,6 +367,11 @@ Spree::Core::Engine.add_routes do
|
|
|
366
367
|
# (docs/plans/6.0-seller-product-submission.md).
|
|
367
368
|
patch :approve
|
|
368
369
|
patch :reject
|
|
370
|
+
# One product's status, through the workflow that publishes its
|
|
371
|
+
# event; bulk_status_update writes the column for many at once.
|
|
372
|
+
patch :activate
|
|
373
|
+
patch :archive
|
|
374
|
+
patch :draft
|
|
369
375
|
end
|
|
370
376
|
collection do
|
|
371
377
|
post :bulk_status_update
|
|
@@ -605,7 +611,7 @@ Spree::Core::Engine.add_routes do
|
|
|
605
611
|
# The operator is the only one who can repair a seller whose team
|
|
606
612
|
# has locked itself out, which the seller's own panel cannot do.
|
|
607
613
|
resources :team, only: [:index, :destroy], controller: 'sellers/team'
|
|
608
|
-
resources :invitations, only: [:index, :destroy], controller: 'sellers/invitations' do
|
|
614
|
+
resources :invitations, only: [:index, :create, :destroy], controller: 'sellers/invitations' do
|
|
609
615
|
patch :resend, on: :member
|
|
610
616
|
resource :acceptance_link, only: [:show], controller: 'sellers/invitations/acceptance_links'
|
|
611
617
|
end
|
|
@@ -925,6 +931,7 @@ Spree::Core::Engine.add_routes do
|
|
|
925
931
|
|
|
926
932
|
resources :digital_assets, controller: 'products/digital_assets',
|
|
927
933
|
only: [:index, :create, :show, :update, :destroy]
|
|
934
|
+
resources :media, controller: 'products/media', only: [:destroy]
|
|
928
935
|
end
|
|
929
936
|
|
|
930
937
|
|