@spree/docs 0.1.251 → 0.1.253
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/developer/core-concepts/carts.md +5 -1
- package/dist/developer/core-concepts/orders.md +1 -1
- package/dist/developer/core-concepts/sellers.md +9 -0
- package/dist/developer/customization/checkout.md +5 -0
- package/dist/developer/sdk/store/cart-checkout.md +18 -1
- package/dist/developer/upgrades/5.6-to-6.0.md +7 -5
- package/package.json +1 -1
|
@@ -250,7 +250,7 @@ For providers like Stripe, create a payment session and confirm it with their ow
|
|
|
250
250
|
const order = await client.carts.complete(cartId)
|
|
251
251
|
```
|
|
252
252
|
|
|
253
|
-
You get back an [Order](orders.md).
|
|
253
|
+
You get back an [Order](orders.md) — or, in a marketplace where the cart held several sellers' goods, an [order group](sellers.md#one-checkout-several-sellers) holding one order per seller. Tell them apart with `isOrderGroup` from `@spree/sdk`.
|
|
254
254
|
|
|
255
255
|
|
|
256
256
|
Discount codes, gift cards and store credit can be applied any time before completion:
|
|
@@ -280,6 +280,10 @@ Completing a cart moves real money, so Spree is careful about it:
|
|
|
280
280
|
|
|
281
281
|
**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.
|
|
282
282
|
|
|
283
|
+
**The order keeps what the cart collected.** The customer, addresses, items, notes, purchase order number, tax identifier and the cart's `metadata` are all copied onto the order. When a checkout is split into one order per seller, every one of those orders receives the same copy. After that the cart and the order are independent — changing one never changes the other.
|
|
284
|
+
|
|
285
|
+
> **WARNING:** A customer can write a cart's `metadata` through the Store API, so once it is copied onto the order, treat those keys as customer input. Do not keep anything there that your own code later trusts, such as a fraud or approval flag.
|
|
286
|
+
|
|
283
287
|
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.
|
|
284
288
|
|
|
285
289
|
## Abandoned carts
|
|
@@ -5,7 +5,7 @@ description: How Spree models orders — a permanent record created by completin
|
|
|
5
5
|
|
|
6
6
|
## Overview
|
|
7
7
|
|
|
8
|
-
An order is a placed purchase. It's created by completing a [Cart](carts.md) and holds its own copy of everything the customer agreed to — items, prices, taxes, discounts and delivery.
|
|
8
|
+
An order is a placed purchase. It's created by completing a [Cart](carts.md) and holds its own copy of everything the customer agreed to — items, prices, taxes, discounts and delivery. Anything your storefront stored in the cart's `metadata` is copied onto the order too, including onto every order of a checkout split between sellers.
|
|
9
9
|
|
|
10
10
|
```mermaid
|
|
11
11
|
erDiagram
|
|
@@ -246,6 +246,15 @@ Two details worth knowing:
|
|
|
246
246
|
> A back office must handle it too: an order raised from the admin divides the same way, so completing one may answer with a group instead of an order.
|
|
247
247
|
|
|
248
248
|
|
|
249
|
+
```typescript Store SDK
|
|
250
|
+
import { isOrderGroup } from '@spree/sdk'
|
|
251
|
+
|
|
252
|
+
const result = await client.carts.complete(cartId, { spreeToken: cart.token })
|
|
253
|
+
|
|
254
|
+
// One order per seller when the cart held several sellers' goods.
|
|
255
|
+
const orders = isOrderGroup(result) ? result.orders : [result]
|
|
256
|
+
```
|
|
257
|
+
|
|
249
258
|
```typescript Admin SDK
|
|
250
259
|
import { isOrderGroup } from '@spree/admin-sdk'
|
|
251
260
|
|
|
@@ -41,6 +41,11 @@ Spree::Checkout::Registry.add_requirement(
|
|
|
41
41
|
While `satisfied:` returns false the cart reports the requirement and refuses to
|
|
42
42
|
complete. Its `code` is derived as `<field>_required` — `vat_number_required` here.
|
|
43
43
|
|
|
44
|
+
The storefront satisfies it by writing the value into the cart's `metadata`. When the
|
|
45
|
+
cart is completed, its `metadata` is copied onto the order — onto every order if the
|
|
46
|
+
checkout is split between sellers — so the VAT number is still there after placement as
|
|
47
|
+
`order.metadata['vat_number']`.
|
|
48
|
+
|
|
44
49
|
Pass `applicable:` to scope it. It is checked before `satisfied:`, so a requirement
|
|
45
50
|
that doesn't apply never appears at all:
|
|
46
51
|
|
|
@@ -122,9 +122,26 @@ await client.carts.update(cartId, {
|
|
|
122
122
|
### Complete Checkout
|
|
123
123
|
|
|
124
124
|
```typescript
|
|
125
|
-
|
|
125
|
+
import { isOrderGroup } from '@spree/sdk';
|
|
126
|
+
|
|
127
|
+
const result = await client.carts.complete(cartId, { spreeToken: cart.token });
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Completing a cart usually returns one order. In a [marketplace](../../core-concepts/sellers.md#one-checkout-several-sellers), a cart holding several sellers' goods divides into one order per seller, and the response is the **order group** that ties them together: one purchase, one payment, combined totals, and the per-seller orders in `orders`. Use `isOrderGroup` to tell the two apart:
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
if (isOrderGroup(result)) {
|
|
134
|
+
// One purchase, shown to the customer under the group's number and total.
|
|
135
|
+
console.log(result.number, result.display_total);
|
|
136
|
+
// How it will arrive: one order per seller, each with its own items and delivery.
|
|
137
|
+
result.orders.forEach((order) => console.log(order.number, order.items));
|
|
138
|
+
} else {
|
|
139
|
+
console.log(result.number, result.display_total);
|
|
140
|
+
}
|
|
126
141
|
```
|
|
127
142
|
|
|
143
|
+
A storefront that never sells through more than one seller always gets an order back, but checking costs nothing and keeps the confirmation page working if sellers are added later.
|
|
144
|
+
|
|
128
145
|
### Fulfillments
|
|
129
146
|
|
|
130
147
|
Fulfillments are included in the cart response — there is no separate list endpoint.
|
|
@@ -313,13 +313,15 @@ Replace it by swapping the handler:
|
|
|
313
313
|
|
|
314
314
|
```ruby
|
|
315
315
|
# config/initializers/spree.rb
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
316
|
+
Spree.hooks.unregister('returns.create.validate', 'Spree::Returns::EligibilityValidator')
|
|
317
|
+
Spree.hooks.register('returns.create.validate', 'MyStore::ReturnPolicy')
|
|
318
|
+
|
|
319
|
+
# The same validator guards exchanges — swap it there too if your policy should cover them:
|
|
320
|
+
Spree.hooks.unregister('exchanges.create.validate', 'Spree::Returns::EligibilityValidator')
|
|
321
|
+
Spree.hooks.register('exchanges.create.validate', 'MyStore::ReturnPolicy')
|
|
320
322
|
```
|
|
321
323
|
|
|
322
|
-
|
|
324
|
+
Core registers the default validator before your initializers load, so the swap works at the top level of an initializer.
|
|
323
325
|
|
|
324
326
|
A handler receives the workflow (so it can read `order`, `items`, `created_by`, `order.market`) and calls `workflow.reject!(message)` to veto. Every one of the fifteen transitions has a leading `validate` hook, so the same seam gates approving, receiving and refunding.
|
|
325
327
|
|