@spree/docs 0.1.289 → 0.1.291
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.
|
@@ -239,7 +239,9 @@ sequenceDiagram
|
|
|
239
239
|
|
|
240
240
|
The frontend calls the API to create a Payment Session for a specific payment method and order. Spree calls the gateway to create a provider-side session (e.g., Stripe PaymentIntent, Adyen Session) and returns the session data including a `client_secret` for the frontend SDK.
|
|
241
241
|
|
|
242
|
-
> **INFO:**
|
|
242
|
+
> **INFO:** Create the payment session **after** the shipping method is selected, so the amount includes shipping costs. If the order total changes (a different shipping rate, a coupon), create the session again.
|
|
243
|
+
|
|
244
|
+
A cart has at most one open session per gateway. Asking Stripe for a session again (a reloaded checkout page, a second tab) cancels the cart's open session and opens a new one, because every open Stripe PaymentIntent can be paid on its own. If that session has already been paid, the request fails with a `gateway_error` and the paid session stays open. Once the order is placed, a background job cancels any session still pending — for example, one left behind when the customer switched to a different payment method — so it can no longer be paid.
|
|
243
245
|
|
|
244
246
|
**Step 2: Customer pays on the frontend**
|
|
245
247
|
|
|
@@ -373,8 +375,9 @@ stateDiagram-v2
|
|
|
373
375
|
```
|
|
374
376
|
|
|
375
377
|
> **NOTE:** There is no cancel endpoint. A session reaches `canceled` when the provider
|
|
376
|
-
> says so through its webhook,
|
|
377
|
-
>
|
|
378
|
+
> says so through its webhook, or after the order is placed while the session
|
|
379
|
+
> is still pending with nothing paid through it. It reaches `expired` when it
|
|
380
|
+
> passes `expires_at`. Neither is something a storefront drives.
|
|
378
381
|
|
|
379
382
|
#### API
|
|
380
383
|
|
|
@@ -18,7 +18,7 @@ The CLI walks you through an interactive setup:
|
|
|
18
18
|
|
|
19
19
|
Once complete, your store is running at [http://localhost:3000](http://localhost:3000) — setup pulls the latest Spree image, seeds the database, and configures API keys, then prints a summary with your admin credentials and keys. If you skipped starting services, the first `pnpm dev` completes setup automatically.
|
|
20
20
|
|
|
21
|
-
The **dashboard** and the
|
|
21
|
+
The **admin dashboard** is included in every project (skip it with `--no-dashboard` and the API still serves the built-in one at `/dashboard`). The installer asks whether to add the **seller panel** — a dedicated panel where marketplace vendors manage their products, orders and settings. Answer yes only if you run a marketplace; you can add it later with `spree add seller-dashboard`.
|
|
22
22
|
|
|
23
23
|
## Prerequisites
|
|
24
24
|
|
|
@@ -30,14 +30,14 @@ The **dashboard** and the marketplace **seller panel** are included in every pro
|
|
|
30
30
|
All prompts can be skipped with flags for non-interactive (CI/CD) usage:
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
npx create-spree-app@latest my-store --no-
|
|
33
|
+
npx create-spree-app@latest my-store --no-seller-dashboard --no-storefront --no-start
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
| Flag | Description |
|
|
37
37
|
|------|-------------|
|
|
38
|
-
| `--
|
|
38
|
+
| `--no-dashboard` | Skip the admin dashboard app — the API still serves the built-in one at `/dashboard` |
|
|
39
|
+
| `--no-seller-dashboard` | Skip the marketplace seller panel |
|
|
39
40
|
| `--no-storefront` | Skip Next.js storefront setup |
|
|
40
|
-
| `--no-sample-data` | Skip loading sample products and categories |
|
|
41
41
|
| `--no-start` | Don't start Docker services after scaffolding |
|
|
42
42
|
| `--port <number>` | Port for the Spree backend (default: `3000`) |
|
|
43
43
|
| `--use-npm` | Use npm as package manager |
|
|
@@ -58,9 +58,9 @@ my-store/
|
|
|
58
58
|
│ ├── Dockerfile # Also builds the production image (API + dashboard)
|
|
59
59
|
│ └── Gemfile
|
|
60
60
|
├── apps/
|
|
61
|
-
│ ├── dashboard/ # Admin dashboard (
|
|
61
|
+
│ ├── dashboard/ # Admin dashboard (unless --no-dashboard)
|
|
62
62
|
│ │ └── .env.local # Dev proxy target — no credentials
|
|
63
|
-
│ ├── seller-dashboard/ # Seller panel, for marketplaces (
|
|
63
|
+
│ ├── seller-dashboard/ # Seller panel, for marketplaces (unless --no-seller-dashboard)
|
|
64
64
|
│ └── storefront/ # Next.js storefront (unless --no-storefront)
|
|
65
65
|
│ └── .env.local # API URL + publishable key
|
|
66
66
|
├── .env # SECRET_KEY_BASE, encryption keys, SPREE_PORT, SPREE_VERSION_TAG, SPREE_SAMPLE_DATA
|
|
@@ -109,11 +109,12 @@ The project includes [@spree/cli](../cli/quickstart.md) for managing your Spree
|
|
|
109
109
|
|
|
110
110
|
| Command | Description |
|
|
111
111
|
|---------|-------------|
|
|
112
|
-
| `spree dev` | Run the app in the foreground — streams logs, Ctrl+C stops it. First run completes setup automatically; co-runs the
|
|
112
|
+
| `spree dev` | Run the app in the foreground — streams logs, Ctrl+C stops it. First run completes setup automatically; co-runs the Admin Dashboard dev server when `apps/dashboard` exists |
|
|
113
113
|
| `spree stop` | Stop backend services |
|
|
114
114
|
| `spree update` | Pull latest Spree image and restart (runs migrations automatically) |
|
|
115
115
|
| `spree eject` | Switch from prebuilt image to building from `server/` |
|
|
116
|
-
| `spree add dashboard` | Add the
|
|
116
|
+
| `spree add dashboard` | Add the Admin Dashboard to an existing project, to customize it |
|
|
117
|
+
| `spree add seller-dashboard` | Add the marketplace seller panel to an existing project |
|
|
117
118
|
| `spree build --production` | Build the production image — the Spree API plus your dashboard, in one |
|
|
118
119
|
| `spree logs` | View backend logs |
|
|
119
120
|
| `spree logs worker` | View background jobs logs |
|
|
@@ -160,7 +161,7 @@ SPREE_VERSION_TAG=5.4
|
|
|
160
161
|
|
|
161
162
|
## Deployment
|
|
162
163
|
|
|
163
|
-
The project deploys as **one image**: `server/Dockerfile` builds the Spree API together with your
|
|
164
|
+
The project deploys as **one image**: `server/Dockerfile` builds the Spree API together with your Admin Dashboard (when `apps/dashboard` exists), served same-origin at `/dashboard` — no CORS, no cookie configuration, no second service.
|
|
164
165
|
|
|
165
166
|
- **Render** — the `render.yaml` at the project root is a ready Blueprint: one Docker service built straight from your repo, migrations run on boot.
|
|
166
167
|
- **Anywhere else** — `spree build --production` builds the same image locally; push it to a registry and run it on any Docker host.
|
|
@@ -158,12 +158,22 @@ class MyGateway < Spree::PaymentMethod
|
|
|
158
158
|
payment_session
|
|
159
159
|
end
|
|
160
160
|
|
|
161
|
+
# Cancel a session the customer left behind, so it can no longer be paid.
|
|
162
|
+
# Spree calls this from a background job, once the order is placed, for
|
|
163
|
+
# every session still pending with nothing paid through it.
|
|
164
|
+
def cancel_payment_session(payment_session:)
|
|
165
|
+
MyProvider::Client.new(preferred_api_key).cancel_session(payment_session.external_id)
|
|
166
|
+
payment_session.cancel
|
|
167
|
+
end
|
|
168
|
+
|
|
161
169
|
def payment_icon_name
|
|
162
170
|
'my-gateway'
|
|
163
171
|
end
|
|
164
172
|
end
|
|
165
173
|
```
|
|
166
174
|
|
|
175
|
+
> **WARNING:** If your provider lets each open session be paid on its own (as Stripe does with PaymentIntents), a customer with two open sessions can be charged twice — for example, with checkout open in two tabs. Have `create_payment_session` cancel the cart's open sessions for your gateway before opening a new one, and implement `cancel_payment_session`. Leave a session the provider has already accepted, and do not open another. The built-in Stripe gateway does both. If you leave out `cancel_payment_session`, sessions still pending when the order is placed stay open at your provider.
|
|
176
|
+
|
|
167
177
|
### How the Frontend Uses It
|
|
168
178
|
|
|
169
179
|
The frontend creates a session, then uses the provider's SDK to collect payment:
|
|
@@ -194,7 +204,7 @@ const completed = await client.carts.paymentSessions.complete(
|
|
|
194
204
|
const order = await client.carts.complete(cart.id, options)
|
|
195
205
|
```
|
|
196
206
|
|
|
197
|
-
> **INFO:** **Important:** Always create the payment session **after** shipping is selected. If the order total changes (shipping rate change, coupon applied),
|
|
207
|
+
> **INFO:** **Important:** Always create the payment session **after** shipping is selected. If the order total changes (shipping rate change, coupon applied), update the session with the new amount (`client.carts.paymentSessions.update`) rather than creating another one. The `complete` call in step 5 only handles payment — step 6 finalizes the order.
|
|
198
208
|
|
|
199
209
|
## Step 4: Handle Webhooks (Recommended)
|
|
200
210
|
|