@spree/docs 0.1.286 → 0.1.287

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.
@@ -12427,6 +12427,14 @@ components:
12427
12427
  type: string
12428
12428
  paid_amount:
12429
12429
  type: string
12430
+ pre_tax_amount:
12431
+ type: string
12432
+ included_tax_total:
12433
+ type: string
12434
+ additional_tax_total:
12435
+ type: string
12436
+ tax_total:
12437
+ type: string
12430
12438
  display_refund_amount:
12431
12439
  type: string
12432
12440
  variant_id:
@@ -12447,6 +12455,10 @@ components:
12447
12455
  - description
12448
12456
  - refund_amount
12449
12457
  - paid_amount
12458
+ - pre_tax_amount
12459
+ - included_tax_total
12460
+ - additional_tax_total
12461
+ - tax_total
12450
12462
  - display_refund_amount
12451
12463
  - variant_id
12452
12464
  - replacement_variant_id
@@ -13246,6 +13258,7 @@ components:
13246
13258
  - cod
13247
13259
  - payment
13248
13260
  - duty
13261
+ - exchange
13249
13262
  - type: string
13250
13263
  description: What sort of charge this is. `duty` is a customs duty on a
13251
13264
  cross-border order and is not taxed; the other kinds are. Extensions may
@@ -15019,6 +15032,18 @@ components:
15019
15032
  type: string
15020
15033
  display_pre_tax_amount:
15021
15034
  type: string
15035
+ included_tax_total:
15036
+ type: string
15037
+ additional_tax_total:
15038
+ type: string
15039
+ tax_total:
15040
+ type: string
15041
+ display_tax_total:
15042
+ type: string
15043
+ refund_amount:
15044
+ type: string
15045
+ display_refund_amount:
15046
+ type: string
15022
15047
  variant_id:
15023
15048
  type: string
15024
15049
  nullable: true
@@ -15037,6 +15062,12 @@ components:
15037
15062
  - resellable
15038
15063
  - pre_tax_amount
15039
15064
  - display_pre_tax_amount
15065
+ - included_tax_total
15066
+ - additional_tax_total
15067
+ - tax_total
15068
+ - display_tax_total
15069
+ - refund_amount
15070
+ - display_refund_amount
15040
15071
  - variant_id
15041
15072
  - line_item_id
15042
15073
  - fulfillment_item_id
@@ -15084,6 +15115,10 @@ components:
15084
15115
  type: string
15085
15116
  display_refund_total:
15086
15117
  type: string
15118
+ refund_tax_total:
15119
+ type: string
15120
+ display_refund_tax_total:
15121
+ type: string
15087
15122
  approved_at:
15088
15123
  type: string
15089
15124
  nullable: true
@@ -15110,6 +15145,8 @@ components:
15110
15145
  - reason_id
15111
15146
  - refund_total
15112
15147
  - display_refund_total
15148
+ - refund_tax_total
15149
+ - display_refund_tax_total
15113
15150
  - approved_at
15114
15151
  - received_at
15115
15152
  - refunded_at
@@ -15391,6 +15428,8 @@ components:
15391
15428
  type: string
15392
15429
  included:
15393
15430
  type: boolean
15431
+ credit:
15432
+ type: boolean
15394
15433
  rate:
15395
15434
  type: string
15396
15435
  tax_rate_id:
@@ -15405,6 +15444,15 @@ components:
15405
15444
  fee_id:
15406
15445
  type: string
15407
15446
  nullable: true
15447
+ return_line_item_id:
15448
+ type: string
15449
+ nullable: true
15450
+ claim_line_item_id:
15451
+ type: string
15452
+ nullable: true
15453
+ exchange_line_item_id:
15454
+ type: string
15455
+ nullable: true
15408
15456
  amount:
15409
15457
  type: string
15410
15458
  nullable: true
@@ -15415,11 +15463,15 @@ components:
15415
15463
  - id
15416
15464
  - label
15417
15465
  - included
