@spree/docs 0.1.176 → 0.1.178
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.
- package/dist/api-reference/store.yaml +48 -48
- package/dist/developer/cli/quickstart.md +1 -1
- package/dist/developer/contributing/creating-an-extension.md +2 -2
- package/dist/developer/core-concepts/addresses.md +3 -3
- package/dist/developer/core-concepts/architecture.md +4 -4
- package/dist/developer/core-concepts/calculators.md +2 -2
- package/dist/developer/core-concepts/carts.md +207 -0
- package/dist/developer/core-concepts/channels.md +3 -3
- package/dist/developer/core-concepts/customers.md +1 -1
- package/dist/developer/core-concepts/events.md +1 -1
- package/dist/developer/core-concepts/fulfillments.md +278 -0
- package/dist/developer/core-concepts/imports-exports.md +6 -18
- package/dist/developer/core-concepts/inventory.md +3 -3
- package/dist/developer/core-concepts/media.md +1 -1
- package/dist/developer/core-concepts/metafields.md +1 -1
- package/dist/developer/core-concepts/orders.md +92 -339
- package/dist/developer/core-concepts/payments.md +1 -1
- package/dist/developer/core-concepts/promotions.md +68 -195
- package/dist/developer/core-concepts/returns-exchanges-claims.md +173 -0
- package/dist/developer/core-concepts/store-credits-gift-cards.md +16 -18
- package/dist/developer/core-concepts/stores.md +1 -1
- package/dist/developer/core-concepts/taxes-discounts-fees.md +199 -0
- package/dist/developer/core-concepts/taxes.md +3 -3
- package/dist/developer/create-spree-app/quickstart.md +1 -1
- package/dist/developer/customization/api.md +36 -11
- package/dist/developer/customization/configuration.md +207 -37
- package/dist/developer/customization/decorators.md +8 -8
- package/dist/developer/customization/permissions.md +34 -229
- package/dist/developer/customization/quickstart.md +159 -108
- package/dist/developer/customization/validations.md +1 -1
- package/dist/developer/dashboard/overview.md +1 -1
- package/dist/developer/how-to/build-a-b2b-store.md +21 -0
- package/dist/developer/how-to/build-a-marketplace.md +25 -0
- package/dist/developer/how-to/custom-api-authentication.md +1 -1
- package/dist/developer/how-to/custom-delivery-rate-provider.md +242 -0
- package/dist/developer/how-to/custom-document-numbers.md +154 -0
- package/dist/developer/how-to/custom-order-routing.md +1 -1
- package/dist/developer/how-to/custom-payment-method.md +1 -1
- package/dist/developer/how-to/custom-promotion.md +76 -115
- package/dist/developer/how-to/custom-report.md +2 -2
- package/dist/developer/how-to/custom-stock-splitter.md +5 -5
- package/dist/developer/how-to/sell-digital-products.md +20 -0
- package/dist/developer/multi-tenant/quickstart.md +1 -1
- package/dist/developer/providers/dam.md +14 -0
- package/dist/developer/providers/erp.md +31 -0
- package/dist/developer/providers/fulfillment.md +25 -0
- package/dist/developer/{deployment/telemetry.md → providers/observability.md} +1 -1
- package/dist/developer/providers/overview.md +44 -0
- package/dist/developer/providers/pim.md +25 -0
- package/dist/developer/providers/sso.md +20 -0
- package/dist/developer/sdk/admin/extending.md +1 -1
- package/dist/developer/sdk/admin/quickstart.md +1 -1
- package/dist/developer/sdk/admin/resources.md +1 -1
- package/dist/developer/sdk/extending.md +1 -1
- package/dist/developer/tutorial/admin-api.md +13 -0
- package/dist/developer/tutorial/dashboard-plugin.md +14 -0
- package/dist/developer/tutorial/events.md +7 -161
- package/dist/developer/tutorial/introduction.md +15 -35
- package/dist/developer/tutorial/model.md +7 -98
- package/dist/developer/tutorial/store-api.md +13 -0
- package/dist/developer/tutorial/storefront.md +12 -0
- package/dist/developer/tutorial/testing.md +7 -711
- package/dist/developer/upgrades/5.6-to-6.0.md +2 -2
- package/package.json +1 -1
- package/dist/developer/admin/admin.md +0 -214
- package/dist/developer/admin/authentication.md +0 -59
- package/dist/developer/admin/components.md +0 -711
- package/dist/developer/admin/custom-css.md +0 -256
- package/dist/developer/admin/custom-javascript.md +0 -116
- package/dist/developer/admin/extending-ui.md +0 -1839
- package/dist/developer/admin/form-builder.md +0 -444
- package/dist/developer/admin/helper-methods.md +0 -531
- package/dist/developer/admin/navigation.md +0 -805
- package/dist/developer/admin/tables.md +0 -490
- package/dist/developer/advanced/adding_spree_to_rails_app.md +0 -92
- package/dist/developer/core-concepts/adjustments.md +0 -113
- package/dist/developer/core-concepts/reports.md +0 -208
- package/dist/developer/core-concepts/shipments.md +0 -307
- package/dist/developer/core-concepts/users.md +0 -303
- package/dist/developer/customization/authentication.md +0 -100
- package/dist/developer/customization/checkout.md +0 -202
- package/dist/developer/customization/emails.md +0 -18
- package/dist/developer/customization/routes.md +0 -24
- package/dist/developer/multi-vendor/installation.md +0 -61
- package/dist/developer/multi-vendor/quickstart.md +0 -17
- package/dist/developer/tutorial/admin.md +0 -206
- package/dist/developer/tutorial/api.md +0 -606
- package/dist/developer/tutorial/extending-models.md +0 -393
- package/dist/developer/tutorial/sdk.md +0 -170
- package/dist/developer/upgrades/2.0-to-2.1.md +0 -46
- package/dist/developer/upgrades/2.1-to-2.2.md +0 -59
- package/dist/developer/upgrades/2.2-to-2.3.md +0 -44
- package/dist/developer/upgrades/2.3-to-2.4.md +0 -42
- package/dist/developer/upgrades/3.0-to-3.1.md +0 -47
- package/dist/developer/upgrades/3.1-to-3.2.md +0 -34
- package/dist/developer/upgrades/3.2-to-3.3.md +0 -70
- package/dist/developer/upgrades/3.3-to-3.4.md +0 -36
- package/dist/developer/upgrades/3.4-to-3.5.md +0 -44
- package/dist/developer/upgrades/3.5-to-3.6.md +0 -40
- package/dist/developer/upgrades/3.6-to-3.7.md +0 -62
- package/dist/developer/upgrades/3.7-to-4.0.md +0 -152
- package/dist/developer/upgrades/4.0-to-4.1.md +0 -92
- package/dist/developer/upgrades/4.1-to-4.2.md +0 -109
- package/dist/developer/upgrades/4.10-to-5.0.md +0 -131
- package/dist/developer/upgrades/4.2-to-4.3.md +0 -100
- package/dist/developer/upgrades/4.3-to-4.4.md +0 -125
- package/dist/developer/upgrades/4.4-to-4.5.md +0 -94
- package/dist/developer/upgrades/4.5-to-4.6.md +0 -119
- package/dist/developer/upgrades/4.6-to-4.7.md +0 -39
- package/dist/developer/upgrades/4.8-to-4.9.md +0 -24
- package/dist/developer/upgrades/4.9-to-4.10.md +0 -24
- package/dist/developer/upgrades/4.x-to-4.8.md +0 -52
- package/dist/developer/upgrades/5.0-to-5.1.md +0 -28
- package/dist/developer/upgrades/5.1-to-5.2.md +0 -131
- package/dist/developer/upgrades/5.2-to-5.3.md +0 -338
- package/dist/developer/upgrades/5.3-to-5.4.md +0 -277
- package/dist/developer/upgrades/5.4-to-5.5.md +0 -301
- package/dist/developer/upgrades/5.5-to-5.6.md +0 -207
|
@@ -1,215 +1,242 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Quickstart
|
|
3
3
|
og:title: Spree Customization Quickstart
|
|
4
|
-
description: Recommended ways to customize Spree
|
|
4
|
+
description: Recommended ways to customize the Spree 6 backend — configuration, workflow hooks, events, checkout steps, providers, dependencies, and decorators as a last resort.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Spree is
|
|
7
|
+
Spree is designed to be customized without forking it. This guide presents the options **in order of recommendation** — start at the top and only move down when a simpler option doesn't fit.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
> **NOTE:** Business logic is extended through **workflow hooks** rather than by replacing classes wholesale, and the admin is a React application with its own extension points rather than a Rails engine extended through partials.
|
|
10
|
+
|
|
11
|
+
## Quick reference
|
|
10
12
|
|
|
11
13
|
| What you want to do | Recommended approach |
|
|
12
|
-
|
|
13
|
-
| Change store settings (currency,
|
|
14
|
+
|---|---|
|
|
15
|
+
| Change store settings (currency, markets, languages) | [Store settings](#store-settings) |
|
|
14
16
|
| Tweak Spree behavior globally | [Configuration](#configuration) |
|
|
15
|
-
|
|
|
17
|
+
| Run your own logic inside checkout, cancellation, refunds | [Workflow hooks](#workflow-hooks) |
|
|
18
|
+
| Block an operation from happening | [Workflow hooks](#workflow-hooks) — `validate` |
|
|
19
|
+
| React after something happened (sync, notifications) | [Events & subscribers](#events-and-subscribers) |
|
|
20
|
+
| Add or reorder checkout steps | [Checkout registry](#checkout-steps) |
|
|
21
|
+
| Swap tax, delivery rate, search or fulfillment behavior | [Providers](#providers) |
|
|
22
|
+
| Add searchable/filterable fields | [Search & filtering](#search-and-filtering) |
|
|
23
|
+
| Use your own user model or identity provider | [Authentication](#authentication) |
|
|
16
24
|
| Notify external services | [Webhooks](#webhooks) |
|
|
17
|
-
|
|
|
18
|
-
| Add admin menu items | [Admin Navigation](#admin-extensions) |
|
|
19
|
-
| Add sections to admin forms | [Admin Partials](#admin-extensions) |
|
|
20
|
-
| Add searchable/filterable fields | [Ransack Configuration](#search-and-filtering) |
|
|
25
|
+
| Replace a whole workflow or service | [Dependencies](#dependencies) |
|
|
21
26
|
| Add associations/validations to models | [Decorators](#decorators) (last resort) |
|
|
22
27
|
|
|
23
|
-
**
|
|
24
|
-
|
|
25
|
-
There's a lot of Store settings you can change in the admin panel without touching the code.
|
|
28
|
+
> **INFO:** **Customizing the admin?** This page covers the backend — models, API and business logic. The Spree 6 admin is a separate React application with its own extension points. See [Dashboard Customization](../dashboard/customization/quickstart.md).
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
<img src="/images/spree_admin_store_settings.png" alt="Spree Admin Store Settings" />
|
|
30
|
+
**Best for:** currency, markets, delivery zones, languages, and other business settings.
|
|
30
31
|
|
|
32
|
+
Most day-to-day configuration is data, not code. Change it in the dashboard under **Settings** — no deploy required.
|
|
31
33
|
<details>
|
|
32
34
|
<summary>Configuration</summary>
|
|
33
35
|
|
|
34
|
-
**Best for:**
|
|
35
|
-
|
|
36
|
-
Global application configuration allows you to customize various aspects of Spree:
|
|
36
|
+
**Best for:** tweaking Spree's behavior globally.
|
|
37
37
|
|
|
38
38
|
```ruby config/initializers/spree.rb
|
|
39
39
|
Spree.config do |config|
|
|
40
|
-
config.
|
|
41
|
-
config.products_per_page = 20
|
|
40
|
+
config.minimum_password_length = 10
|
|
42
41
|
end
|
|
43
42
|
```
|
|
44
43
|
|
|
45
|
-
|
|
44
|
+
See [Configuration](configuration.md).
|
|
46
45
|
|
|
47
46
|
</details>
|
|
48
47
|
|
|
49
|
-
|
|
50
48
|
<details>
|
|
51
|
-
<summary>
|
|
49
|
+
<summary>Workflow hooks</summary>
|
|
52
50
|
|
|
53
|
-
**Best for:**
|
|
51
|
+
**Best for:** running your own logic *inside* a core flow — checkout completion, order cancellation, refunds, fulfillment creation.
|
|
54
52
|
|
|
55
|
-
> **INFO:**
|
|
53
|
+
> **INFO:** Hooks are the **headline extension point in Spree 6**. Before them, customizing a flow meant replacing the entire class and keeping your copy in sync with core forever.
|
|
56
54
|
|
|
57
|
-
|
|
55
|
+
Register a handler against a hook key — `<workflow key>.<hook name>`:
|
|
58
56
|
|
|
59
|
-
```ruby
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
```ruby config/initializers/spree.rb
|
|
58
|
+
Spree.hooks.register('carts.complete.validate') do |flow|
|
|
59
|
+
flow.reject!('We cannot deliver to this region') unless deliverable?(flow.cart)
|
|
60
|
+
end
|
|
61
|
+
```
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
order = Spree::Order.find_by_prefix_id(event.payload['id'])
|
|
65
|
-
return unless order
|
|
63
|
+
Pass a class instead of a block for anything longer than a line:
|
|
66
64
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
end
|
|
70
|
-
end
|
|
65
|
+
```ruby
|
|
66
|
+
Spree.hooks.register('carts.complete.after_finalize', 'MyApp::PushOrderToERP')
|
|
71
67
|
```
|
|
72
68
|
|
|
73
|
-
|
|
74
|
-
- Loose coupling - your code doesn't depend on Spree internals
|
|
75
|
-
- Async by default - keeps requests fast
|
|
76
|
-
- Easier testing and upgrades
|
|
69
|
+
There are three families of hook:
|
|
77
70
|
|
|
78
|
-
|
|
71
|
+
| Family | Naming | What it can do |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| **validate** | `validate` | Veto the operation with `flow.reject!(message)` |
|
|
74
|
+
| **lifecycle** | past tense — `after_finalize`, `after_cancel` | React to what happened; read-only |
|
|
75
|
+
| **context** | `set_*_context`, `get_provider_data` | Return a hash that gets merged into the flow's data |
|
|
79
76
|
|
|
80
|
-
|
|
77
|
+
Hook keys are validated after boot, so a typo fails startup rather than silently never running.
|
|
81
78
|
|
|
79
|
+
See [Services & Workflows](workflows.md) for the full list of flows and their hooks.
|
|
80
|
+
|
|
81
|
+
</details>
|
|
82
82
|
|
|
83
83
|
<details>
|
|
84
|
-
<summary>
|
|
84
|
+
<summary>Events and subscribers</summary>
|
|
85
|
+
|
|
86
|
+
**Best for:** reacting *after* something happened — syncing to external systems, notifications, audit logging.
|
|
85
87
|
|
|
86
|
-
|
|
88
|
+
```ruby app/subscribers/spree/order_placed_subscriber.rb
|
|
89
|
+
module Spree
|
|
90
|
+
class OrderPlacedSubscriber < Spree::Subscriber
|
|
91
|
+
subscribes_to 'order.placed'
|
|
87
92
|
|
|
88
|
-
|
|
93
|
+
def handle(event)
|
|
94
|
+
order = Spree::Order.find_by_prefix_id(event.payload['id'])
|
|
95
|
+
return unless order
|
|
89
96
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
97
|
+
MyApp::ERP.push(order)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
```
|
|
93
102
|
|
|
94
|
-
|
|
103
|
+
**Events or hooks?** A hook runs *inside* the flow and can influence or block it. An event fires *after* the fact and cannot. Reach for an event unless you need to change the outcome.
|
|
95
104
|
|
|
96
|
-
|
|
105
|
+
See [Events](../core-concepts/events.md).
|
|
97
106
|
|
|
98
107
|
</details>
|
|
99
108
|
|
|
100
|
-
|
|
101
109
|
<details>
|
|
102
|
-
<summary>
|
|
110
|
+
<summary>Checkout steps</summary>
|
|
103
111
|
|
|
104
|
-
**Best for:**
|
|
112
|
+
**Best for:** adding, removing or reordering checkout steps.
|
|
105
113
|
|
|
106
|
-
Spree
|
|
114
|
+
Spree 6 has no checkout state machine. A cart reports what it still needs, and you can add to that list:
|
|
107
115
|
|
|
108
116
|
```ruby config/initializers/spree.rb
|
|
109
|
-
Spree::
|
|
110
|
-
|
|
117
|
+
Spree::Checkout::Registry.register_step(
|
|
118
|
+
name: :loyalty,
|
|
119
|
+
before: :payment,
|
|
120
|
+
satisfied: ->(cart) { cart.metadata['loyalty_number'].present? },
|
|
121
|
+
requirements: ->(cart) {
|
|
122
|
+
[{ step: 'loyalty', field: 'loyalty_number', message: 'Loyalty number is required' }]
|
|
123
|
+
}
|
|
124
|
+
)
|
|
111
125
|
```
|
|
112
126
|
|
|
113
|
-
|
|
127
|
+
Or attach a requirement to an existing step:
|
|
114
128
|
|
|
115
|
-
|
|
129
|
+
```ruby
|
|
130
|
+
Spree::Checkout::Registry.add_requirement(
|
|
131
|
+
step: :payment,
|
|
132
|
+
field: :po_number,
|
|
133
|
+
message: 'PO number is required',
|
|
134
|
+
satisfied: ->(cart) { cart.metadata['po_number'].present? }
|
|
135
|
+
)
|
|
136
|
+
```
|
|
116
137
|
|
|
117
|
-
|
|
138
|
+
Registered requirements appear in the Cart API's `requirements` array, so your storefront renders them without duplicating any rules.
|
|
139
|
+
|
|
140
|
+
See [Carts](../core-concepts/carts.md#checkout-requirements).
|
|
118
141
|
|
|
142
|
+
</details>
|
|
119
143
|
|
|
120
144
|
<details>
|
|
121
|
-
<summary>
|
|
145
|
+
<summary>Providers</summary>
|
|
122
146
|
|
|
123
|
-
**Best for:**
|
|
147
|
+
**Best for:** swapping a whole area of behavior for your own implementation.
|
|
124
148
|
|
|
125
|
-
Spree
|
|
149
|
+
Spree 6 exposes pluggable providers for the domains that vary most between businesses:
|
|
126
150
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
position: 35
|
|
135
|
-
end
|
|
136
|
-
```
|
|
151
|
+
| Provider | Controls |
|
|
152
|
+
|---|---|
|
|
153
|
+
| Tax provider | How tax is calculated, per market |
|
|
154
|
+
| Delivery rate provider | How delivery is priced — flat rates or live carrier rates |
|
|
155
|
+
| Fulfillment provider | How a delivery type behaves — shipping, digital, pickup |
|
|
156
|
+
| Search provider | Database or Meilisearch |
|
|
157
|
+
| Payout provider | Where marketplace payouts go |
|
|
137
158
|
|
|
138
|
-
|
|
139
|
-
```ruby config/initializers/spree.rb
|
|
140
|
-
Spree.admin.partials.product_form << 'spree/admin/products/erp_section'
|
|
141
|
-
```
|
|
159
|
+
Each is a class you register and select on the relevant record, so no conditional code lands in core.
|
|
142
160
|
|
|
143
|
-
|
|
144
|
-
- [Admin Navigation](../admin/navigation.md) - For adding menu items
|
|
145
|
-
- [Admin Partials](../admin/extending-ui.md) - For extending UI
|
|
146
|
-
- [Admin Tables](../admin/tables.md) - For customizing list views
|
|
161
|
+
See [Fulfillments](../core-concepts/fulfillments.md#delivery-types) and [Taxes](../core-concepts/taxes.md).
|
|
147
162
|
|
|
148
163
|
</details>
|
|
149
164
|
|
|
150
|
-
|
|
151
165
|
<details>
|
|
152
|
-
<summary>Search and
|
|
166
|
+
<summary>Search and filtering</summary>
|
|
153
167
|
|
|
154
|
-
**Best for:**
|
|
155
|
-
|
|
156
|
-
Instead of decorating models to add `ransackable_attributes`, use the Ransack configuration API:
|
|
168
|
+
**Best for:** making custom fields searchable and sortable in the dashboard and API.
|
|
157
169
|
|
|
158
170
|
```ruby config/initializers/spree.rb
|
|
159
|
-
Spree.ransack.add_attribute
|
|
160
|
-
Spree.ransack.add_association
|
|
171
|
+
Spree.ransack.add_attribute(Spree::Product, :erp_id)
|
|
172
|
+
Spree.ransack.add_association(Spree::Product, :brand)
|
|
173
|
+
Spree.ransack.add_scope(Spree::Product, :featured)
|
|
161
174
|
```
|
|
162
175
|
|
|
163
|
-
|
|
176
|
+
See [Search & Filtering](../core-concepts/search-filtering.md).
|
|
164
177
|
|
|
165
178
|
</details>
|
|
166
179
|
|
|
167
|
-
|
|
168
180
|
<details>
|
|
169
181
|
<summary>Authentication</summary>
|
|
170
182
|
|
|
171
|
-
**Best for:**
|
|
183
|
+
**Best for:** using your own user model or identity provider.
|
|
172
184
|
|
|
173
|
-
Spree
|
|
185
|
+
Spree 6 owns its authentication stack rather than depending on Devise, and separates the customer identity from the staff identity. Point Spree at your own classes with `Spree.user_class` and `Spree.admin_user_class`.
|
|
174
186
|
|
|
175
|
-
|
|
187
|
+
See [Authentication](../providers/sso.md).
|
|
176
188
|
|
|
177
189
|
</details>
|
|
178
190
|
|
|
179
|
-
|
|
180
191
|
<details>
|
|
181
|
-
<summary>
|
|
192
|
+
<summary>Webhooks</summary>
|
|
182
193
|
|
|
183
|
-
**Best for:**
|
|
194
|
+
**Best for:** notifying external services — ERPs, CRMs, fulfillment systems — without writing Ruby.
|
|
184
195
|
|
|
185
|
-
|
|
196
|
+
Configure them in the dashboard under **Settings → Webhooks**, or through the Admin API.
|
|
186
197
|
|
|
187
|
-
|
|
198
|
+
See [Webhooks](../core-concepts/webhooks.md).
|
|
188
199
|
|
|
189
200
|
</details>
|
|
190
201
|
|
|
202
|
+
<details>
|
|
203
|
+
<summary>Dependencies</summary>
|
|
204
|
+
|
|
205
|
+
**Best for:** replacing an entire workflow or service with your own class.
|
|
206
|
+
|
|
207
|
+
```ruby config/initializers/spree.rb
|
|
208
|
+
Spree::Dependencies.cart_add_item_workflow = 'MyApp::Carts::AddItem'
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
> **WARNING:** Seam names end in `_workflow` in Spree 6. The old `*_service` names still resolve for one release with a warning, but **writes to them are ignored** — a class written against the old service contract isn't interchangeable with a workflow. Update the key when you upgrade.
|
|
212
|
+
|
|
213
|
+
Prefer a hook when you only need to add behavior. Replace the class only when you need to change what the flow fundamentally does.
|
|
214
|
+
|
|
215
|
+
See [Dependencies](dependencies.md).
|
|
216
|
+
|
|
217
|
+
</details>
|
|
191
218
|
|
|
192
219
|
<details>
|
|
193
220
|
<summary>Decorators</summary>
|
|
194
221
|
|
|
195
|
-
**Best for:**
|
|
222
|
+
**Best for:** adding associations, validations and scopes to Spree models. Use as a last resort.
|
|
196
223
|
|
|
197
|
-
> **WARNING:** Decorators
|
|
224
|
+
> **WARNING:** Decorators couple your code to Spree internals and are the most common cause of painful upgrades.
|
|
198
225
|
>
|
|
199
|
-
> **Do
|
|
200
|
-
> -
|
|
201
|
-
> -
|
|
202
|
-
> -
|
|
203
|
-
> -
|
|
226
|
+
> **Do not use decorators for:**
|
|
227
|
+
> - Logic inside a core flow → use [workflow hooks](#workflow-hooks)
|
|
228
|
+
> - After-save callbacks → use [events](#events-and-subscribers)
|
|
229
|
+
> - External service sync → use [webhooks](#webhooks)
|
|
230
|
+
> - Replacing a service → use [dependencies](#dependencies)
|
|
231
|
+
> - Admin UI changes → use [dashboard customization](../dashboard/customization/quickstart.md)
|
|
204
232
|
|
|
205
|
-
|
|
233
|
+
They remain appropriate for structural additions:
|
|
206
234
|
|
|
207
235
|
```ruby app/models/spree/product_decorator.rb
|
|
208
236
|
module Spree
|
|
209
237
|
module ProductDecorator
|
|
210
238
|
def self.prepended(base)
|
|
211
239
|
base.belongs_to :brand, class_name: 'MyApp::Brand', optional: true
|
|
212
|
-
base.validates :external_id, presence: true
|
|
213
240
|
base.scope :featured, -> { where(featured: true) }
|
|
214
241
|
end
|
|
215
242
|
|
|
@@ -222,6 +249,30 @@ Spree is a flexible platform allowing you to customize every part of it to suit
|
|
|
222
249
|
end
|
|
223
250
|
```
|
|
224
251
|
|
|
225
|
-
|
|
252
|
+
See [Decorators](decorators.md).
|
|
226
253
|
|
|
227
254
|
</details>
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
## Choosing between hooks, events and dependencies
|
|
258
|
+
|
|
259
|
+
These three overlap, and picking the wrong one is the most common source of upgrade pain:
|
|
260
|
+
|
|
261
|
+
**Step 1: Do you need to block or change the outcome?**
|
|
262
|
+
|
|
263
|
+
Use a **workflow hook**. Only `validate` hooks can stop an operation, and only they run early enough to do so safely — before money moves.
|
|
264
|
+
|
|
265
|
+
**Step 2: Do you just need to know it happened?**
|
|
266
|
+
|
|
267
|
+
Use an **event subscriber**. It's decoupled, testable, and survives upgrades untouched.
|
|
268
|
+
|
|
269
|
+
**Step 3: Do you need the flow to do something fundamentally different?**
|
|
270
|
+
|
|
271
|
+
Use **dependencies** to replace the class — and accept that you now own keeping it current.
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
## Related
|
|
275
|
+
|
|
276
|
+
- [Services & Workflows](workflows.md) — the workflow model and every hook
|
|
277
|
+
- [Carts](../core-concepts/carts.md) — checkout requirements and completion
|
|
278
|
+
- [Dashboard Customization](../dashboard/customization/quickstart.md) — extending the admin
|
|
@@ -162,7 +162,7 @@ Spree::Checkout::Registry.add_requirement(
|
|
|
162
162
|
)
|
|
163
163
|
```
|
|
164
164
|
|
|
165
|
-
See the [Spree 6 quickstart](
|
|
165
|
+
See the [Spree 6 quickstart](quickstart.md) for the full registry API.
|
|
166
166
|
|
|
167
167
|
## Custom field values
|
|
168
168
|
|
|
@@ -102,4 +102,4 @@ When in doubt, customize in-app first. The migration path to a plugin is mechani
|
|
|
102
102
|
- [Plugin scaffolding](plugins/scaffolding.md)
|
|
103
103
|
- [Slots catalog](slots-catalog.md) — every named slot the dashboard exposes
|
|
104
104
|
- [`@spree/dashboard-core` README](https://github.com/spree/spree/tree/main/packages/dashboard-core) — full extension API reference
|
|
105
|
-
- [Classic Admin extension model](
|
|
105
|
+
- [Classic Admin extension model](customization/quickstart.md) — for Spree 5.x
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Build a B2B Store
|
|
3
|
+
description: Wholesale pricing, customer groups, companies with tax exemption, and gated storefront access — assembling Spree's B2B capabilities into a working wholesale channel.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Spree's B2B capabilities are core features composed together rather than a separate product: price lists give buyers negotiated and volume pricing, customer groups segment who sees what, companies carry the legal and tax identity of the buyer, and channel access controls gate the storefront to signed-in buyers.
|
|
7
|
+
|
|
8
|
+
## What you will build
|
|
9
|
+
|
|
10
|
+
- **Wholesale pricing** — price lists scoped to customer groups, volume tiers, and regional pricing per market.
|
|
11
|
+
- **Companies** — buyer organizations with locations and contacts, tax identifiers validated per jurisdiction, and tax exemption certificates applied at checkout.
|
|
12
|
+
- **Gated access** — a storefront channel restricted to approved buyers, with guest checkout disabled.
|
|
13
|
+
- **B2B checkout** — orders carrying the buying company and location, priced and taxed accordingly.
|
|
14
|
+
|
|
15
|
+
## Outline
|
|
16
|
+
|
|
17
|
+
1. Model your buyer segments as customer groups
|
|
18
|
+
2. Build wholesale price lists and volume tiers
|
|
19
|
+
3. Register companies, locations and tax exemptions
|
|
20
|
+
4. Gate a sales channel for wholesale buyers
|
|
21
|
+
5. Take a wholesale order end to end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Build a Multi-Vendor Marketplace
|
|
3
|
+
description: Marketplace capabilities are part of Spree 6 core — sellers, order splitting, commissions and payouts, without a separate extension.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **NOTE:** Marketplace features are a headline capability of the Spree 6.0 release and are documented here as they land. This guide covers the open-source core.
|
|
7
|
+
|
|
8
|
+
Spree 6 brings multi-vendor marketplace support into the open-source core: sellers as first-class records, orders split per seller at completion, a commission engine, and a payout ledger with pluggable payout providers.
|
|
9
|
+
|
|
10
|
+
## What you will build
|
|
11
|
+
|
|
12
|
+
- **Sellers** — onboard sellers with an operator-configured requirements checklist, review submissions, and approve them for selling.
|
|
13
|
+
- **Order splitting** — a customer checks out once; completion produces per-seller orders grouped under one purchase.
|
|
14
|
+
- **Commissions** — the platform's cut computed per seller, with EU commission taxation handled.
|
|
15
|
+
- **Payouts** — a transfer and payout ledger, with Stripe Connect payouts (Express onboarding, on-fulfillment transfers) shipping in the open-source monorepo.
|
|
16
|
+
- **Seller operations** — sellers work through their own dedicated API surface, scoped so a seller only ever sees their own trade.
|
|
17
|
+
|
|
18
|
+
## Outline
|
|
19
|
+
|
|
20
|
+
1. Enable marketplace capabilities and configure the store
|
|
21
|
+
2. Define seller onboarding requirements
|
|
22
|
+
3. Invite and approve sellers
|
|
23
|
+
4. Assign catalog to sellers and take a multi-seller order through checkout
|
|
24
|
+
5. Configure commissions
|
|
25
|
+
6. Connect Stripe for payouts
|
|
@@ -378,4 +378,4 @@ end
|
|
|
378
378
|
- `Spree::Api::V3::Store::AuthController` — `spree/api/app/controllers/spree/api/v3/store/auth_controller.rb`
|
|
379
379
|
- `Spree::Api::V3::Admin::AuthController` — `spree/api/app/controllers/spree/api/v3/admin/auth_controller.rb`
|
|
380
380
|
- `Spree::Api::V3::JwtAuthentication` — `spree/api/app/controllers/concerns/spree/api/v3/jwt_authentication.rb`
|
|
381
|
-
- See also: [Staff & Roles](../core-concepts/staff-roles.md) for the admin login flow, [Customers](../core-concepts/customers.md) for storefront auth, and [Authentication](../
|
|
381
|
+
- See also: [Staff & Roles](../core-concepts/staff-roles.md) for the admin login flow, [Customers](../core-concepts/customers.md) for storefront auth, and [Authentication](../providers/sso.md) for `Spree.user_class` integration.
|