spree_api 6.0.0.beta2 → 6.0.0.beta3
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 +55 -0
- data/app/controllers/concerns/spree/api/v3/admin/role_grant_guard.rb +34 -5
- data/app/controllers/concerns/spree/api/v3/current_password_confirmation.rb +8 -0
- data/app/controllers/concerns/spree/api/v3/orders/fulfillment_actions.rb +15 -2
- data/app/controllers/concerns/spree/api/v3/scoped_authorization.rb +14 -0
- data/app/controllers/concerns/spree/api/v3/store/storefront_products.rb +35 -0
- data/app/controllers/spree/api/v3/admin/admin_users_controller.rb +9 -0
- data/app/controllers/spree/api/v3/admin/base_controller.rb +1 -0
- data/app/controllers/spree/api/v3/admin/custom_fields_controller.rb +8 -3
- data/app/controllers/spree/api/v3/admin/customers_controller.rb +0 -14
- data/app/controllers/spree/api/v3/admin/gift_cards_controller.rb +29 -2
- data/app/controllers/spree/api/v3/admin/invitation_acceptances_controller.rb +4 -1
- data/app/controllers/spree/api/v3/admin/invitations/acceptance_links_controller.rb +41 -0
- data/app/controllers/spree/api/v3/admin/me_controller.rb +11 -0
- data/app/controllers/spree/api/v3/admin/orders/claims_controller.rb +14 -1
- data/app/controllers/spree/api/v3/admin/orders/exchanges_controller.rb +22 -1
- data/app/controllers/spree/api/v3/admin/orders/fulfillments_controller.rb +1 -1
- data/app/controllers/spree/api/v3/admin/orders/returns_controller.rb +22 -1
- data/app/controllers/spree/api/v3/admin/orders_controller.rb +27 -1
- data/app/controllers/spree/api/v3/admin/password_resets_controller.rb +31 -11
- data/app/controllers/spree/api/v3/admin/price_lists_controller.rb +1 -19
- data/app/controllers/spree/api/v3/admin/prices_controller.rb +33 -2
- data/app/controllers/spree/api/v3/admin/products_controller.rb +1 -1
- data/app/controllers/spree/api/v3/admin/resource_controller.rb +1 -0
- data/app/controllers/spree/api/v3/admin/sellers/invitations/acceptance_links_controller.rb +37 -0
- data/app/controllers/spree/api/v3/admin/setup_controller.rb +1 -1
- data/app/controllers/spree/api/v3/admin/store_controller.rb +4 -0
- data/app/controllers/spree/api/v3/admin/translations/batches_controller.rb +1 -1
- data/app/controllers/spree/api/v3/admin/translations_controller.rb +1 -1
- data/app/controllers/spree/api/v3/admin/webhook_deliveries_controller.rb +12 -0
- data/app/controllers/spree/api/v3/admin/webhook_endpoints_controller.rb +27 -0
- data/app/controllers/spree/api/v3/base_controller.rb +7 -3
- data/app/controllers/spree/api/v3/resource_controller.rb +11 -1
- data/app/controllers/spree/api/v3/seller/auth_controller.rb +1 -1
- data/app/controllers/spree/api/v3/seller/invitation_acceptances_controller.rb +5 -2
- data/app/controllers/spree/api/v3/seller/invitations/acceptance_links_controller.rb +34 -0
- data/app/controllers/spree/api/v3/seller/me_controller.rb +25 -2
- data/app/controllers/spree/api/v3/seller/orders_controller.rb +19 -24
- data/app/controllers/spree/api/v3/seller/password_resets_controller.rb +1 -1
- data/app/controllers/spree/api/v3/seller/resource_controller.rb +4 -0
- data/app/controllers/spree/api/v3/store/carts/items_controller.rb +7 -4
- data/app/controllers/spree/api/v3/store/carts/payment_sessions_controller.rb +10 -1
- data/app/controllers/spree/api/v3/store/carts/payments_controller.rb +5 -1
- data/app/controllers/spree/api/v3/store/companies/members_controller.rb +10 -11
- data/app/controllers/spree/api/v3/store/companies/orders_controller.rb +6 -0
- data/app/controllers/spree/api/v3/store/products/filters_controller.rb +1 -0
- data/app/controllers/spree/api/v3/store/products_controller.rb +6 -12
- data/app/controllers/spree/api/v3/store/resource_controller.rb +4 -0
- data/app/controllers/spree/api/v3/store/wishlist_items_controller.rb +11 -0
- data/app/controllers/spree/api/v3/webhooks/fulfillments_controller.rb +10 -6
- data/app/controllers/spree/api/v3/webhooks/payments_controller.rb +6 -2
- data/app/controllers/spree/api/v3/webhooks/payouts_controller.rb +6 -2
- data/app/jobs/spree/webhook_delivery_job.rb +18 -4
- data/app/serializers/spree/api/v3/admin/gift_card_serializer.rb +6 -0
- data/app/serializers/spree/api/v3/admin/invitation_acceptance_link_serializer.rb +15 -0
- data/app/serializers/spree/api/v3/admin/invitation_serializer.rb +0 -11
- data/app/serializers/spree/api/v3/admin/order_group_serializer.rb +7 -0
- data/app/serializers/spree/api/v3/admin/store_serializer.rb +8 -0
- data/app/serializers/spree/api/v3/admin/webhook_delivery_serializer.rb +6 -2
- data/app/serializers/spree/api/v3/gift_card_serializer.rb +3 -1
- data/app/serializers/spree/api/v3/line_item_serializer.rb +2 -1
- data/app/serializers/spree/api/v3/market_serializer.rb +5 -0
- data/app/serializers/spree/api/v3/product_filters_serializer.rb +3 -0
- data/app/serializers/spree/api/v3/seller/account_serializer.rb +19 -0
- data/app/serializers/spree/api/v3/seller/invitation_acceptance_link_serializer.rb +15 -0
- data/app/serializers/spree/api/v3/seller/invitation_serializer.rb +1 -10
- data/app/services/spree/api/v3/filters_aggregator.rb +5 -2
- data/config/routes.rb +7 -0
- data/lib/spree/api/dependencies.rb +3 -0
- data/lib/spree/api/openapi/schema_helper.rb +10 -4
- metadata +14 -6
|
@@ -5,6 +5,7 @@ module Spree
|
|
|
5
5
|
class ProductsController < ResourceController
|
|
6
6
|
include Spree::Api::V3::HttpCaching
|
|
7
7
|
include Spree::Api::V3::Store::SearchProviderSupport
|
|
8
|
+
include Spree::Api::V3::Store::StorefrontProducts
|
|
8
9
|
|
|
9
10
|
protected
|
|
10
11
|
|
|
@@ -28,19 +29,12 @@ module Spree
|
|
|
28
29
|
end
|
|
29
30
|
end
|
|
30
31
|
|
|
32
|
+
# Catalog narrowing for the buyer: their company's effective
|
|
33
|
+
# catalogs, their group's, or the channel default — union of
|
|
34
|
+
# assortments, resolved in one place
|
|
35
|
+
# (docs/plans/6.0-b2b-companies-and-catalogs.md).
|
|
31
36
|
def scope
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
# Catalog narrowing for the buyer: their company's effective
|
|
35
|
-
# catalogs, their group's, or the channel default — union of
|
|
36
|
-
# assortments, resolved in one place
|
|
37
|
-
# (docs/plans/6.0-b2b-companies-and-catalogs.md).
|
|
38
|
-
Spree.products_for_context_service.call(
|
|
39
|
-
store: current_store,
|
|
40
|
-
channel: current_channel,
|
|
41
|
-
customer: current_user,
|
|
42
|
-
base: base
|
|
43
|
-
).value
|
|
37
|
+
storefront_products(super)
|
|
44
38
|
end
|
|
45
39
|
|
|
46
40
|
# these scopes are not automatically picked by ar_lazy_preload gem and we need to explicitly include them
|
|
@@ -3,6 +3,8 @@ module Spree
|
|
|
3
3
|
module V3
|
|
4
4
|
module Store
|
|
5
5
|
class WishlistItemsController < ResourceController
|
|
6
|
+
include Spree::Api::V3::Store::StorefrontProducts
|
|
7
|
+
|
|
6
8
|
prepend_before_action :require_authentication!
|
|
7
9
|
|
|
8
10
|
protected
|
|
@@ -29,6 +31,15 @@ module Spree
|
|
|
29
31
|
def resource_permitted_attributes
|
|
30
32
|
[:variant_id, :quantity]
|
|
31
33
|
end
|
|
34
|
+
|
|
35
|
+
# The item renders its variant and product, so the variant must be
|
|
36
|
+
# one the buyer could find in the listing — not a draft, another
|
|
37
|
+
# catalog's product, or an id guessed from the sequence.
|
|
38
|
+
def permitted_params
|
|
39
|
+
@permitted_params ||= super.tap do |attributes|
|
|
40
|
+
attributes[:variant_id] = storefront_variants.find_by_prefix_id!(params[:variant_id]).id if params.key?(:variant_id)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
32
43
|
end
|
|
33
44
|
end
|
|
34
45
|
end
|
|
@@ -15,7 +15,6 @@ module Spree
|
|
|
15
15
|
# sender's timeout.
|
|
16
16
|
class FulfillmentsController < ActionController::API
|
|
17
17
|
include ActionController::RateLimiting
|
|
18
|
-
include Spree::Core::ControllerHelpers::Store
|
|
19
18
|
|
|
20
19
|
# Must render — instance_exec'd in a before_action, where only
|
|
21
20
|
# render/redirect halts the chain.
|
|
@@ -31,12 +30,17 @@ module Spree
|
|
|
31
30
|
with: RATE_LIMIT_RESPONSE
|
|
32
31
|
|
|
33
32
|
def create
|
|
34
|
-
|
|
33
|
+
# By id alone: providers call back without an API key or store
|
|
34
|
+
# header, so the request cannot name the store — the record does.
|
|
35
|
+
# The signature check below, against the record's own secret, is
|
|
36
|
+
# what authenticates the request.
|
|
37
|
+
integration = Spree::Integration.active.find_by_prefix_id!(params[:integration_id])
|
|
38
|
+
Spree::Current.store = integration.store
|
|
35
39
|
|
|
36
40
|
event = integration.parse_webhook_event(request.raw_post, request.headers)
|
|
37
41
|
return head :ok if event.nil?
|
|
38
42
|
|
|
39
|
-
delivery = find_delivery(event[:tracking_code])
|
|
43
|
+
delivery = find_delivery(integration.store, event[:tracking_code])
|
|
40
44
|
return head :ok if delivery.nil?
|
|
41
45
|
|
|
42
46
|
Spree.delivery_update_tracking_workflow.call(
|
|
@@ -57,7 +61,7 @@ module Spree
|
|
|
57
61
|
private
|
|
58
62
|
|
|
59
63
|
# Scoped to the store the verified integration belongs to — a
|
|
60
|
-
# tracking code can never address another
|
|
64
|
+
# tracking code can never address another store's parcel — and to
|
|
61
65
|
# consignments whose parcel was not canceled, so a recycled code
|
|
62
66
|
# cannot reopen an old one. The newest wins when a code was reused.
|
|
63
67
|
# Carriers reuse tracking numbers across years, so a code can match
|
|
@@ -67,14 +71,14 @@ module Spree
|
|
|
67
71
|
# database. The newest survivor wins.
|
|
68
72
|
CANDIDATE_LIMIT = 20
|
|
69
73
|
|
|
70
|
-
def find_delivery(tracking_code)
|
|
74
|
+
def find_delivery(store, tracking_code)
|
|
71
75
|
return if tracking_code.blank?
|
|
72
76
|
|
|
73
77
|
# Paged rather than capped: a tracking number reused across
|
|
74
78
|
# canceled owners would otherwise fill the window and hide the
|
|
75
79
|
# live delivery behind them, and the webhook would be
|
|
76
80
|
# acknowledged without applying the carrier's update.
|
|
77
|
-
|
|
81
|
+
store.deliveries.
|
|
78
82
|
where(tracking_number: tracking_code).
|
|
79
83
|
order(created_at: :desc, id: :desc).
|
|
80
84
|
includes(:owner).
|
|
@@ -4,7 +4,6 @@ module Spree
|
|
|
4
4
|
module Webhooks
|
|
5
5
|
class PaymentsController < ActionController::API
|
|
6
6
|
include ActionController::RateLimiting
|
|
7
|
-
include Spree::Core::ControllerHelpers::Store
|
|
8
7
|
|
|
9
8
|
# Must render — instance_exec'd in a before_action, where only
|
|
10
9
|
# render/redirect halts the chain.
|
|
@@ -24,7 +23,12 @@ module Spree
|
|
|
24
23
|
# Verifies the webhook signature synchronously (returns 401 if invalid),
|
|
25
24
|
# then enqueues async processing and returns 200 immediately.
|
|
26
25
|
def create
|
|
27
|
-
|
|
26
|
+
# By id alone: providers call back without an API key or store
|
|
27
|
+
# header, so the request cannot name the store — the record does.
|
|
28
|
+
# The signature check below, against the record's own secret, is
|
|
29
|
+
# what authenticates the request.
|
|
30
|
+
payment_method = Spree::PaymentMethod.find_by_prefix_id!(params[:payment_method_id])
|
|
31
|
+
Spree::Current.store = payment_method.store
|
|
28
32
|
|
|
29
33
|
# Signature verification must be synchronous — invalid = 401
|
|
30
34
|
result = payment_method.parse_webhook_event(request.raw_post, request.headers)
|
|
@@ -19,7 +19,6 @@ module Spree
|
|
|
19
19
|
# database writes, well inside any sender's timeout.
|
|
20
20
|
class PayoutsController < ActionController::API
|
|
21
21
|
include ActionController::RateLimiting
|
|
22
|
-
include Spree::Core::ControllerHelpers::Store
|
|
23
22
|
|
|
24
23
|
# Must render — instance_exec'd in a before_action, where only
|
|
25
24
|
# render/redirect halts the chain.
|
|
@@ -35,7 +34,12 @@ module Spree
|
|
|
35
34
|
with: RATE_LIMIT_RESPONSE
|
|
36
35
|
|
|
37
36
|
def create
|
|
38
|
-
|
|
37
|
+
# By id alone: providers call back without an API key or store
|
|
38
|
+
# header, so the request cannot name the store — the record does.
|
|
39
|
+
# The signature check below, against the record's own secret, is
|
|
40
|
+
# what authenticates the request.
|
|
41
|
+
payment_method = Spree::PaymentMethod.find_by_prefix_id!(params[:payment_method_id])
|
|
42
|
+
Spree::Current.store = payment_method.store
|
|
39
43
|
return head :not_found unless payment_method.respond_to?(:handle_payout_webhook)
|
|
40
44
|
|
|
41
45
|
payment_method.handle_payout_webhook(request.raw_post, request.headers)
|
|
@@ -2,11 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
module Spree
|
|
4
4
|
class WebhookDeliveryJob < Spree::BaseJob
|
|
5
|
+
# Raised when the endpoint answered with anything other than 2xx, timed
|
|
6
|
+
# out or could not be reached, so the delivery is sent again with backoff.
|
|
7
|
+
class DeliveryFailed < StandardError; end
|
|
8
|
+
|
|
5
9
|
queue_as Spree.queues.webhooks
|
|
6
10
|
|
|
7
|
-
#
|
|
8
|
-
#
|
|
11
|
+
# Delivery is retry-safe: each attempt overwrites the outcome on the same
|
|
12
|
+
# delivery record, and receivers deduplicate on the event id.
|
|
9
13
|
retry_on StandardError, wait: :polynomially_longer, attempts: 5
|
|
14
|
+
# The outcome of the last attempt is already on the delivery record, so an
|
|
15
|
+
# exhausted retry is not re-raised into the queue backend.
|
|
16
|
+
retry_on DeliveryFailed, wait: :polynomially_longer, attempts: 5 do |_job, _error|
|
|
17
|
+
end
|
|
10
18
|
# Must come after `retry_on StandardError` so DeserializationError lands in discard
|
|
11
19
|
# (ActiveJob handler lookup is reverse-declaration-order).
|
|
12
20
|
discard_on ActiveJob::DeserializationError
|
|
@@ -21,9 +29,15 @@ module Spree
|
|
|
21
29
|
delivery = Spree::WebhookDelivery.find_by(id: delivery_id)
|
|
22
30
|
return if delivery.nil?
|
|
23
31
|
|
|
32
|
+
endpoint = delivery.webhook_endpoint
|
|
33
|
+
return if endpoint.nil?
|
|
34
|
+
# A retry stops once the endpoint was switched off, by hand or by auto-disable.
|
|
35
|
+
return if executions > 1 && !endpoint.active?
|
|
36
|
+
|
|
24
37
|
delivery.payload_secrets = payload_secrets
|
|
25
|
-
secret_key
|
|
26
|
-
|
|
38
|
+
Spree::Webhooks::DeliverWebhook.call(delivery: delivery, secret_key: endpoint.secret_key)
|
|
39
|
+
|
|
40
|
+
raise DeliveryFailed, "Webhook delivery #{delivery.prefixed_id} failed" if delivery.failed?
|
|
27
41
|
end
|
|
28
42
|
end
|
|
29
43
|
end
|
|
@@ -18,6 +18,12 @@ module Spree
|
|
|
18
18
|
|
|
19
19
|
attributes created_at: :iso8601, updated_at: :iso8601
|
|
20
20
|
|
|
21
|
+
# A bearer credential: in full only to a caller who may read gift
|
|
22
|
+
# cards, masked when the card rides along on an order.
|
|
23
|
+
attribute :code do |gift_card|
|
|
24
|
+
params[:gift_card_codes] ? gift_card.display_code : gift_card.masked_code
|
|
25
|
+
end
|
|
26
|
+
|
|
21
27
|
attribute :customer_id do |gift_card|
|
|
22
28
|
gift_card.customer&.prefixed_id
|
|
23
29
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module Admin
|
|
5
|
+
# The acceptance link of one staff invitation, served on its own so the
|
|
6
|
+
# token never travels with the invitation listing.
|
|
7
|
+
class InvitationAcceptanceLinkSerializer < V3::BaseSerializer
|
|
8
|
+
typelize acceptance_url: :string
|
|
9
|
+
|
|
10
|
+
attributes :acceptance_url
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -13,7 +13,6 @@ module Spree
|
|
|
13
13
|
role_name: :string,
|
|
14
14
|
inviter_email: :string,
|
|
15
15
|
expires_at: :string,
|
|
16
|
-
acceptance_url: :string,
|
|
17
16
|
invitee_exists: :boolean,
|
|
18
17
|
store: '{ id: string; name: string }'
|
|
19
18
|
|
|
@@ -34,16 +33,6 @@ module Spree
|
|
|
34
33
|
invitation.inviter.email
|
|
35
34
|
end
|
|
36
35
|
|
|
37
|
-
# Absolute URL when a dashboard origin is configured, otherwise the
|
|
38
|
-
# path so the SPA can prepend `window.location.origin`.
|
|
39
|
-
attribute :acceptance_url do |invitation|
|
|
40
|
-
if Spree::Config[:dashboard_url].present?
|
|
41
|
-
Rails.application.routes.url_helpers.admin_invitation_acceptance_url(invitation)
|
|
42
|
-
else
|
|
43
|
-
"/accept-invitation/#{invitation.prefixed_id}?token=#{invitation.token}"
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
36
|
# Drives the SPA's sign-in vs sign-up branch on the acceptance page.
|
|
48
37
|
# Looked up by email so an admin who's already on another store sees
|
|
49
38
|
# the password prompt, not a fresh account form.
|
|
@@ -13,6 +13,8 @@ module Spree
|
|
|
13
13
|
cart_id: 'string | null',
|
|
14
14
|
seller_count: :number,
|
|
15
15
|
includes_first_party: :boolean,
|
|
16
|
+
confirmation_delivered: :boolean,
|
|
17
|
+
store_owner_notification_delivered: :boolean,
|
|
16
18
|
created_at: :string, updated_at: :string
|
|
17
19
|
|
|
18
20
|
attribute :customer_id do |group|
|
|
@@ -34,6 +36,11 @@ module Spree
|
|
|
34
36
|
group.includes_first_party?
|
|
35
37
|
end
|
|
36
38
|
|
|
39
|
+
# A split checkout is confirmed once, from here — every child order
|
|
40
|
+
# places silently, so their own flags are false and only the group
|
|
41
|
+
# can answer whether the customer was told.
|
|
42
|
+
attributes :confirmation_delivered, :store_owner_notification_delivered
|
|
43
|
+
|
|
37
44
|
attributes :created_at, :updated_at
|
|
38
45
|
|
|
39
46
|
# Re-declared against the admin serializers. Inheriting the store
|
|
@@ -42,6 +42,10 @@ module Spree
|
|
|
42
42
|
preferred_payout_provider: 'string | null',
|
|
43
43
|
preferred_default_payouts_schedule_interval: :string,
|
|
44
44
|
preferred_default_minimum_payout_amount: :number,
|
|
45
|
+
preferred_auto_approve_sellers: :boolean,
|
|
46
|
+
preferred_auto_approve_seller_products: :boolean,
|
|
47
|
+
preferred_send_seller_transactional_emails: :boolean,
|
|
48
|
+
preferred_default_commission_tax_rate: :number,
|
|
45
49
|
preferred_document_number_format: :string,
|
|
46
50
|
preferred_order_number_prefix: :string,
|
|
47
51
|
preferred_order_number_suffix: :string,
|
|
@@ -90,6 +94,10 @@ module Spree
|
|
|
90
94
|
:preferred_payout_provider,
|
|
91
95
|
:preferred_default_payouts_schedule_interval,
|
|
92
96
|
:preferred_default_minimum_payout_amount,
|
|
97
|
+
:preferred_auto_approve_sellers,
|
|
98
|
+
:preferred_auto_approve_seller_products,
|
|
99
|
+
:preferred_send_seller_transactional_emails,
|
|
100
|
+
:preferred_default_commission_tax_rate,
|
|
93
101
|
:preferred_document_number_format,
|
|
94
102
|
:preferred_order_number_prefix,
|
|
95
103
|
:preferred_order_number_suffix,
|
|
@@ -19,7 +19,7 @@ module Spree
|
|
|
19
19
|
response_body: [:string, nullable: true],
|
|
20
20
|
success: [:boolean, nullable: true],
|
|
21
21
|
delivered_at: [:string, nullable: true],
|
|
22
|
-
payload: 'Record<string, unknown>',
|
|
22
|
+
payload: ['Record<string, unknown>', nullable: true],
|
|
23
23
|
webhook_endpoint_id: :string,
|
|
24
24
|
webhook_endpoint_url: :string
|
|
25
25
|
|
|
@@ -29,8 +29,12 @@ module Spree
|
|
|
29
29
|
delivered_at: :iso8601
|
|
30
30
|
|
|
31
31
|
# Redacted again on read: deliveries written before payload redaction
|
|
32
|
-
# shipped still hold live credentials in the column.
|
|
32
|
+
# shipped still hold live credentials in the column. Null when the
|
|
33
|
+
# caller cannot read the record the event is about.
|
|
33
34
|
attribute :payload do |delivery|
|
|
35
|
+
visible = params[:payload_visible]
|
|
36
|
+
next nil if visible && !visible.call(delivery)
|
|
37
|
+
|
|
34
38
|
Spree::WebhookPayloadRedaction.split(delivery.payload).first
|
|
35
39
|
end
|
|
36
40
|
|
|
@@ -17,8 +17,10 @@ module Spree
|
|
|
17
17
|
expired: :boolean,
|
|
18
18
|
active: :boolean
|
|
19
19
|
|
|
20
|
+
# A bearer credential: masked when the order is shown to someone other
|
|
21
|
+
# than its buyer (a company's other members).
|
|
20
22
|
attribute :code do |gift_card|
|
|
21
|
-
gift_card.display_code
|
|
23
|
+
params[:hide_credentials] ? gift_card.masked_code : gift_card.display_code
|
|
22
24
|
end
|
|
23
25
|
|
|
24
26
|
attribute :status do |gift_card|
|
|
@@ -71,7 +71,8 @@ module Spree
|
|
|
71
71
|
if: proc { expand?('seller') }
|
|
72
72
|
|
|
73
73
|
many :option_values, resource: proc { Spree.api.option_value_serializer }
|
|
74
|
-
|
|
74
|
+
# Download links carry a bearer token; only the buyer gets them.
|
|
75
|
+
many :digital_links, resource: proc { Spree.api.digital_link_serializer }, if: proc { !params[:hide_credentials] }
|
|
75
76
|
# Tax hangs off its adjustable, never off the cart or order: the
|
|
76
77
|
# exactly-one-adjustable rule makes the nested view complete, and the
|
|
77
78
|
# owner already carries the tax totals.
|
|
@@ -6,11 +6,16 @@ module Spree
|
|
|
6
6
|
default_locale: :string,
|
|
7
7
|
supported_locales: [:string, multi: true],
|
|
8
8
|
country_codes: [:string, multi: true],
|
|
9
|
+
country_isos: [:string, multi: true],
|
|
9
10
|
tax_inclusive: :boolean,
|
|
10
11
|
default: :boolean
|
|
11
12
|
|
|
12
13
|
attributes :name, :currency, :default_locale, :tax_inclusive, :default, :country_codes
|
|
13
14
|
|
|
15
|
+
# @deprecated Storefronts shipped against this name; use +country_codes+.
|
|
16
|
+
# Removed in 6.1.
|
|
17
|
+
attribute :country_isos, &:country_codes
|
|
18
|
+
|
|
14
19
|
attribute :supported_locales do |market|
|
|
15
20
|
market.supported_locales_list
|
|
16
21
|
end
|
|
@@ -12,6 +12,9 @@ module Spree
|
|
|
12
12
|
attribute :filters do |result|
|
|
13
13
|
result.filters.filter_map do |filter|
|
|
14
14
|
filter_type = filter[:type]
|
|
15
|
+
# A price range is prices; a gated guest sees none.
|
|
16
|
+
next if filter_type == 'price_range' && params[:hide_prices]
|
|
17
|
+
|
|
15
18
|
serializer_class = case filter_type
|
|
16
19
|
when 'price_range'
|
|
17
20
|
Spree.api.product_filter_price_range_serializer
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module Seller
|
|
5
|
+
# The signed-in person's own account, as `/me` answers it.
|
|
6
|
+
#
|
|
7
|
+
# Extends the team member shape rather than widening it: `selected_locale`
|
|
8
|
+
# is a preference its owner sets, and the team list serializes colleagues
|
|
9
|
+
# with the parent — where publishing each member's chosen language would
|
|
10
|
+
# tell the whole team something none of them asked to share.
|
|
11
|
+
class AccountSerializer < Seller::TeamMemberSerializer
|
|
12
|
+
typelize selected_locale: [:string, nullable: true]
|
|
13
|
+
|
|
14
|
+
attributes :selected_locale
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module Seller
|
|
5
|
+
# The acceptance link of one seller-team invitation, served on its own
|
|
6
|
+
# so the token never travels with the invitation listing.
|
|
7
|
+
class InvitationAcceptanceLinkSerializer < V3::BaseSerializer
|
|
8
|
+
typelize acceptance_url: :string
|
|
9
|
+
|
|
10
|
+
attributes :acceptance_url
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -5,8 +5,7 @@ module Spree
|
|
|
5
5
|
class InvitationSerializer < V3::BaseSerializer
|
|
6
6
|
typelize email: :string, status: [:string, enum: Spree::Invitation.statuses, enum_type_name: 'InvitationStatus'],
|
|
7
7
|
expires_at: [:string, nullable: true],
|
|
8
|
-
accepted_at: [:string, nullable: true]
|
|
9
|
-
acceptance_url: :string
|
|
8
|
+
accepted_at: [:string, nullable: true]
|
|
10
9
|
|
|
11
10
|
attributes :email,
|
|
12
11
|
created_at: :iso8601, expires_at: :iso8601, accepted_at: :iso8601
|
|
@@ -14,14 +13,6 @@ module Spree
|
|
|
14
13
|
attribute :status do |invitation|
|
|
15
14
|
invitation.status.to_s
|
|
16
15
|
end
|
|
17
|
-
|
|
18
|
-
attribute :acceptance_url do |invitation|
|
|
19
|
-
if Spree::Config[:seller_panel_url].present? || Spree::Config[:dashboard_url].present?
|
|
20
|
-
Rails.application.routes.url_helpers.admin_invitation_acceptance_url(invitation)
|
|
21
|
-
else
|
|
22
|
-
"/accept-invitation/#{invitation.prefixed_id}?token=#{invitation.token}"
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
16
|
end
|
|
26
17
|
end
|
|
27
18
|
end
|
|
@@ -51,8 +51,11 @@ module Spree
|
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
def price_filter
|
|
54
|
-
# Remove ordering to avoid PostgreSQL DISTINCT + ORDER BY conflicts
|
|
55
|
-
prices
|
|
54
|
+
# Remove ordering to avoid PostgreSQL DISTINCT + ORDER BY conflicts.
|
|
55
|
+
# Base prices only: a price list's rows are for its own audience
|
|
56
|
+
# (a company's contract, a draft or scheduled list), and the range is
|
|
57
|
+
# shown to everyone.
|
|
58
|
+
prices = Spree::Price.base_prices.for_products(@scope.reorder(''), @currency)
|
|
56
59
|
min = prices.minimum(:amount)
|
|
57
60
|
max = prices.maximum(:amount)
|
|
58
61
|
return nil if min.nil? || max.nil?
|
data/config/routes.rb
CHANGED
|
@@ -273,6 +273,7 @@ Spree::Core::Engine.add_routes do
|
|
|
273
273
|
member do
|
|
274
274
|
patch :resend
|
|
275
275
|
end
|
|
276
|
+
resource :acceptance_link, only: [:show], controller: 'invitations/acceptance_links'
|
|
276
277
|
end
|
|
277
278
|
resources :api_keys, only: [:index, :show, :create, :update, :destroy] do
|
|
278
279
|
collection do
|
|
@@ -590,6 +591,7 @@ Spree::Core::Engine.add_routes do
|
|
|
590
591
|
member do
|
|
591
592
|
patch :resend
|
|
592
593
|
end
|
|
594
|
+
resource :acceptance_link, only: [:show], controller: 'sellers/invitations/acceptance_links'
|
|
593
595
|
end
|
|
594
596
|
|
|
595
597
|
# What this seller submitted about the requirements, and the
|
|
@@ -875,6 +877,10 @@ Spree::Core::Engine.add_routes do
|
|
|
875
877
|
patch 'auth/password_resets/:id', to: 'password_resets#update'
|
|
876
878
|
|
|
877
879
|
get 'me', to: 'me#show'
|
|
880
|
+
# Self-service edits to the signed-in person's own account — their
|
|
881
|
+
# name, photo and panel language. Distinct from `profile`, which is
|
|
882
|
+
# the seller business they act for.
|
|
883
|
+
patch 'me', to: 'me#update'
|
|
878
884
|
|
|
879
885
|
# Singular: the seller in play is always `current_seller`.
|
|
880
886
|
resource :profile, only: [:show, :update], controller: 'profile'
|
|
@@ -896,6 +902,7 @@ Spree::Core::Engine.add_routes do
|
|
|
896
902
|
member do
|
|
897
903
|
patch :resend
|
|
898
904
|
end
|
|
905
|
+
resource :acceptance_link, only: [:show], controller: 'invitations/acceptance_links'
|
|
899
906
|
end
|
|
900
907
|
|
|
901
908
|
resources :products, only: [:index, :show, :create, :update, :destroy] do
|
|
@@ -187,7 +187,9 @@ module Spree
|
|
|
187
187
|
seller_profile_serializer: 'Spree::Api::V3::Seller::ProfileSerializer',
|
|
188
188
|
seller_policy_serializer: 'Spree::Api::V3::Seller::PolicySerializer',
|
|
189
189
|
seller_team_member_serializer: 'Spree::Api::V3::Seller::TeamMemberSerializer',
|
|
190
|
+
seller_account_serializer: 'Spree::Api::V3::Seller::AccountSerializer',
|
|
190
191
|
seller_invitation_serializer: 'Spree::Api::V3::Seller::InvitationSerializer',
|
|
192
|
+
seller_invitation_acceptance_link_serializer: 'Spree::Api::V3::Seller::InvitationAcceptanceLinkSerializer',
|
|
191
193
|
seller_product_serializer: 'Spree::Api::V3::Seller::ProductSerializer',
|
|
192
194
|
seller_product_type_serializer: 'Spree::Api::V3::Seller::ProductTypeSerializer',
|
|
193
195
|
seller_delivery_profile_serializer: 'Spree::Api::V3::Seller::DeliveryProfileSerializer',
|
|
@@ -267,6 +269,7 @@ module Spree
|
|
|
267
269
|
admin_webhook_endpoint_serializer: 'Spree::Api::V3::Admin::WebhookEndpointSerializer',
|
|
268
270
|
admin_webhook_delivery_serializer: 'Spree::Api::V3::Admin::WebhookDeliverySerializer',
|
|
269
271
|
admin_invitation_serializer: 'Spree::Api::V3::Admin::InvitationSerializer',
|
|
272
|
+
admin_invitation_acceptance_link_serializer: 'Spree::Api::V3::Admin::InvitationAcceptanceLinkSerializer',
|
|
270
273
|
admin_role_serializer: 'Spree::Api::V3::Admin::RoleSerializer',
|
|
271
274
|
admin_permission_serializer: 'Spree::Api::V3::Admin::PermissionSerializer',
|
|
272
275
|
admin_export_serializer: 'Spree::Api::V3::Admin::ExportSerializer',
|
|
@@ -250,8 +250,8 @@ module Spree
|
|
|
250
250
|
#
|
|
251
251
|
# The seller branch has no API-key credential, so its AuthResponse is
|
|
252
252
|
# neither the store's nor the admin's: signing in returns the JWT, the
|
|
253
|
-
#
|
|
254
|
-
#
|
|
253
|
+
# person who signed in, and the sellers they may act for — the panel
|
|
254
|
+
# cannot make another request until it has picked one.
|
|
255
255
|
def seller_schemas
|
|
256
256
|
schemas = common_schemas
|
|
257
257
|
|
|
@@ -259,7 +259,10 @@ module Spree
|
|
|
259
259
|
type: :object,
|
|
260
260
|
properties: {
|
|
261
261
|
token: { type: :string, description: 'JWT access token, `seller_api` audience' },
|
|
262
|
-
|
|
262
|
+
# `Account`, not `TeamMember`: the panel adopts the signed-in
|
|
263
|
+
# person's saved language from this payload, which is what
|
|
264
|
+
# carries the choice to a second browser.
|
|
265
|
+
user: { '$ref' => '#/components/schemas/Account' },
|
|
263
266
|
sellers: {
|
|
264
267
|
type: :array,
|
|
265
268
|
description: 'The sellers this user may act for. Pick one and send its `id` as `X-Spree-Seller-Id` on every subsequent request.',
|
|
@@ -309,7 +312,10 @@ module Spree
|
|
|
309
312
|
type: :object,
|
|
310
313
|
description: 'The signed-in user, the sellers they may act for, and what they may do on the selected one',
|
|
311
314
|
properties: {
|
|
312
|
-
|
|
315
|
+
# `Account`, not `TeamMember`: the person reading their own
|
|
316
|
+
# record also sees the panel language they chose, which the
|
|
317
|
+
# team list does not publish about a colleague.
|
|
318
|
+
user: { '$ref' => '#/components/schemas/Account' },
|
|
313
319
|
sellers: { type: :array, items: { '$ref' => '#/components/schemas/SellerMeSummary' } },
|
|
314
320
|
permissions: { type: :array, items: { '$ref' => '#/components/schemas/PermissionRule' } },
|
|
315
321
|
permission_keys: {
|