15466
+ - credit
15418
15467
  - rate
15419
15468
  - tax_rate_id
15420
15469
  - line_item_id
15421
15470
  - fulfillment_id
15422
15471
  - fee_id
15472
+ - return_line_item_id
15473
+ - claim_line_item_id
15474
+ - exchange_line_item_id
15423
15475
  - amount
15424
15476
  - display_amount
15425
15477
  x-typelizer: true
@@ -44,6 +44,7 @@ When neither ID is set, the fee applies to the whole order.
44
44
  | `cod` | Cash on delivery |
45
45
  | `payment` | A payment method surcharge |
46
46
  | `duty` | Customs duty — see [below](#customs-duties) |
47
+ | `exchange` | What a customer owes when an [exchange](returns-exchanges-claims.md#settling-the-difference)'s replacement costs more. Spree adds it; you don't |
47
48
 
48
49
  The list is open — an extension can add its own kind.
49
50
 
@@ -129,6 +129,10 @@ the period of the original order. A report over a past range can therefore
129
129
  change after the fact, which is the conventional treatment and the only one an
130
130
  open accounting period can produce.
131
131
 
132
+ A refund from a return, claim or exchange gives tax back with the goods, so it
133
+ is split: the goods come off `returns` and `net_sales`, and the tax comes off
134
+ `taxes`. `total_sales` loses the whole refund.
135
+
132
136
  `cost_of_goods`, `gross_profit` and `gross_margin` read the line item's
133
137
  `cost_price`. That column is nullable, so a variant with no cost contributes
134
138
  zero and margin over an incompletely-costed catalogue reads high.
@@ -116,6 +116,14 @@ Receiving takes the quantities the warehouse actually counted, because partial a
116
116
 
117
117
  Leave `items` out to receive everything as requested. Refunds default to whatever the return is still owed, and can go back to the original payment method or to store credit. A returned item is worth what the customer paid for it after discounts, not its list price, so a free gift sent back refunds nothing. Refunding a return that is owed nothing completes it with no money moved and no refund email; an amount of zero is refused on any return the customer is still owed money on.
118
118
 
119
+ ### Tax on returns
120
+
121
+ A return gives back the tax the customer paid on what came back. A $25.00 shirt sold with 10% tax added on top refunds $27.50, and on a store whose prices include VAT the VAT inside the price goes back with it. Delivery and its tax are not refunded.
122
+
123
+ Each return line shows its worth the way an order line does: `pre_tax_amount` before tax, `included_tax_total` and `additional_tax_total` beside it, and `refund_amount` with the tax included. The return's `refund_tax_total` says how much of `refund_total` is tax, and `expand=return_line_items.tax_lines` (Admin API) lists the tax given back rate by rate.
124
+
125
+ The store's [tax provider](taxes.md) works this out when the return opens, and again just before the money goes back, for the units the warehouse counted. Refunding less than the return is worth — keeping a restocking fee, say — gives the tax back in the same proportion as the goods. If the tax service cannot answer, the return is not opened (or not refunded) and the customer can try again. Claims and exchanges follow the same rules.
126
+
119
127
  ### Where the goods come back to
120
128
 
121
129
  A return is received at a stock location. By default that is wherever the goods
@@ -193,7 +201,7 @@ A replacement creates a new [fulfillment](fulfillments.md) on the original order
193
201
 
194
202
  The replacement is filed under the order line it replaces, but it doesn't count toward that line's quantity. Editing the line later, from a claim or an [exchange](#exchanges), adds or removes only the goods the customer paid for and leaves the replacement where it is.
195
203
 
196
- A claim never refunds more than the customer paid for the claimed items after discounts. Each claim line reports that ceiling as `paid_amount`.
204
+ A claim never refunds more than the customer paid for the claimed items after discounts, tax included. Each claim line reports that ceiling as `paid_amount`, and the `refund_amount` you enter for a line includes its tax. The tax goes back in proportion to the money: refunding half of what a line is worth gives back half its tax, and resolving with a replacement alone gives none back.
197
205
 
198
206
  ## Exchanges
199
207
 
@@ -218,6 +226,16 @@ curl -X PATCH 'https://api.mystore.com/api/v3/admin/orders/or_xxx/exchanges/exch
218
226
  ```
219
227
 
220
228
 
229
+ ### Settling the difference
230
+
231
+ An exchange credits what came back and sells the replacement, each with its tax:
232
+
233
+ - `original_price` is what the customer paid for the items coming back, after discounts and with their tax.
234
+ - `new_variant_price` is the replacement, with its own tax. It keeps the deal the customer had: an item bought at 10% off is replaced at 10% off its price, so swapping a size costs nothing.
235
+ - `price_difference` is the second less the first.
236
+
237
+ When you fulfill, a cheaper replacement refunds the difference, to store credit or the original payment. A dearer one adds the difference to the order as an `exchange` [fee](fees.md), so the order shows a balance due. Spree never charges a stored card for it; take the payment through the order's [payments](payments.md).
238
+
221
239
  ## Reporting
222
240
 
223
241
  Because each one is its own record, you can query them directly:
@@ -325,6 +325,8 @@ The amount is payment-source-agnostic — store credit and gift cards are how th
325
325
 
326
326
  A refund never edits an earning. `refund.created` writes a second row of kind `refund_reversal` against the same order, so what a seller has earned is always the sum of their transfers, and a reversal that lands after a payout closed falls into the next period rather than rewriting a settlement that already happened.
327
327
 
328
+ A reversal takes back only the seller's share of what was refunded. When a return or claim refunds goods and their tax, the goods come back less the commission charged on them; the tax comes back from the seller only if the seller collected it, and stays with the marketplace when the marketplace remits it.
329
+
328
330
  ### Payouts — what was sent
329
331
 
330
332
  On schedule, a seller's confirmed, unsettled earnings are batched into one `Spree::SellerPayout` per currency and handed to the provider. A payout names exactly which transfers it settled, which is what a seller needs to reconcile a deposit.
@@ -148,6 +148,8 @@ Whatever works out the tax, the record is the same: a tax line per charge, sayin
148
148
  | `included` | Whether the tax was already inside the displayed price |
149
149
  | `amount` / `display_amount` | The tax charged |
150
150
  | `line_item_id` / `fulfillment_id` / `fee_id` | What was taxed — exactly one is set |
151
+ | `return_line_item_id` / `claim_line_item_id` / `exchange_line_item_id` | After the sale: the return, claim or exchange line the tax belongs to |
152
+ | `credit` | `true` for tax given back on a return, claim or exchange |
151
153
 
152
154
 
153
155
  ```typescript Admin SDK
@@ -166,6 +168,10 @@ Each line also keeps its own copy of the rate and label. If someone edits that t
166
168
 
167
169
  You never create tax lines yourself; they're written whenever the total is worked out.
168
170
 
171
+ ### Tax given back
172
+
173
+ When a customer returns something, the tax they paid on it goes back with the money. That tax is recorded as tax lines too, marked `credit`, on the [return, claim or exchange](returns-exchanges-claims.md) line rather than the order line. Each one names the sale's tax line it gives back (`original_tax_line_id`, Admin API), keeps that line's rate and label, and covers only the units that came back. They never change the order's own tax totals, and the order's tax lines list above shows only what was charged.
174
+
169
175
  ## When tax is worked out
170
176
 
171
177
  Tax is recalculated whenever the answer could have changed — an item added, an address entered, a delivery option chosen. Every one of those requests returns the updated cart, so a storefront never needs a separate "refresh the tax" call.
@@ -204,6 +210,27 @@ A provider declares up front what it cannot do — no US local tax, no reverse c
204
210
 
205
211
  Whichever provider is in use, the result is the same: tax lines on the order, in the same shape. Your storefront code doesn't change.
206
212
 
213
+ The provider also decides the tax given back on returns, claims and exchanges, and the refund pays exactly what it answers. Spree's own rates give back each returned unit's share of the tax the sale actually charged, so the customer gets back what they paid even if a rate has been edited since. An external service may calculate it itself instead, for example at the rates in force on the day of the sale. If it cannot be reached, the return is refused until it can, rather than refunding tax nobody worked out.
214
+
215
+ If you are writing a provider, these are the calls Spree makes after the sale:
216
+
217
+ | Method | When | What it does |
218
+ |---|---|---|
219
+ | `estimate_refund` | A return, claim or exchange opens, and again before its money moves | Writes the credit tax lines the refund will carry |
220
+ | `estimate_replacement` | An exchange opens and is fulfilled | Taxes the replacement as a new sale |
221
+ | `refund` | After the money has moved | Files the credit with your service — no more than the credit lines hold |
222
+ | `commit_replacement` | After an exchange is fulfilled | Files the replacement sale |
223
+
224
+ `estimate_refund` and `estimate_replacement` have no default — a provider without them cannot open a return, claim or exchange. To give back exactly what the sale charged, as Spree's own rates do, answer `estimate_refund` with `Spree::TaxProvider::RecordedShare`:
225
+
226
+ ```ruby server/app/models/my_app/tax_provider.rb
227
+ def estimate_refund(order, items, amounts: nil, tax_date: nil)
228
+ Spree::TaxProvider::RecordedShare.new(order: order, items: items, amounts: amounts).call
229
+ end
230
+ ```
231
+
232
+ `refund` and `commit_replacement` are optional: by default they do nothing, which suits a service that keeps no record of sales.
233
+
207
234
  ## Tax-exempt customers
208
235
 
209
236
  Business customers are often exempt, and the paperwork is real. Spree records a customer's or company's **tax identifier** — a VAT number, an ABN — and can validate it. Companies can also hold exemption certificates, scoped to the country or state that issued them.
@@ -214,5 +241,6 @@ Exemption is decided when tax is worked out, not stored as a flag on the custome
214
241
 
215
242
  - [Order totals](order-totals.md) — how tax rolls into what a customer pays
216
243
  - [Markets](markets.md) — where tax treatment and provider are chosen
244
+ - [Returns, exchanges and claims](returns-exchanges-claims.md) — how tax goes back with a refund
217
245
  - [Addresses](addresses.md) — what determines the rate
218
246
  - [Companies](companies.md) — B2B tax identifiers and exemptions
@@ -366,7 +366,7 @@ A handler receives the workflow (so it can read `order`, `items`, `created_by`,
366
366
  ### Other behavioral changes
367
367
 
368
368
  - **`Return#refunded_total` counts store credits.** Store credit is a separate ledger and never creates a `Spree::Refund` row, so the old sum reported zero for a store-credit refund.
369
- - **`Order#outstanding_balance` dropped its reimbursement term** rather than replacing it — refunds already net out of `payment_total`, so that term was double-counting.
369
+ - **`Order#outstanding_balance` replaced its reimbursement term** with refunds made for returns, claims and exchanges (`returned_items_refund_total`). Those refunds net out of `payment_total`, and adding them back is what keeps a refunded return from reading as a balance due. A refund made for nothing in return still reads as owed, as in 5.x.
370
370
  - **The reimbursement email is now `Spree::ReturnMailer#refunded_email`**, sent on `return.refunded` (in the optional `spree_emails` gem, like the other transactional mail).
371
371
  - **`Refund#originator`** points at the new records.
372
372
  - Events are `return.requested` / `.approved` / `.received` / `.refunded` / `.canceled`, and the matching `exchange.*` and `claim.*` families.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spree/docs",
3
- "version": "0.1.286",
3
+ "version": "0.1.287",
4
4
  "description": "Spree Commerce developer documentation for AI agents and local reference",
5
5
  "type": "module",
6
6
  "license": "CC-BY-4.0",