@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
|
@@ -879,8 +879,8 @@ paths:
|
|
|
879
879
|
example:
|
|
880
880
|
data:
|
|
881
881
|
- id: prod_UkLWZg9DAJ
|
|
882
|
-
name: Product
|
|
883
|
-
slug: product-
|
|
882
|
+
name: Product 1496979
|
|
883
|
+
slug: product-1496979
|
|
884
884
|
meta_title:
|
|
885
885
|
meta_description:
|
|
886
886
|
meta_keywords:
|
|
@@ -1054,8 +1054,8 @@ paths:
|
|
|
1054
1054
|
example:
|
|
1055
1055
|
data:
|
|
1056
1056
|
- id: prod_UkLWZg9DAJ
|
|
1057
|
-
name: Product
|
|
1058
|
-
slug: product-
|
|
1057
|
+
name: Product 1949085
|
|
1058
|
+
slug: product-1949085
|
|
1059
1059
|
meta_title:
|
|
1060
1060
|
meta_description:
|
|
1061
1061
|
meta_keywords:
|
|
@@ -1086,8 +1086,8 @@ paths:
|
|
|
1086
1086
|
original_price:
|
|
1087
1087
|
seller_id:
|
|
1088
1088
|
- id: prod_gbHJdmfrXB
|
|
1089
|
-
name: Product
|
|
1090
|
-
slug: product-
|
|
1089
|
+
name: Product 1958209
|
|
1090
|
+
slug: product-1958209
|
|
1091
1091
|
meta_title:
|
|
1092
1092
|
meta_description:
|
|
1093
1093
|
meta_keywords:
|
|
@@ -1215,8 +1215,8 @@ paths:
|
|
|
1215
1215
|
application/json:
|
|
1216
1216
|
example:
|
|
1217
1217
|
id: prod_UkLWZg9DAJ
|
|
1218
|
-
name: Product
|
|
1219
|
-
slug: product-
|
|
1218
|
+
name: Product 2226885
|
|
1219
|
+
slug: product-2226885
|
|
1220
1220
|
meta_title:
|
|
1221
1221
|
meta_description:
|
|
1222
1222
|
meta_keywords:
|
|
@@ -1565,8 +1565,8 @@ paths:
|
|
|
1565
1565
|
preorder_ships_at:
|
|
1566
1566
|
quantity: 1
|
|
1567
1567
|
currency: USD
|
|
1568
|
-
name: Product
|
|
1569
|
-
slug: product-
|
|
1568
|
+
name: Product 123715
|
|
1569
|
+
slug: product-123715
|
|
1570
1570
|
options_text: ''
|
|
1571
1571
|
price: '10.0'
|
|
1572
1572
|
display_price: "$10.00"
|
|
@@ -1674,8 +1674,8 @@ paths:
|
|
|
1674
1674
|
preorder_ships_at:
|
|
1675
1675
|
quantity: 1
|
|
1676
1676
|
currency: USD
|
|
1677
|
-
name: Product
|
|
1678
|
-
slug: product-
|
|
1677
|
+
name: Product 1242171
|
|
1678
|
+
slug: product-1242171
|
|
1679
1679
|
options_text: ''
|
|
1680
1680
|
price: '10.0'
|
|
1681
1681
|
display_price: "$10.00"
|
|
@@ -1969,7 +1969,7 @@ paths:
|
|
|
1969
1969
|
total_quantity: 0
|
|
1970
1970
|
warnings:
|
|
1971
1971
|
- code: line_item_removed
|
|
1972
|
-
message: Product
|
|
1972
|
+
message: Product 128307 was removed because it was sold out
|
|
1973
1973
|
line_item_id: li_UkLWZg9DAJ
|
|
1974
1974
|
variant_id: variant_UkLWZg9DAJ
|
|
1975
1975
|
coupon_code:
|
|
@@ -2177,8 +2177,8 @@ paths:
|
|
|
2177
2177
|
preorder_ships_at:
|
|
2178
2178
|
quantity: 1
|
|
2179
2179
|
currency: USD
|
|
2180
|
-
name: Product
|
|
2181
|
-
slug: product-
|
|
2180
|
+
name: Product 1293263
|
|
2181
|
+
slug: product-1293263
|
|
2182
2182
|
options_text: ''
|
|
2183
2183
|
price: '10.0'
|
|
2184
2184
|
display_price: "$10.00"
|
|
@@ -2453,8 +2453,8 @@ paths:
|
|
|
2453
2453
|
preorder_ships_at:
|
|
2454
2454
|
quantity: 1
|
|
2455
2455
|
currency: USD
|
|
2456
|
-
name: Product
|
|
2457
|
-
slug: product-
|
|
2456
|
+
name: Product 1318992
|
|
2457
|
+
slug: product-1318992
|
|
2458
2458
|
options_text: ''
|
|
2459
2459
|
price: '10.0'
|
|
2460
2460
|
display_price: "$10.00"
|
|
@@ -2657,8 +2657,8 @@ paths:
|
|
|
2657
2657
|
preorder_ships_at:
|
|
2658
2658
|
quantity: 1
|
|
2659
2659
|
currency: USD
|
|
2660
|
-
name: Product
|
|
2661
|
-
slug: product-
|
|
2660
|
+
name: Product 1344794
|
|
2661
|
+
slug: product-1344794
|
|
2662
2662
|
options_text: ''
|
|
2663
2663
|
price: '10.0'
|
|
2664
2664
|
display_price: "$10.00"
|
|
@@ -2986,8 +2986,8 @@ paths:
|
|
|
2986
2986
|
preorder_ships_at:
|
|
2987
2987
|
quantity: 1
|
|
2988
2988
|
currency: USD
|
|
2989
|
-
name: Product
|
|
2990
|
-
slug: product-
|
|
2989
|
+
name: Product 1604241
|
|
2990
|
+
slug: product-1604241
|
|
2991
2991
|
options_text: ''
|
|
2992
2992
|
price: '10.0'
|
|
2993
2993
|
display_price: "$10.00"
|
|
@@ -3175,8 +3175,8 @@ paths:
|
|
|
3175
3175
|
preorder_ships_at:
|
|
3176
3176
|
quantity: 1
|
|
3177
3177
|
currency: USD
|
|
3178
|
-
name: Product
|
|
3179
|
-
slug: product-
|
|
3178
|
+
name: Product 1623461
|
|
3179
|
+
slug: product-1623461
|
|
3180
3180
|
options_text: ''
|
|
3181
3181
|
price: '10.0'
|
|
3182
3182
|
display_price: "$10.00"
|
|
@@ -3347,8 +3347,8 @@ paths:
|
|
|
3347
3347
|
preorder_ships_at:
|
|
3348
3348
|
quantity: 1
|
|
3349
3349
|
currency: USD
|
|
3350
|
-
name: Product
|
|
3351
|
-
slug: product-
|
|
3350
|
+
name: Product 1648182
|
|
3351
|
+
slug: product-1648182
|
|
3352
3352
|
options_text: ''
|
|
3353
3353
|
price: '10.0'
|
|
3354
3354
|
display_price: "$10.00"
|
|
@@ -3633,8 +3633,8 @@ paths:
|
|
|
3633
3633
|
preorder_ships_at:
|
|
3634
3634
|
quantity: 1
|
|
3635
3635
|
currency: USD
|
|
3636
|
-
name: Product
|
|
3637
|
-
slug: product-
|
|
3636
|
+
name: Product 1665702
|
|
3637
|
+
slug: product-1665702
|
|
3638
3638
|
options_text: ''
|
|
3639
3639
|
price: '10.0'
|
|
3640
3640
|
display_price: "$10.00"
|
|
@@ -3877,8 +3877,8 @@ paths:
|
|
|
3877
3877
|
preorder_ships_at:
|
|
3878
3878
|
quantity: 1
|
|
3879
3879
|
currency: USD
|
|
3880
|
-
name: Product
|
|
3881
|
-
slug: product-
|
|
3880
|
+
name: Product 1709569
|
|
3881
|
+
slug: product-1709569
|
|
3882
3882
|
options_text: ''
|
|
3883
3883
|
price: '10.0'
|
|
3884
3884
|
display_price: "$10.00"
|
|
@@ -4021,10 +4021,10 @@ paths:
|
|
|
4021
4021
|
total_quantity: 2
|
|
4022
4022
|
warnings:
|
|
4023
4023
|
- code: delivery_unavailable
|
|
4024
|
-
message: Product
|
|
4024
|
+
message: Product 17363 cannot be delivered to the selected address
|
|
4025
4025
|
line_item_id: li_UkLWZg9DAJ
|
|
4026
4026
|
- code: delivery_unavailable
|
|
4027
|
-
message: Product
|
|
4027
|
+
message: Product 174298 cannot be delivered to the selected address
|
|
4028
4028
|
line_item_id: li_gbHJdmfrXB
|
|
4029
4029
|
coupon_code:
|
|
4030
4030
|
item_total: '29.99'
|
|
@@ -4078,8 +4078,8 @@ paths:
|
|
|
4078
4078
|
preorder_ships_at:
|
|
4079
4079
|
quantity: 1
|
|
4080
4080
|
currency: USD
|
|
4081
|
-
name: Product
|
|
4082
|
-
slug: product-
|
|
4081
|
+
name: Product 17363
|
|
4082
|
+
slug: product-17363
|
|
4083
4083
|
options_text: ''
|
|
4084
4084
|
price: '10.0'
|
|
4085
4085
|
display_price: "$10.00"
|
|
@@ -4109,8 +4109,8 @@ paths:
|
|
|
4109
4109
|
preorder_ships_at:
|
|
4110
4110
|
quantity: 1
|
|
4111
4111
|
currency: USD
|
|
4112
|
-
name: Product
|
|
4113
|
-
slug: product-
|
|
4112
|
+
name: Product 174298
|
|
4113
|
+
slug: product-174298
|
|
4114
4114
|
options_text: ''
|
|
4115
4115
|
price: '19.99'
|
|
4116
4116
|
display_price: "$19.99"
|
|
@@ -4324,8 +4324,8 @@ paths:
|
|
|
4324
4324
|
preorder_ships_at:
|
|
4325
4325
|
quantity: 1
|
|
4326
4326
|
currency: USD
|
|
4327
|
-
name: Product
|
|
4328
|
-
slug: product-
|
|
4327
|
+
name: Product 1809165
|
|
4328
|
+
slug: product-1809165
|
|
4329
4329
|
options_text: ''
|
|
4330
4330
|
price: '10.0'
|
|
4331
4331
|
display_price: "$10.00"
|
|
@@ -5116,8 +5116,8 @@ paths:
|
|
|
5116
5116
|
preorder_ships_at:
|
|
5117
5117
|
quantity: 1
|
|
5118
5118
|
currency: USD
|
|
5119
|
-
name: Product
|
|
5120
|
-
slug: product-
|
|
5119
|
+
name: Product 2429789
|
|
5120
|
+
slug: product-2429789
|
|
5121
5121
|
options_text: ''
|
|
5122
5122
|
price: '10.0'
|
|
5123
5123
|
display_price: "$10.00"
|
|
@@ -5324,8 +5324,8 @@ paths:
|
|
|
5324
5324
|
preorder_ships_at:
|
|
5325
5325
|
quantity: 1
|
|
5326
5326
|
currency: USD
|
|
5327
|
-
name: Product
|
|
5328
|
-
slug: product-
|
|
5327
|
+
name: Product 244179
|
|
5328
|
+
slug: product-244179
|
|
5329
5329
|
options_text: ''
|
|
5330
5330
|
price: '10.0'
|
|
5331
5331
|
display_price: "$10.00"
|
|
@@ -5485,8 +5485,8 @@ paths:
|
|
|
5485
5485
|
preorder_ships_at:
|
|
5486
5486
|
quantity: 1
|
|
5487
5487
|
currency: USD
|
|
5488
|
-
name: Product
|
|
5489
|
-
slug: product-
|
|
5488
|
+
name: Product 184496
|
|
5489
|
+
slug: product-184496
|
|
5490
5490
|
options_text: ''
|
|
5491
5491
|
price: '10.0'
|
|
5492
5492
|
display_price: "$10.00"
|
|
@@ -6575,8 +6575,8 @@ paths:
|
|
|
6575
6575
|
preorder_ships_at:
|
|
6576
6576
|
quantity: 1
|
|
6577
6577
|
currency: USD
|
|
6578
|
-
name: Product
|
|
6579
|
-
slug: product-
|
|
6578
|
+
name: Product 1505270
|
|
6579
|
+
slug: product-1505270
|
|
6580
6580
|
options_text: ''
|
|
6581
6581
|
price: '10.0'
|
|
6582
6582
|
display_price: "$10.00"
|
|
@@ -6875,8 +6875,8 @@ paths:
|
|
|
6875
6875
|
preorder_ships_at:
|
|
6876
6876
|
quantity: 1
|
|
6877
6877
|
currency: USD
|
|
6878
|
-
name: Product
|
|
6879
|
-
slug: product-
|
|
6878
|
+
name: Product 1525633
|
|
6879
|
+
slug: product-1525633
|
|
6880
6880
|
options_text: ''
|
|
6881
6881
|
price: '10.0'
|
|
6882
6882
|
display_price: "$10.00"
|
|
@@ -9203,7 +9203,7 @@ paths:
|
|
|
9203
9203
|
variant:
|
|
9204
9204
|
id: variant_gbHJdmfrXB
|
|
9205
9205
|
product_id: prod_gbHJdmfrXB
|
|
9206
|
-
sku: SKU-
|
|
9206
|
+
sku: SKU-298
|
|
9207
9207
|
options_text: ''
|
|
9208
9208
|
track_inventory: true
|
|
9209
9209
|
media_count: 0
|
|
@@ -237,8 +237,8 @@ While this tutorial uses decorators to extend Spree's core behavior, modern Spre
|
|
|
237
237
|
| React to model changes | [Events subscribers](../core-concepts/events.md) |
|
|
238
238
|
| External service integration | [Webhooks](../core-concepts/webhooks.md) |
|
|
239
239
|
| Replace core services | [Dependencies injection](../customization/dependencies.md) |
|
|
240
|
-
| Add admin UI elements | [Admin Partials](../
|
|
241
|
-
| Add admin menu items | [Admin Navigation](../
|
|
240
|
+
| Add admin UI elements | [Admin Partials](../dashboard/customization/quickstart.md) |
|
|
241
|
+
| Add admin menu items | [Admin Navigation](../dashboard/customization/navigation.md) |
|
|
242
242
|
|
|
243
243
|
For example, if your extension needs to sync data with an external service when products are updated, use an Events subscriber instead of a decorator callback:
|
|
244
244
|
|
|
@@ -243,7 +243,7 @@ For countries without predefined states, addresses accept a free-text `state_nam
|
|
|
243
243
|
|
|
244
244
|
## Zones
|
|
245
245
|
|
|
246
|
-
Zones group countries or states together for [tax](taxes.md) and [shipping](
|
|
246
|
+
Zones group countries or states together for [tax](taxes.md) and [shipping](fulfillments.md) rules. A zone is either **country-based** or **state-based**.
|
|
247
247
|
|
|
248
248
|
**Examples:**
|
|
249
249
|
- **EU VAT** (country zone) — Germany, France, Italy, Spain, ... → applies EU VAT rates
|
|
@@ -252,7 +252,7 @@ Zones group countries or states together for [tax](taxes.md) and [shipping](ship
|
|
|
252
252
|
|
|
253
253
|
When a customer enters their address at checkout, Spree matches it against zones to determine:
|
|
254
254
|
1. Which **tax rates** apply (see [Taxes](taxes.md))
|
|
255
|
-
2. Which **shipping methods** are available (see [Shipments](
|
|
255
|
+
2. Which **shipping methods** are available (see [Shipments](fulfillments.md))
|
|
256
256
|
|
|
257
257
|
Zones are configured in the admin dashboard — storefront developers don't interact with them directly via the API.
|
|
258
258
|
|
|
@@ -275,7 +275,7 @@ Here's how geography flows through a typical checkout:
|
|
|
275
275
|
|
|
276
276
|
- [Markets](markets.md) — Multi-region commerce with currency, locale, and country grouping
|
|
277
277
|
- [Taxes](taxes.md) — How zones and addresses affect taxation
|
|
278
|
-
- [Shipments](
|
|
278
|
+
- [Shipments](fulfillments.md) — How zones and addresses affect shipping availability
|
|
279
279
|
- [Orders](orders.md) — Order billing and shipping addresses
|
|
280
280
|
- [Account SDK guide](../sdk/store/account.md) — Managing the logged-in customer's address book with `client.customer.addresses`
|
|
281
281
|
- [Store API authentication](../../api-reference/store-api/authentication.md) — How to obtain and send the customer JWT (`Authorization: Bearer` header)
|
|
@@ -57,11 +57,11 @@ flowchart TB
|
|
|
57
57
|
|
|
58
58
|
2. **Shopping** — Customers add Variants to their cart, creating an [Order](orders.md) with Line Items
|
|
59
59
|
|
|
60
|
-
3. **Checkout** — The Order collects [Addresses](addresses.md), calculates [Shipping](
|
|
60
|
+
3. **Checkout** — The Order collects [Addresses](addresses.md), calculates [Shipping](fulfillments.md) options, and processes [Payments](payments.md)
|
|
61
61
|
|
|
62
|
-
4. **Fulfillment** — [Shipments](
|
|
62
|
+
4. **Fulfillment** — [Shipments](fulfillments.md) are created from Stock Locations, tracking individual [Inventory Units](inventory.md#inventory-units)
|
|
63
63
|
|
|
64
|
-
5. **Pricing & Adjustments** — [Taxes](taxes.md) and [Promotions](promotions.md) create [Adjustments](
|
|
64
|
+
5. **Pricing & Adjustments** — [Taxes](taxes.md) and [Promotions](promotions.md) create [Adjustments](taxes-discounts-fees.md) that modify order totals
|
|
65
65
|
|
|
66
66
|
## Core Model Relationships
|
|
67
67
|
|
|
@@ -172,5 +172,5 @@ Spree is distributed as a set of packages:
|
|
|
172
172
|
- [Products](products.md) — Product catalog and variants
|
|
173
173
|
- [Orders](orders.md) — Order lifecycle and state machine
|
|
174
174
|
- [Payments](payments.md) — Payment processing
|
|
175
|
-
- [Shipments](
|
|
175
|
+
- [Shipments](fulfillments.md) — Shipping and fulfillment
|
|
176
176
|
- [Customization Quickstart](../customization/quickstart.md) — How to extend Spree
|
|
@@ -45,7 +45,7 @@ erDiagram
|
|
|
45
45
|
**Key relationships:**
|
|
46
46
|
- **Calculator** computes amounts for various features
|
|
47
47
|
- Used by **[Tax Rates](taxes.md)** to calculate tax amounts
|
|
48
|
-
- Used by **[Shipping Methods](
|
|
48
|
+
- Used by **[Shipping Methods](fulfillments.md)** to calculate shipping costs
|
|
49
49
|
- Used by **[Promotion Actions](promotions.md)** to calculate discounts
|
|
50
50
|
- Calculators store [preferences (rates, percentages, etc.)](../customization/model-preferences.md) for their calculations
|
|
51
51
|
|
|
@@ -299,5 +299,5 @@ The module does not define `create_adjustment`, `update_adjustment`, or `compute
|
|
|
299
299
|
|
|
300
300
|
## Related Documentation
|
|
301
301
|
|
|
302
|
-
- [Adjustments](
|
|
302
|
+
- [Adjustments](taxes-discounts-fees.md) — the records calculators compute amounts for.
|
|
303
303
|
- [Dependencies](../customization/dependencies.md) — swap out calculators via the Dependencies system.
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Carts
|
|
3
|
+
description: How Spree models the shopping and checkout phase — a cart collects items and customer details, then completing it creates an order.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
A cart is everything that happens before a purchase is final: adding items, entering an address, choosing delivery, and paying. Completing a cart creates an [Order](orders.md) — a separate, permanent record.
|
|
9
|
+
|
|
10
|
+
The two are kept apart because they want opposite things. A cart changes constantly, tolerates half-finished states, and is often abandoned. An order is a financial record: it must not change quietly, and it has to keep saying what the customer actually agreed to pay.
|
|
11
|
+
|
|
12
|
+
```mermaid
|
|
13
|
+
erDiagram
|
|
14
|
+
Cart ||--o{ LineItem : "has many"
|
|
15
|
+
Cart ||--o{ Fulfillment : "has many"
|
|
16
|
+
Cart ||--o| Order : "completes into"
|
|
17
|
+
Cart }o--|| Customer : "belongs to"
|
|
18
|
+
|
|
19
|
+
Cart {
|
|
20
|
+
string token
|
|
21
|
+
string email
|
|
22
|
+
string currency
|
|
23
|
+
string total
|
|
24
|
+
datetime completed_at
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Order {
|
|
28
|
+
string number
|
|
29
|
+
string payment_status
|
|
30
|
+
string fulfillment_status
|
|
31
|
+
string total
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Cart attributes
|
|
36
|
+
|
|
37
|
+
| Attribute | Description |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `id` | Cart ID, e.g. `cart_86Rf07xd4z` |
|
|
40
|
+
| `token` | Guest cart token — save it so a guest can return to their cart |
|
|
41
|
+
| `email` | Customer's email address |
|
|
42
|
+
| `currency` | Cart currency, e.g. `USD` |
|
|
43
|
+
| `total_quantity` | Total number of items |
|
|
44
|
+
| `requirements` | What the cart still needs before it can be completed |
|
|
45
|
+
| `item_total` / `display_item_total` | Sum of line item prices |
|
|
46
|
+
| `delivery_total` / `display_delivery_total` | Delivery cost |
|
|
47
|
+
| `tax_total` / `display_tax_total` | Total tax |
|
|
48
|
+
| `discount_total` / `display_discount_total` | Total discount |
|
|
49
|
+
| `total` / `display_total` | Cart total |
|
|
50
|
+
| `amount_due` / `display_amount_due` | Still to pay after store credit and gift cards |
|
|
51
|
+
| `warnings` | Items removed or changed since the customer last looked |
|
|
52
|
+
| `completed_at` | Set once checkout succeeded |
|
|
53
|
+
|
|
54
|
+
Every amount comes in two forms: `total` is the raw value (`"135.60"`) and [`display_total` is formatted for the currency](../../api-reference/store-api/monetary-amounts.md) (`"$135.60"`). Render the `display_` one.
|
|
55
|
+
|
|
56
|
+
> **NOTE:** Money is sent as a **string**, not a number. JavaScript numbers can't represent every decimal exactly — `0.1 + 0.2` gives `0.30000000000000004` — which is not something you want inside a price. Let Spree do the arithmetic and render the formatted strings.
|
|
57
|
+
|
|
58
|
+
## Creating a cart and adding items
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
```typescript Store SDK
|
|
62
|
+
// Create a cart
|
|
63
|
+
const cart = await client.carts.create()
|
|
64
|
+
// cart.token => "abc123" (save this for guest checkout)
|
|
65
|
+
|
|
66
|
+
// Add an item
|
|
67
|
+
await client.carts.items.create(cart.id, {
|
|
68
|
+
variant_id: 'var_xxx',
|
|
69
|
+
quantity: 2,
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
// Update quantity
|
|
73
|
+
await client.carts.items.update(cart.id, 'li_xxx', { quantity: 3 })
|
|
74
|
+
|
|
75
|
+
// Remove an item
|
|
76
|
+
await client.carts.items.delete(cart.id, 'li_xxx')
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```bash cURL
|
|
80
|
+
# Create a cart
|
|
81
|
+
curl -X POST 'https://api.mystore.com/api/v3/store/carts' \
|
|
82
|
+
-H 'X-Spree-API-Key: pk_xxx'
|
|
83
|
+
|
|
84
|
+
# Add an item
|
|
85
|
+
curl -X POST 'https://api.mystore.com/api/v3/store/carts/cart_xxx/items' \
|
|
86
|
+
-H 'X-Spree-API-Key: pk_xxx' \
|
|
87
|
+
-H 'X-Spree-Token: abc123' \
|
|
88
|
+
-H 'Content-Type: application/json' \
|
|
89
|
+
-d '{ "variant_id": "var_xxx", "quantity": 2 }'
|
|
90
|
+
|
|
91
|
+
# Update quantity
|
|
92
|
+
curl -X PATCH 'https://api.mystore.com/api/v3/store/carts/cart_xxx/items/li_xxx' \
|
|
93
|
+
-H 'X-Spree-API-Key: pk_xxx' \
|
|
94
|
+
-H 'X-Spree-Token: abc123' \
|
|
95
|
+
-H 'Content-Type: application/json' \
|
|
96
|
+
-d '{ "quantity": 3 }'
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
Every change returns the whole cart with new totals, so you never need a second request to refresh the summary.
|
|
101
|
+
|
|
102
|
+
When a guest signs in, attach their cart to the account:
|
|
103
|
+
|
|
104
|
+
```typescript Store SDK
|
|
105
|
+
await client.carts.associate(cartId, { spreeToken: 'abc123' })
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Checkout requirements
|
|
109
|
+
|
|
110
|
+
A cart tells you what it still needs before it can be completed:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"requirements": [
|
|
115
|
+
{
|
|
116
|
+
"step": "address",
|
|
117
|
+
"field": "email",
|
|
118
|
+
"code": "email_required",
|
|
119
|
+
"message": "Email address is required"
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
An empty `requirements` array means the cart is ready.
|
|
126
|
+
|
|
127
|
+
This is what lets you design your own checkout. Spree tells you what's missing; you decide how and when to ask for it — one long page, a few steps, or whatever suits your storefront.
|
|
128
|
+
|
|
129
|
+
## Checkout
|
|
130
|
+
|
|
131
|
+
**Step 1: Add the customer's details**
|
|
132
|
+
|
|
133
|
+
```typescript Store SDK
|
|
134
|
+
await client.carts.update(cartId, {
|
|
135
|
+
email: 'john@example.com',
|
|
136
|
+
shipping_address: {
|
|
137
|
+
first_name: 'John', last_name: 'Doe',
|
|
138
|
+
address1: '123 Main St', city: 'Los Angeles',
|
|
139
|
+
country_code: 'US', state_abbr: 'CA', postal_code: '90001',
|
|
140
|
+
},
|
|
141
|
+
})
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Step 2: Choose delivery**
|
|
145
|
+
|
|
146
|
+
Each [fulfillment](fulfillments.md) offers delivery rates. Pick one per fulfillment.
|
|
147
|
+
|
|
148
|
+
```typescript Store SDK
|
|
149
|
+
const cart = await client.carts.get(cartId)
|
|
150
|
+
await client.carts.fulfillments.update(cartId, cart.fulfillments[0].id, {
|
|
151
|
+
selected_delivery_rate_id: 'rate_xxx',
|
|
152
|
+
})
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Step 3: Take payment**
|
|
156
|
+
|
|
157
|
+
For providers like Stripe, create a payment session and confirm it with their own SDK.
|
|
158
|
+
|
|
159
|
+
```typescript Store SDK
|
|
160
|
+
const session = await client.carts.paymentSessions.create(cartId, {
|
|
161
|
+
payment_method_id: 'pm_xxx',
|
|
162
|
+
})
|
|
163
|
+
// session.external_data.client_secret => use with Stripe.js
|
|
164
|
+
|
|
165
|
+
await client.carts.paymentSessions.complete(cartId, session.id)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Step 4: Complete the cart**
|
|
169
|
+
|
|
170
|
+
```typescript Store SDK
|
|
171
|
+
const order = await client.carts.complete(cartId)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
You get back an [Order](orders.md).
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
Discount codes, gift cards and store credit can be applied any time before completion:
|
|
178
|
+
|
|
179
|
+
```typescript Store SDK
|
|
180
|
+
await client.carts.discountCodes.apply(cartId, 'SUMMER20')
|
|
181
|
+
await client.carts.giftCards.apply(cartId, 'GIFT-XXXX')
|
|
182
|
+
await client.carts.storeCredits.apply(cartId)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## What completion guarantees
|
|
186
|
+
|
|
187
|
+
Completing a cart moves real money, so Spree is careful about it:
|
|
188
|
+
|
|
189
|
+
**Double submission is safe.** A customer double-clicking "Place order" gets the same order back rather than a second charge. This holds even when your app runs on several servers.
|
|
190
|
+
|
|
191
|
+
**An interrupted completion recovers.** If something dies after the customer was charged, trying again finishes the job instead of charging twice.
|
|
192
|
+
|
|
193
|
+
**Totals are worked out at the last moment.** The amount charged is calculated when the cart is completed, not taken from an earlier request — so a price or promotion that changed while the customer was reviewing can't lead to the wrong charge.
|
|
194
|
+
|
|
195
|
+
If a cart can't be completed you get told why — a payment failure, or unmet [requirements](#checkout-requirements) — and the cart is left alone so the customer can fix it and try again.
|
|
196
|
+
|
|
197
|
+
## Abandoned carts
|
|
198
|
+
|
|
199
|
+
Carts emit `cart.created`, `cart.updated` and `cart.deleted` [events](events.md), which also reach [webhooks](webhooks.md) — enough to drive abandonment email without polling for changes.
|
|
200
|
+
|
|
201
|
+
Completed carts are kept rather than deleted, and an order records which cart it came from, so you can measure conversion. Abandoned carts are cleared out on a schedule you control; carts with a payment in progress are never removed.
|
|
202
|
+
|
|
203
|
+
## Related
|
|
204
|
+
|
|
205
|
+
- [Orders](orders.md) — the record a cart becomes
|
|
206
|
+
- [Payments](payments.md) — payment methods and sessions
|
|
207
|
+
- [Fulfillments](fulfillments.md) — delivery options
|
|
@@ -22,7 +22,7 @@ Every store ships with one default channel named *Online Store*. You can add mor
|
|
|
22
22
|
| `default` | Exactly one channel per store is the default. Used as a fallback when no channel header is present and as the auto-publish target for new products | `true` |
|
|
23
23
|
| `storefront_access` | Controls what an anonymous visitor may see: `public`, `prices_hidden`, or `login_required`. Unset inherits the store's setting. See [Storefront Access Gating](#storefront-access-gating) | `login_required` |
|
|
24
24
|
| `guest_checkout` | Whether an order may be placed without an account on this channel. Unset inherits the store's setting | `false` |
|
|
25
|
-
| `preferred_order_routing_strategy` | Optional per-channel override of the store's [Order Routing](
|
|
25
|
+
| `preferred_order_routing_strategy` | Optional per-channel override of the store's [Order Routing](fulfillments.md#order-routing) strategy | `Spree::OrderRouting::Strategy::Rules` |
|
|
26
26
|
|
|
27
27
|
`code` is normalized to a URL-safe slug on save — `POS` becomes `pos`, `Point of Sale!` becomes `point-of-sale`. Leaving `code` blank derives it from `name`.
|
|
28
28
|
|
|
@@ -89,7 +89,7 @@ Product status (`draft` / `active` / `archived`) is the **outer gate**: a Draft
|
|
|
89
89
|
|
|
90
90
|
Every order is attributed to one channel. The channel is set from the `X-Spree-Channel` header on cart creation, from the merchant's selection on the "New order" form, or defaults to the store's primary channel.
|
|
91
91
|
|
|
92
|
-
This attribution drives reporting (best-selling by channel, revenue per channel) and per-channel order routing — see [Order Routing](
|
|
92
|
+
This attribution drives reporting (best-selling by channel, revenue per channel) and per-channel order routing — see [Order Routing](fulfillments.md#order-routing).
|
|
93
93
|
|
|
94
94
|
### Storefront Access Gating
|
|
95
95
|
|
|
@@ -217,7 +217,7 @@ The write contract is **full-set**: the array represents the complete desired st
|
|
|
217
217
|
- [Stores](stores.md) — Channels belong to a store
|
|
218
218
|
- [Markets](markets.md) — Different from channels: markets segment geography/currency, channels segment selling surfaces
|
|
219
219
|
- [Products](products.md) — Product catalog and publication
|
|
220
|
-
- [Order Routing](
|
|
220
|
+
- [Order Routing](fulfillments.md#order-routing) — Channels can override the store's routing strategy
|
|
221
221
|
- [Store SDK: Products](../sdk/store/products.md) — Channel-scoped product listing and filtering
|
|
222
222
|
- [Admin SDK: Resources](../sdk/admin/resources.md) — How `adminClient.channels.addProducts` and other resource methods are structured
|
|
223
223
|
- [Wholesale Portal](../storefront/nextjs/wholesale.md) — A gated channel driving the Next.js storefront's B2B surface
|
|
@@ -305,5 +305,5 @@ Customers don't need to register to purchase. Guest checkout uses an order token
|
|
|
305
305
|
- [Account (Store SDK)](../sdk/store/account.md) — Task-oriented walkthrough of registration, login, profile, addresses, and order history
|
|
306
306
|
- [Addresses](addresses.md) — Customer address management
|
|
307
307
|
- [Orders](orders.md) — Order history and checkout
|
|
308
|
-
- [Authentication](../
|
|
308
|
+
- [Authentication](../providers/sso.md) — Custom authentication setup
|
|
309
309
|
- [Staff & Roles](staff-roles.md) — Admin users and permissions
|
|
@@ -641,4 +641,4 @@ The base class also provides helper methods:
|
|
|
641
641
|
- [Webhooks & Events Reference](../../api-reference/webhooks-events.md) - Catalog of event and webhook payloads
|
|
642
642
|
- [Customization Quickstart](../customization/quickstart.md) - Overview of all customization options
|
|
643
643
|
- [Decorators](../customization/decorators.md) - When to use decorators vs events
|
|
644
|
-
- [Checkout Flow](
|
|
644
|
+
- [Checkout Flow](carts.md) - Using events in checkout customization
|