@spree/docs 0.1.0
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/README.md +54 -0
- package/dist/api-reference/platform/authentication.md +38 -0
- package/dist/api-reference/store-api/authentication.md +188 -0
- package/dist/api-reference/store-api/errors.md +277 -0
- package/dist/api-reference/store-api/idempotency.md +129 -0
- package/dist/api-reference/store-api/introduction.md +34 -0
- package/dist/api-reference/store-api/localization.md +279 -0
- package/dist/api-reference/store-api/metadata.md +160 -0
- package/dist/api-reference/store-api/monetary-amounts.md +65 -0
- package/dist/api-reference/store-api/querying.md +399 -0
- package/dist/api-reference/store-api/rate-limitting.md +103 -0
- package/dist/api-reference/store-api/relations.md +185 -0
- package/dist/api-reference/storefront/authentication.md +88 -0
- package/dist/api-reference/tutorials/adyen-integration-guide-for-android.md +165 -0
- package/dist/api-reference/tutorials/adyen-integration-guide-for-ios.md +194 -0
- package/dist/api-reference/tutorials/quick-checkout-with-stripe.md +248 -0
- package/dist/api-reference/v2/fetching-multiple-resources.md +26 -0
- package/dist/api-reference/v2/filtering-and-sorting.md +53 -0
- package/dist/api-reference/v2/introduction.md +22 -0
- package/dist/api-reference/v2/pagination.md +37 -0
- package/dist/api-reference/webhooks-events.md +883 -0
- package/dist/developer/admin/admin.md +205 -0
- package/dist/developer/admin/authentication.md +59 -0
- package/dist/developer/admin/components.md +711 -0
- package/dist/developer/admin/custom-css.md +243 -0
- package/dist/developer/admin/custom-javascript.md +116 -0
- package/dist/developer/admin/extending-ui.md +1964 -0
- package/dist/developer/admin/form-builder.md +444 -0
- package/dist/developer/admin/helper-methods.md +531 -0
- package/dist/developer/admin/navigation.md +805 -0
- package/dist/developer/admin/tables.md +491 -0
- package/dist/developer/advanced/adding_spree_to_rails_app.md +106 -0
- package/dist/developer/cli/quickstart.md +137 -0
- package/dist/developer/contributing/creating-an-extension.md +258 -0
- package/dist/developer/contributing/developing-spree.md +339 -0
- package/dist/developer/contributing/quickstart.md +32 -0
- package/dist/developer/contributing/updating-extensions.md +67 -0
- package/dist/developer/core-concepts/addresses.md +265 -0
- package/dist/developer/core-concepts/adjustments.md +107 -0
- package/dist/developer/core-concepts/architecture.md +177 -0
- package/dist/developer/core-concepts/calculators.md +323 -0
- package/dist/developer/core-concepts/customers.md +230 -0
- package/dist/developer/core-concepts/events.md +624 -0
- package/dist/developer/core-concepts/imports-exports.md +698 -0
- package/dist/developer/core-concepts/inventory.md +191 -0
- package/dist/developer/core-concepts/markets.md +250 -0
- package/dist/developer/core-concepts/media.md +167 -0
- package/dist/developer/core-concepts/metafields.md +187 -0
- package/dist/developer/core-concepts/orders.md +328 -0
- package/dist/developer/core-concepts/payments.md +710 -0
- package/dist/developer/core-concepts/pricing.md +163 -0
- package/dist/developer/core-concepts/products.md +360 -0
- package/dist/developer/core-concepts/promotions.md +322 -0
- package/dist/developer/core-concepts/reports.md +206 -0
- package/dist/developer/core-concepts/search-filtering.md +237 -0
- package/dist/developer/core-concepts/shipments.md +212 -0
- package/dist/developer/core-concepts/slugs.md +111 -0
- package/dist/developer/core-concepts/staff-roles.md +123 -0
- package/dist/developer/core-concepts/store-credits-gift-cards.md +317 -0
- package/dist/developer/core-concepts/stores.md +117 -0
- package/dist/developer/core-concepts/taxes.md +135 -0
- package/dist/developer/core-concepts/translations.md +120 -0
- package/dist/developer/core-concepts/users.md +299 -0
- package/dist/developer/core-concepts/webhooks.md +378 -0
- package/dist/developer/create-spree-app/quickstart.md +158 -0
- package/dist/developer/customization/api.md +93 -0
- package/dist/developer/customization/authentication.md +88 -0
- package/dist/developer/customization/checkout.md +204 -0
- package/dist/developer/customization/configuration.md +55 -0
- package/dist/developer/customization/decorators.md +523 -0
- package/dist/developer/customization/dependencies.md +232 -0
- package/dist/developer/customization/emails.md +21 -0
- package/dist/developer/customization/extensions.md +92 -0
- package/dist/developer/customization/metadata.md +236 -0
- package/dist/developer/customization/model-preferences.md +130 -0
- package/dist/developer/customization/permissions.md +265 -0
- package/dist/developer/customization/quickstart.md +229 -0
- package/dist/developer/customization/routes.md +24 -0
- package/dist/developer/customization/v4/admin-panel.md +78 -0
- package/dist/developer/customization/v4/authentication.md +210 -0
- package/dist/developer/customization/v4/checkout.md +212 -0
- package/dist/developer/customization/v4/deface.md +251 -0
- package/dist/developer/customization/v4/images.md +86 -0
- package/dist/developer/customization/v4/storefront.md +450 -0
- package/dist/developer/deployment/assets.md +87 -0
- package/dist/developer/deployment/aws.md +335 -0
- package/dist/developer/deployment/caching.md +27 -0
- package/dist/developer/deployment/cdn.md +39 -0
- package/dist/developer/deployment/database.md +155 -0
- package/dist/developer/deployment/docker.md +128 -0
- package/dist/developer/deployment/emails.md +77 -0
- package/dist/developer/deployment/environment_variables.md +111 -0
- package/dist/developer/deployment/heroku.md +51 -0
- package/dist/developer/deployment/render.md +95 -0
- package/dist/developer/getting-started/quickstart.md +82 -0
- package/dist/developer/how-to/custom-payment-method.md +374 -0
- package/dist/developer/how-to/custom-promotion.md +373 -0
- package/dist/developer/how-to/custom-report.md +387 -0
- package/dist/developer/how-to/custom-search-provider.md +230 -0
- package/dist/developer/multi-store/quickstart.md +71 -0
- package/dist/developer/multi-store/setup.md +38 -0
- package/dist/developer/multi-tenant/configuration.md +41 -0
- package/dist/developer/multi-tenant/core-concepts.md +75 -0
- package/dist/developer/multi-tenant/installation.md +96 -0
- package/dist/developer/multi-tenant/quickstart.md +20 -0
- package/dist/developer/multi-vendor/installation.md +45 -0
- package/dist/developer/multi-vendor/quickstart.md +17 -0
- package/dist/developer/sdk/admin/quickstart.md +22 -0
- package/dist/developer/sdk/authentication.md +89 -0
- package/dist/developer/sdk/configuration.md +225 -0
- package/dist/developer/sdk/quickstart.md +82 -0
- package/dist/developer/sdk/store/account.md +67 -0
- package/dist/developer/sdk/store/cart-checkout.md +140 -0
- package/dist/developer/sdk/store/markets.md +151 -0
- package/dist/developer/sdk/store/payments.md +96 -0
- package/dist/developer/sdk/store/products.md +149 -0
- package/dist/developer/sdk/store/wishlists.md +52 -0
- package/dist/developer/security/pci_compliance.md +15 -0
- package/dist/developer/security/security_policy.md +68 -0
- package/dist/developer/storefront/blocks.md +285 -0
- package/dist/developer/storefront/custom-css.md +260 -0
- package/dist/developer/storefront/custom-javascript.md +166 -0
- package/dist/developer/storefront/helper-methods.md +1288 -0
- package/dist/developer/storefront/links.md +298 -0
- package/dist/developer/storefront/nextjs/architecture.md +150 -0
- package/dist/developer/storefront/nextjs/customization.md +141 -0
- package/dist/developer/storefront/nextjs/deployment.md +180 -0
- package/dist/developer/storefront/nextjs/quickstart.md +92 -0
- package/dist/developer/storefront/nextjs/spree-next-package.md +314 -0
- package/dist/developer/storefront/pages.md +163 -0
- package/dist/developer/storefront/sections.md +569 -0
- package/dist/developer/storefront/storefront.md +56 -0
- package/dist/developer/storefront/themes.md +161 -0
- package/dist/developer/tutorial/admin.md +134 -0
- package/dist/developer/tutorial/extending-models.md +380 -0
- package/dist/developer/tutorial/file-uploads.md +121 -0
- package/dist/developer/tutorial/introduction.md +33 -0
- package/dist/developer/tutorial/model.md +41 -0
- package/dist/developer/tutorial/page-builder.md +487 -0
- package/dist/developer/tutorial/rich-text.md +73 -0
- package/dist/developer/tutorial/seo.md +332 -0
- package/dist/developer/tutorial/storefront.md +352 -0
- package/dist/developer/tutorial/testing.md +558 -0
- package/dist/developer/upgrades/2.0-to-2.1.md +46 -0
- package/dist/developer/upgrades/2.1-to-2.2.md +59 -0
- package/dist/developer/upgrades/2.2-to-2.3.md +44 -0
- package/dist/developer/upgrades/2.3-to-2.4.md +42 -0
- package/dist/developer/upgrades/3.0-to-3.1.md +47 -0
- package/dist/developer/upgrades/3.1-to-3.2.md +34 -0
- package/dist/developer/upgrades/3.2-to-3.3.md +70 -0
- package/dist/developer/upgrades/3.3-to-3.4.md +36 -0
- package/dist/developer/upgrades/3.4-to-3.5.md +44 -0
- package/dist/developer/upgrades/3.5-to-3.6.md +40 -0
- package/dist/developer/upgrades/3.6-to-3.7.md +62 -0
- package/dist/developer/upgrades/3.7-to-4.0.md +152 -0
- package/dist/developer/upgrades/4.0-to-4.1.md +92 -0
- package/dist/developer/upgrades/4.1-to-4.2.md +109 -0
- package/dist/developer/upgrades/4.10-to-5.0.md +129 -0
- package/dist/developer/upgrades/4.2-to-4.3.md +100 -0
- package/dist/developer/upgrades/4.3-to-4.4.md +125 -0
- package/dist/developer/upgrades/4.4-to-4.5.md +94 -0
- package/dist/developer/upgrades/4.5-to-4.6.md +119 -0
- package/dist/developer/upgrades/4.6-to-4.7.md +39 -0
- package/dist/developer/upgrades/4.8-to-4.9.md +24 -0
- package/dist/developer/upgrades/4.9-to-4.10.md +24 -0
- package/dist/developer/upgrades/4.x-to-4.8.md +52 -0
- package/dist/developer/upgrades/5.0-to-5.1.md +28 -0
- package/dist/developer/upgrades/5.1-to-5.2.md +127 -0
- package/dist/developer/upgrades/5.2-to-5.3.md +338 -0
- package/dist/developer/upgrades/5.3-to-5.4.md +248 -0
- package/dist/developer/upgrades/quickstart.md +36 -0
- package/dist/integrations/analytics/google-analytics.md +64 -0
- package/dist/integrations/analytics/google-tag-manager.md +78 -0
- package/dist/integrations/integrations.md +39 -0
- package/dist/integrations/marketing/klaviyo.md +99 -0
- package/dist/integrations/payments/adyen.md +90 -0
- package/dist/integrations/payments/paypal.md +41 -0
- package/dist/integrations/payments/razorpay.md +45 -0
- package/dist/integrations/payments/stripe.md +109 -0
- package/dist/integrations/search/meilisearch.md +236 -0
- package/dist/integrations/sso-mfa-social-login/admin-dashboard.md +57 -0
- package/dist/integrations/sso-mfa-social-login/storefront.md +56 -0
- package/package.json +27 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Inventory
|
|
3
|
+
description: Stock locations, stock items, stock movements, and inventory tracking
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
Each [Variant](/developer/core-concepts/products#variants) has a `StockItem` that tracks its inventory at a specific location. A variant can have multiple stock items if it's available at multiple stock locations.
|
|
9
|
+
|
|
10
|
+
When products are sold or returned, individual `InventoryUnit` records track each unit through the fulfillment process.
|
|
11
|
+
|
|
12
|
+
Adding new inventory to an out-of-stock product that has backorders will first fill the backorders, then update the available count with the remainder.
|
|
13
|
+
|
|
14
|
+
### Inventory Model Diagram
|
|
15
|
+
|
|
16
|
+
```mermaid
|
|
17
|
+
erDiagram
|
|
18
|
+
StockLocation {
|
|
19
|
+
string name
|
|
20
|
+
string admin_name
|
|
21
|
+
boolean active
|
|
22
|
+
boolean default
|
|
23
|
+
boolean backorderable_default
|
|
24
|
+
boolean propagate_all_variants
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
StockItem {
|
|
28
|
+
integer count_on_hand
|
|
29
|
+
boolean backorderable
|
|
30
|
+
integer stock_location_id
|
|
31
|
+
integer variant_id
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
StockMovement {
|
|
35
|
+
integer quantity
|
|
36
|
+
string originator_type
|
|
37
|
+
integer originator_id
|
|
38
|
+
integer stock_item_id
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
StockTransfer {
|
|
42
|
+
string number
|
|
43
|
+
string reference
|
|
44
|
+
integer source_location_id
|
|
45
|
+
integer destination_location_id
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
InventoryUnit {
|
|
49
|
+
string state
|
|
50
|
+
integer variant_id
|
|
51
|
+
integer order_id
|
|
52
|
+
integer shipment_id
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
StockLocation ||--o{ StockItem : "has many"
|
|
56
|
+
StockLocation ||--o{ StockTransfer : "source"
|
|
57
|
+
StockLocation ||--o{ StockTransfer : "destination"
|
|
58
|
+
Variant ||--o{ StockItem : "has many"
|
|
59
|
+
Variant ||--o{ InventoryUnit : "has many"
|
|
60
|
+
StockItem ||--o{ StockMovement : "has many"
|
|
61
|
+
StockTransfer ||--o{ StockMovement : "has many"
|
|
62
|
+
Order ||--o{ InventoryUnit : "has many"
|
|
63
|
+
Shipment ||--o{ InventoryUnit : "has many"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Key relationships:**
|
|
67
|
+
- **Stock Location** → Contains Stock Items (inventory per variant) and is the source/destination for Stock Transfers
|
|
68
|
+
- **Stock Item** → Tracks quantity (`count_on_hand`) for a specific Variant at a specific Stock Location
|
|
69
|
+
- **Stock Movement** → Records changes to Stock Item quantities (purchases, returns, transfers)
|
|
70
|
+
- **Stock Transfer** → Moves inventory between Stock Locations, creating Stock Movements at source and destination
|
|
71
|
+
- **Inventory Unit** → Represents individual units in [Orders](/developer/core-concepts/orders) and [Shipments](/developer/core-concepts/shipments)
|
|
72
|
+
|
|
73
|
+
## Inventory Management
|
|
74
|
+
|
|
75
|
+
### Stock Locations
|
|
76
|
+
|
|
77
|
+
Stock Locations are the physical locations where your inventory is stored and shipped from.
|
|
78
|
+
|
|
79
|
+
Stock Locations can be created in the Admin Panel under **Settings → Stock Locations**, or via the Admin API.
|
|
80
|
+
|
|
81
|
+
Stock Locations have several attributes that define their properties and behavior within the Spree system. Below is a table outlining these attributes:
|
|
82
|
+
|
|
83
|
+
| Attribute | Description | Example Value |
|
|
84
|
+
|-------------------|-----------------------------------------------------------------------------|---------------------|
|
|
85
|
+
| `name` | The public name of the stock location. This is returned in Store API | Warehouse 1 |
|
|
86
|
+
| `admin_name` | The name used internally for the stock location. This is only returned in Admin API. | WH1 Domestic |
|
|
87
|
+
| `address1` | The primary address line for the stock location. | 5th avenue |
|
|
88
|
+
| `address2` | The secondary address line for the stock location. | Suite 100 |
|
|
89
|
+
| `city` | The city where the stock location is based. | New York |
|
|
90
|
+
| `state_id` | The ID of the state where the stock location is based. This references the `State` model. | 1 |
|
|
91
|
+
| `country_id` | The ID of the country where the stock location is based. This references the `Country` model. | 1 |
|
|
92
|
+
| `zipcode` | The postal code for the stock location. | 10001 |
|
|
93
|
+
| `phone` | The contact phone number for the stock location. | 555-1234 |
|
|
94
|
+
| `active` | A boolean indicating whether the stock location is active. Inactive stock locations will not be used in stock calculations or be available for selection during checkout. | `true` |
|
|
95
|
+
| `default` | A boolean indicating whether the stock location is the default one used for new inventory operations. | `false` |
|
|
96
|
+
| `backorderable_default` | A boolean indicating whether new stock items in this location are backorderable by default. | `false` |
|
|
97
|
+
| `propagate_all_variants` | A boolean indicating whether new stock items should be automatically created for all Store variants when a new stock location is added. | `false` |
|
|
98
|
+
|
|
99
|
+
Stock Locations can be easily used for tracking warehouses and other physical locations. They can be used to track separate sections of a warehouse (e.g. aisles, shelves, etc.) or to track different warehouses.
|
|
100
|
+
|
|
101
|
+
You can easily use them with your Point of Sale (POS) system to track inventory at different locations.
|
|
102
|
+
|
|
103
|
+
### Stock Items
|
|
104
|
+
|
|
105
|
+
Stock Items represent the inventory at a stock location for a specific variant. Stock item count on hand can be increased or decreased by creating stock movements.
|
|
106
|
+
|
|
107
|
+
| Attribute | Description | Example Value |
|
|
108
|
+
|-------------------|-----------------------------------------------------------------------------|---------------------|
|
|
109
|
+
| `stock_location_id` | References the stock location where the stock item belongs. | `1` |
|
|
110
|
+
| `variant_id` | References the variant associated with the stock item. | `32` |
|
|
111
|
+
| `count_on_hand` | The number of items available on hand. | `150` |
|
|
112
|
+
| `backorderable` | Indicates whether the stock item can be backordered. | `true` |
|
|
113
|
+
|
|
114
|
+
### Stock Transfers
|
|
115
|
+
|
|
116
|
+
Stock transfers allow you to move inventory in bulk from one stock location to another stock location. This is handy when you want to integrate with a POS system or other inventory management system. Or you can just rely on Spree being the source of truth for your inventory.
|
|
117
|
+
|
|
118
|
+
> **INFO:** Stock Transfers can be created in the Admin dashboard or via the Admin API.
|
|
119
|
+
|
|
120
|
+
Here's the list of attributes for the Stock Transfer model:
|
|
121
|
+
|
|
122
|
+
| Attribute | Description | Example Value |
|
|
123
|
+
|--------------------------|-----------------------------------------------------------------------------|---------------------|
|
|
124
|
+
| `number` | The unique number identifier for the stock transfer, generated automatically. | `T123456789` |
|
|
125
|
+
| `reference` | An optional reference field for the stock transfer. | Transfer for Event |
|
|
126
|
+
| `source_location_id` | The ID of the stock location where the stock is transferred from. | `2` |
|
|
127
|
+
| `destination_location_id`| The ID of the stock location where the stock is transferred to. | `3` |
|
|
128
|
+
|
|
129
|
+
Stock transfers are crucial for managing inventory across multiple locations, ensuring that stock levels are accurate and up-to-date.
|
|
130
|
+
|
|
131
|
+
Each Stock Transfer will hold a list of Stock Movements.
|
|
132
|
+
|
|
133
|
+
### Stock Movements
|
|
134
|
+
|
|
135
|
+
Stock Movements track the movement of the inventory:
|
|
136
|
+
|
|
137
|
+
* when you move inventory between stock locations (via Stock Transfer)
|
|
138
|
+
* when you add inventory to a stock location
|
|
139
|
+
* when you remove inventory from a stock location
|
|
140
|
+
* when customers purchase products
|
|
141
|
+
* when customers return products
|
|
142
|
+
|
|
143
|
+
Here's the list of attributes for the Stock Movement model:
|
|
144
|
+
|
|
145
|
+
| Attribute | Description | Example Value |
|
|
146
|
+
|-------------------|-----------------------------------------------------------------------------|---------------------|
|
|
147
|
+
| `stock_item_id` | References the stock item that the movement belongs to. | `45` |
|
|
148
|
+
| `quantity` | The quantity by which the stock item's count on hand is changed. Positive values indicate stock being added, while negative values indicate stock being removed. | `-10` |
|
|
149
|
+
| `originator_type` | The type of the originator of the stock movement. This is a polymorphic association. | `Spree::Shipment` |
|
|
150
|
+
| `originator_id` | The ID of the originator of the stock movement. This is used in conjunction with `originator_type`. | `2` |
|
|
151
|
+
|
|
152
|
+
Stock Movements are crucial for maintaining accurate inventory levels and for historical tracking of inventory adjustments.
|
|
153
|
+
|
|
154
|
+
## Inventory Units
|
|
155
|
+
|
|
156
|
+
As we mentioned above, back-ordered, sold, or shipped products are stored as individual `InventoryUnit` objects so they can have relevant information attached to them.
|
|
157
|
+
|
|
158
|
+
We create `InventoryUnit` objects when:
|
|
159
|
+
|
|
160
|
+
* a product is sold (they are added to the Shipment)
|
|
161
|
+
* a product is returned
|
|
162
|
+
|
|
163
|
+
Here's a list of attributes for the Inventory Unit model:
|
|
164
|
+
|
|
165
|
+
| Attribute | Description | Example Value |
|
|
166
|
+
|-------------------|-----------------------------------------------------------------------------|---------------------|
|
|
167
|
+
| `variant_id` | References the variant associated with the inventory unit. | `32` |
|
|
168
|
+
| `order_id` | References the order associated with the inventory unit. | `123` |
|
|
169
|
+
| `shipment_id` | References the shipment associated with the inventory unit. | `77` |
|
|
170
|
+
| `state` | The state of the inventory unit | `on_hand` |
|
|
171
|
+
|
|
172
|
+
Inventory Units states are:
|
|
173
|
+
|
|
174
|
+
* `on_hand` - the inventory unit is on hand
|
|
175
|
+
* `backordered` - the inventory unit is backordered
|
|
176
|
+
* `shipped` - the inventory unit is shipped
|
|
177
|
+
|
|
178
|
+
> **NOTE:** As we noted before, when you add new Stock Items to a Variant (eg. via Admin Panel or Admin API), the first Inventory Units to fulfill are the backordered ones.
|
|
179
|
+
|
|
180
|
+
## Disabling Inventory Tracking
|
|
181
|
+
|
|
182
|
+
If you don't need to track inventory, you can disable it:
|
|
183
|
+
|
|
184
|
+
- **Per variant** — set `track_inventory` to `false` on a specific variant via the Admin Panel or Admin API
|
|
185
|
+
- **Globally** — disable inventory tracking for the entire store in your Spree configuration
|
|
186
|
+
|
|
187
|
+
## Related Documentation
|
|
188
|
+
|
|
189
|
+
- [Products](/developer/core-concepts/products) - Product and variant management
|
|
190
|
+
- [Shipments](/developer/core-concepts/shipments) - How inventory relates to shipments
|
|
191
|
+
- [Orders](/developer/core-concepts/orders) - How inventory is allocated to orders
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Markets
|
|
3
|
+
description: Multi-region commerce with Markets — bundle geography, currency, and locale into distinct selling regions within a single store.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Overview
|
|
7
|
+
|
|
8
|
+
Markets let you segment a single [Store](/developer/core-concepts/stores) into distinct geographic regions, each with its own currency, locale, and set of countries. For example, an international store might define:
|
|
9
|
+
|
|
10
|
+
- **North America** — USD, English, ships to US and Canada
|
|
11
|
+
- **Europe** — EUR, German, ships to DE, FR, AT, NL
|
|
12
|
+
- **United Kingdom** — GBP, English, ships to GB
|
|
13
|
+
|
|
14
|
+
```mermaid
|
|
15
|
+
erDiagram
|
|
16
|
+
Store ||--o{ Market : "has many"
|
|
17
|
+
Market ||--o{ MarketCountry : "has many"
|
|
18
|
+
MarketCountry }o--|| Country : "belongs to"
|
|
19
|
+
|
|
20
|
+
Store {
|
|
21
|
+
string name
|
|
22
|
+
string url
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
Market {
|
|
26
|
+
string name
|
|
27
|
+
string currency
|
|
28
|
+
string default_locale
|
|
29
|
+
string supported_locales
|
|
30
|
+
boolean tax_inclusive
|
|
31
|
+
boolean default
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Country {
|
|
35
|
+
string iso
|
|
36
|
+
string name
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Market Attributes
|
|
41
|
+
|
|
42
|
+
| Attribute | Description | Example |
|
|
43
|
+
|-----------|-------------|---------|
|
|
44
|
+
| `name` | Human-readable name, unique per store | `North America` |
|
|
45
|
+
| `currency` | ISO 4217 currency code | `USD` |
|
|
46
|
+
| `default_locale` | Default language for this market | `en` |
|
|
47
|
+
| `supported_locales` | All locales available in this market | `["en", "es"]` |
|
|
48
|
+
| `tax_inclusive` | Whether prices include tax (affects display and checkout calculation) | `false` |
|
|
49
|
+
| `default` | Whether this is the fallback market when no country match is found | `true` |
|
|
50
|
+
| `countries` | List of countries in this market | `[{ iso: "US" }, { iso: "CA" }]` |
|
|
51
|
+
|
|
52
|
+
## How Markets Work
|
|
53
|
+
|
|
54
|
+
When a customer visits your store, their country determines which market applies. The market then sets the currency, locale, and tax behavior for that session.
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
Customer's Country → Market → Currency + Locale + Tax Zone
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The resolution chain:
|
|
61
|
+
|
|
62
|
+
1. Customer's country is detected (from URL, geolocation, `X-Spree-Country` header, or manual selection)
|
|
63
|
+
2. Spree finds the market containing that country
|
|
64
|
+
3. The market's currency and locale become the defaults for the session
|
|
65
|
+
4. The market's tax zone determines whether prices are shown with or without tax
|
|
66
|
+
|
|
67
|
+
If no market matches the customer's country, the store's **default market** is used.
|
|
68
|
+
|
|
69
|
+
## Listing Markets
|
|
70
|
+
|
|
71
|
+
Fetch all markets for the current store, including their countries:
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
```typescript SDK
|
|
75
|
+
const { data: markets } = await client.markets.list()
|
|
76
|
+
// [
|
|
77
|
+
// {
|
|
78
|
+
// id: "mkt_k5nR8xLq",
|
|
79
|
+
// name: "North America",
|
|
80
|
+
// currency: "USD",
|
|
81
|
+
// default_locale: "en",
|
|
82
|
+
// supported_locales: ["en", "es"],
|
|
83
|
+
// tax_inclusive: false,
|
|
84
|
+
// default: true,
|
|
85
|
+
// countries: [
|
|
86
|
+
// { iso: "US", name: "United States", states_required: true, zipcode_required: true },
|
|
87
|
+
// { iso: "CA", name: "Canada", states_required: true, zipcode_required: true }
|
|
88
|
+
// ]
|
|
89
|
+
// },
|
|
90
|
+
// ...
|
|
91
|
+
// ]
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```bash cURL
|
|
95
|
+
curl 'https://api.mystore.com/api/v3/store/markets' \
|
|
96
|
+
-H 'Authorization: Bearer spree_pk_xxx'
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
## Resolving a Market by Country
|
|
101
|
+
|
|
102
|
+
When you know a customer's country (e.g., from geolocation or a country picker), resolve which market applies:
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
```typescript SDK
|
|
106
|
+
const market = await client.markets.resolve('DE')
|
|
107
|
+
// { id: "mkt_gbHJdmfr", name: "Europe", currency: "EUR", tax_inclusive: true, ... }
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
```bash cURL
|
|
111
|
+
curl 'https://api.mystore.com/api/v3/store/markets/resolve?country=DE' \
|
|
112
|
+
-H 'Authorization: Bearer spree_pk_xxx'
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
Returns the market object on success, or `404` if no market contains that country.
|
|
117
|
+
|
|
118
|
+
This is useful for building a country switcher — resolve the market to show the customer what currency and language they'll get.
|
|
119
|
+
|
|
120
|
+
## Countries in a Market
|
|
121
|
+
|
|
122
|
+
List countries belonging to a specific market. Useful for populating address form dropdowns during checkout:
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
```typescript SDK
|
|
126
|
+
const { data: countries } = await client.markets.countries.list('mkt_k5nR8xLq')
|
|
127
|
+
// [
|
|
128
|
+
// { iso: "CA", name: "Canada", states_required: true, zipcode_required: true },
|
|
129
|
+
// { iso: "US", name: "United States", states_required: true, zipcode_required: true }
|
|
130
|
+
// ]
|
|
131
|
+
|
|
132
|
+
// Get a country with its states (for address form dropdowns)
|
|
133
|
+
const usa = await client.markets.countries.get('mkt_k5nR8xLq', 'US', {
|
|
134
|
+
include: 'states',
|
|
135
|
+
})
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
```bash cURL
|
|
139
|
+
# List countries in a market
|
|
140
|
+
curl 'https://api.mystore.com/api/v3/store/markets/mkt_k5nR8xLq/countries' \
|
|
141
|
+
-H 'Authorization: Bearer spree_pk_xxx'
|
|
142
|
+
|
|
143
|
+
# Get a country with its states
|
|
144
|
+
curl 'https://api.mystore.com/api/v3/store/markets/mkt_k5nR8xLq/countries/US?include=states' \
|
|
145
|
+
-H 'Authorization: Bearer spree_pk_xxx'
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
You can also fetch countries flat (across all markets) or include the market on a country:
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
```typescript SDK
|
|
153
|
+
// All countries across all markets
|
|
154
|
+
const { data: countries } = await client.countries.list()
|
|
155
|
+
|
|
156
|
+
// Get a country with its market details
|
|
157
|
+
const germany = await client.countries.get('DE', { include: 'market' })
|
|
158
|
+
// { iso: "DE", name: "Germany", market: { currency: "EUR", default_locale: "de", tax_inclusive: true } }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```bash cURL
|
|
162
|
+
# All countries across all markets
|
|
163
|
+
curl 'https://api.mystore.com/api/v3/store/countries' \
|
|
164
|
+
-H 'Authorization: Bearer spree_pk_xxx'
|
|
165
|
+
|
|
166
|
+
# Get a country with its market
|
|
167
|
+
curl 'https://api.mystore.com/api/v3/store/countries/DE?include=market' \
|
|
168
|
+
-H 'Authorization: Bearer spree_pk_xxx'
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
## Currency and Locale
|
|
173
|
+
|
|
174
|
+
Each market defines a currency and set of supported locales. When a market is resolved, its currency and locale become the defaults for the session.
|
|
175
|
+
|
|
176
|
+
You can discover all available currencies and locales (aggregated from all markets) via dedicated endpoints:
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
```typescript SDK
|
|
180
|
+
const { data: currencies } = await client.currencies.list()
|
|
181
|
+
// [{ iso_code: "USD", name: "US Dollar", symbol: "$" }, { iso_code: "EUR", name: "Euro", symbol: "€" }]
|
|
182
|
+
|
|
183
|
+
const { data: locales } = await client.locales.list()
|
|
184
|
+
// [{ code: "en", name: "English" }, { code: "de", name: "German" }]
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```bash cURL
|
|
188
|
+
curl 'https://api.mystore.com/api/v3/store/currencies' \
|
|
189
|
+
-H 'Authorization: Bearer spree_pk_xxx'
|
|
190
|
+
|
|
191
|
+
curl 'https://api.mystore.com/api/v3/store/locales' \
|
|
192
|
+
-H 'Authorization: Bearer spree_pk_xxx'
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
See [Localization](/api-reference/store-api/localization) for details on how to pass locale, currency, and country headers in API requests.
|
|
197
|
+
|
|
198
|
+
## Tax Behavior
|
|
199
|
+
|
|
200
|
+
The `tax_inclusive` flag on a market controls how prices are displayed and calculated:
|
|
201
|
+
|
|
202
|
+
- **`tax_inclusive: true`** (common in Europe) — the price shown to the customer already includes tax
|
|
203
|
+
- **`tax_inclusive: false`** (common in the US) — tax is added at checkout on top of the displayed price
|
|
204
|
+
|
|
205
|
+
Each market also resolves a **tax zone** from its default country. This zone determines which tax rates apply when browsing products — before the customer enters a shipping address. Once the customer provides an address at checkout, the actual shipping address takes over for tax calculation.
|
|
206
|
+
|
|
207
|
+
See [Taxes](/developer/core-concepts/taxes) for details on tax zones and rates.
|
|
208
|
+
|
|
209
|
+
## Pricing Integration
|
|
210
|
+
|
|
211
|
+
Markets integrate with the [Pricing](/developer/core-concepts/pricing) system, enabling market-specific pricing through **Price Lists** with a **Market Rule**. This lets you set different prices for the same product in different markets — beyond just currency conversion.
|
|
212
|
+
|
|
213
|
+
For example, you could price a product at $29.99 in North America and €24.99 in Europe, rather than relying on exchange rate conversion.
|
|
214
|
+
|
|
215
|
+
See [Pricing — Price Rules](/developer/core-concepts/pricing#price-rules) for details on configuring market-specific price lists.
|
|
216
|
+
|
|
217
|
+
## Setting Up Markets
|
|
218
|
+
|
|
219
|
+
Markets are managed in the admin dashboard under **Settings → Markets**. When you run `rails db:seed`, Spree automatically creates a default market for each store.
|
|
220
|
+
|
|
221
|
+
To create markets programmatically:
|
|
222
|
+
|
|
223
|
+
```ruby
|
|
224
|
+
# North America market
|
|
225
|
+
current_store.markets.create!(
|
|
226
|
+
name: 'North America',
|
|
227
|
+
currency: 'USD',
|
|
228
|
+
default_locale: 'en',
|
|
229
|
+
countries: [usa, canada],
|
|
230
|
+
default: true
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
# Europe market with tax-inclusive pricing
|
|
234
|
+
current_store.markets.create!(
|
|
235
|
+
name: 'Europe',
|
|
236
|
+
currency: 'EUR',
|
|
237
|
+
default_locale: 'de',
|
|
238
|
+
supported_locales: 'de,en,fr',
|
|
239
|
+
tax_inclusive: true,
|
|
240
|
+
countries: [germany, france, austria, netherlands]
|
|
241
|
+
)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Related Documentation
|
|
245
|
+
|
|
246
|
+
- [Stores](/developer/core-concepts/stores) — Multi-store setup and configuration
|
|
247
|
+
- [Pricing](/developer/core-concepts/pricing) — Price Lists, Price Rules, and the Pricing Context
|
|
248
|
+
- [Addresses](/developer/core-concepts/addresses) — Countries, States, and Zones
|
|
249
|
+
- [Localization](/api-reference/store-api/localization) — Locale, currency, and country headers in API requests
|
|
250
|
+
- [Translations](/developer/core-concepts/translations) — Resource and UI translations
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Media
|
|
3
|
+
sidebarTitle: "Media"
|
|
4
|
+
description: Product media (images, videos), named variants, focal points, and how media is served via the Store API
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
Spree handles uploads, processing, and delivery for product media. Images are automatically converted to WebP format and preprocessed into multiple sizes for optimal performance.
|
|
10
|
+
|
|
11
|
+
## Product Media
|
|
12
|
+
|
|
13
|
+
Product media uses the `Spree::Asset` model, which provides:
|
|
14
|
+
|
|
15
|
+
- **Multiple media per product** with ordering
|
|
16
|
+
- **Media types** — `image`, `video`, `external_video`
|
|
17
|
+
- **Alt text** for accessibility and SEO
|
|
18
|
+
- **Focal point** coordinates for smart cropping
|
|
19
|
+
- **Preprocessed named variants** for fast delivery
|
|
20
|
+
|
|
21
|
+
Each media item has a `media_type` field that defaults to `image`. The `variant_ids` field indicates which product variants the media is associated with — an empty array means the media belongs to the product as a whole.
|
|
22
|
+
|
|
23
|
+
> **NOTE:** `Spree::Image` is a backward-compatible subclass of `Spree::Asset` that sets `media_type` to `image`. New code should use `Spree::Asset` directly.
|
|
24
|
+
|
|
25
|
+
### Named Variant Sizes
|
|
26
|
+
|
|
27
|
+
When an image is uploaded, Spree automatically generates optimized versions in the background:
|
|
28
|
+
|
|
29
|
+
| Name | Dimensions | Use Case |
|
|
30
|
+
|------|------------|----------|
|
|
31
|
+
| `mini` | 128x128 | Thumbnails, cart items |
|
|
32
|
+
| `small` | 256x256 | Product listings, galleries |
|
|
33
|
+
| `medium` | 400x400 | Product cards, category pages |
|
|
34
|
+
| `large` | 720x720 | Product detail pages |
|
|
35
|
+
| `xlarge` | 2000x2000 | Zoom, high-resolution displays |
|
|
36
|
+
|
|
37
|
+
All variants are cropped to fill the exact dimensions and converted to WebP format.
|
|
38
|
+
|
|
39
|
+
## Store API
|
|
40
|
+
|
|
41
|
+
### Thumbnails (Always Available)
|
|
42
|
+
|
|
43
|
+
Every product response includes a `thumbnail_url` field — ready to use without any expands. Similarly, each variant includes a `thumbnail` URL and a `media_count` counter.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
```typescript SDK
|
|
47
|
+
// List products — thumbnail_url is always included
|
|
48
|
+
const { data: products } = await client.products.list({ limit: 12 })
|
|
49
|
+
|
|
50
|
+
products.forEach(product => {
|
|
51
|
+
product.thumbnail_url // "https://cdn.../tote-front.webp" — no expand needed
|
|
52
|
+
})
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```bash cURL
|
|
56
|
+
# thumbnail_url is always in the response — no ?expand needed
|
|
57
|
+
curl 'https://api.mystore.com/api/v3/store/products?limit=12' \
|
|
58
|
+
-H 'Authorization: Bearer spree_pk_xxx'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
> **WARNING:** Avoid using `?expand=media` on listing pages. This loads **all** media for every product in the response. Use `thumbnail_url` instead and only expand full media on product detail pages.
|
|
63
|
+
|
|
64
|
+
### Full Media (On Demand)
|
|
65
|
+
|
|
66
|
+
On the product detail page, expand `media` and `variants` to get the full set of media with all named variant URLs:
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
```typescript SDK
|
|
70
|
+
const product = await client.products.get('spree-tote', {
|
|
71
|
+
expand: ['media', 'variants'],
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// Product media gallery
|
|
75
|
+
product.media // [{ id, media_type, product_id, variant_ids, original_url, mini_url, ..., alt, position }, ...]
|
|
76
|
+
|
|
77
|
+
// Each variant has its own thumbnail and media_count
|
|
78
|
+
product.variants?.forEach(variant => {
|
|
79
|
+
variant.thumbnail // "https://cdn.../tote-red.webp" — always available
|
|
80
|
+
variant.media_count // 3 — quick check without loading media
|
|
81
|
+
variant.media // full media array (only with ?expand=media)
|
|
82
|
+
})
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```bash cURL
|
|
86
|
+
curl 'https://api.mystore.com/api/v3/store/products/spree-tote?expand=media,variants' \
|
|
87
|
+
-H 'Authorization: Bearer spree_pk_xxx'
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
**Response (media object):**
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"id": "media_k5nR8xLq",
|
|
96
|
+
"media_type": "image",
|
|
97
|
+
"product_id": "prod_86Rf07xd4z",
|
|
98
|
+
"variant_ids": ["variant_m3Rp9wXz"],
|
|
99
|
+
"position": 1,
|
|
100
|
+
"alt": "Front view",
|
|
101
|
+
"focal_point_x": null,
|
|
102
|
+
"focal_point_y": null,
|
|
103
|
+
"external_video_url": null,
|
|
104
|
+
"original_url": "https://cdn.example.com/images/original.jpg",
|
|
105
|
+
"mini_url": "https://cdn.example.com/images/mini.webp",
|
|
106
|
+
"small_url": "https://cdn.example.com/images/small.webp",
|
|
107
|
+
"medium_url": "https://cdn.example.com/images/medium.webp",
|
|
108
|
+
"large_url": "https://cdn.example.com/images/large.webp",
|
|
109
|
+
"xlarge_url": "https://cdn.example.com/images/xlarge.webp"
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Media Fields Summary
|
|
114
|
+
|
|
115
|
+
| Field | Available on | Always Returned | Description |
|
|
116
|
+
|-------|-------------|:---:|-------------|
|
|
117
|
+
| `thumbnail_url` | Product | Yes | URL to the product's first media |
|
|
118
|
+
| `thumbnail` | Variant | Yes | URL to the variant's first media |
|
|
119
|
+
| `media_count` | Variant | Yes | Number of media items (counter cache) |
|
|
120
|
+
| `media` | Product, Variant | No | Full media array (requires `?expand=media`) |
|
|
121
|
+
|
|
122
|
+
### Media Object Fields
|
|
123
|
+
|
|
124
|
+
| Field | Type | Description |
|
|
125
|
+
|-------|------|-------------|
|
|
126
|
+
| `id` | string | Prefixed ID (`media_xxx`) |
|
|
127
|
+
| `media_type` | string | `image`, `video`, or `external_video` |
|
|
128
|
+
| `product_id` | string \| null | Owning product prefixed ID |
|
|
129
|
+
| `variant_ids` | string[] | Associated variant prefixed IDs (empty = product-level) |
|
|
130
|
+
| `position` | number | Sort order |
|
|
131
|
+
| `alt` | string \| null | Alt text |
|
|
132
|
+
| `focal_point_x` | number \| null | Horizontal focal point (0.0–1.0) |
|
|
133
|
+
| `focal_point_y` | number \| null | Vertical focal point (0.0–1.0) |
|
|
134
|
+
| `external_video_url` | string \| null | External video URL (YouTube/Vimeo) |
|
|
135
|
+
| `original_url` | string \| null | Full-size image URL |
|
|
136
|
+
| `mini_url` ... `xlarge_url` | string \| null | Named variant URLs |
|
|
137
|
+
|
|
138
|
+
## Image Processing
|
|
139
|
+
|
|
140
|
+
Spree uses [libvips](https://www.libvips.org/) for image processing. Images are automatically:
|
|
141
|
+
|
|
142
|
+
- Converted to **WebP format** for optimal file size
|
|
143
|
+
- **Preprocessed on upload** into all named variant sizes
|
|
144
|
+
- **Cached** for subsequent requests
|
|
145
|
+
|
|
146
|
+
## Storage
|
|
147
|
+
|
|
148
|
+
Spree supports two storage service types:
|
|
149
|
+
|
|
150
|
+
| Service | Purpose | Examples |
|
|
151
|
+
|---------|---------|---------|
|
|
152
|
+
| Public storage | Product images, logos, taxon images | S3 public bucket, CDN |
|
|
153
|
+
| Private storage | CSV exports, digital downloads | S3 private bucket |
|
|
154
|
+
|
|
155
|
+
> **INFO:** For production deployments, use cloud storage (S3, GCS, Azure) instead of local disk storage. See [Asset Deployment](/developer/deployment/assets) for configuration details.
|
|
156
|
+
|
|
157
|
+
## Best Practices
|
|
158
|
+
|
|
159
|
+
- **Use `thumbnail_url`** on listing pages — avoid loading full media via expand
|
|
160
|
+
- **Always provide alt text** for accessibility and SEO
|
|
161
|
+
- **Use named variant sizes** (`mini`, `small`, `medium`, `large`, `xlarge`) for optimal performance
|
|
162
|
+
- **Use a CDN** in production for faster delivery
|
|
163
|
+
|
|
164
|
+
## Related Documentation
|
|
165
|
+
|
|
166
|
+
- [Products](/developer/core-concepts/products) — Product catalog and media
|
|
167
|
+
- [Deployment — Assets](/developer/deployment/assets) — Storage and CDN configuration
|