@spree/docs 0.1.303 → 0.1.305

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.
@@ -96,6 +96,23 @@ This hash will contain the value for every preference that has been defined for
96
96
 
97
97
  `preferences` never holds secrets — see [Secret preferences](#secret-preferences).
98
98
 
99
+ ## Money preferences
100
+
101
+ Declare an amount of money with the `:money` type, and a rate or a measure (a percentage, a weight) with `:decimal`:
102
+
103
+ ```ruby server/app/models/spree/calculator/handling_fee.rb
104
+ module Spree
105
+ class Calculator::HandlingFee < Spree::Calculator
106
+ preference :amount, :money, default: 0
107
+ preference :currency, :string, default: -> { Spree::Store.default.default_currency }
108
+ preference :surcharge_percent, :decimal, default: 0
109
+ end
110
+ end
111
+ ```
112
+
113
+ Both are read back as a `BigDecimal` and take a number or a decimal string (`"4.50"`); text such as `"4,50"` is refused rather than misread. The difference is on the [API](../../api-reference/admin-api/monetary-amounts.md): a `:money` preference is written with the decimals of the record's `currency` preference (`"4.50"`, or `"450"` in yen), and the dashboard shows it with that currency's symbol. A money preference on a record with no currency, such as a rule matching an order total in any currency, keeps its exact decimal.
114
+
115
+
99
116
  ## Secret preferences
100
117
 
101
118
  Declare API keys, signing secrets and other credentials with the `:password` type:
@@ -637,7 +637,7 @@ Also note:
637
637
 
638
638
  - **Ransack:** `default_price` is no longer a searchable association on `Variant`; query `prices` instead.
639
639
  - **Prices in permitted params:** the dead `:price` and `:compare_at_price` entries are gone. Prices were already written as nested `prices: [{ amount:, currency: }]` under variants — the top-level keys had no writer behind them. (`Spree::PermittedAttributes` itself is removed in 6.0 — see below.)
640
- - Localized number parsing still happens: `Spree::Price#amount=` runs `Spree::LocalizedNumber.parse`, so `set_price(currency, '1,599.99')` works as `price=` did.
640
+ - Prices are written as numbers or canonical decimal strings: `set_price(currency, '1599.99')`. A localized string such as `'1,599.99'` raises `Spree::Money::InvalidFormat` (see [Money](#money)).
641
641
  - The variant validation that inferred a missing price from the product's default variant is gone. Set prices explicitly (the product and variant factories already do).
642
642
 
643
643
  ### `Spree::PermittedAttributes` is removed
@@ -796,6 +796,32 @@ Other changes that come with it:
796
796
  - **Alba moved into `spree_core`**, with its configuration, so core's staff emails render in installations without `spree_api`.
797
797
  - **Your own mailers keep working.** A mailer that inherits `Spree::BaseMailer` and calls `mail` with its own ERB views is wrapped in the new email layout, and the `spree/shared/mailer_hero` and `mailer_button` partials remain for its views. See [Your own mailers](../customization/emails.md#your-own-mailers).
798
798
 
799
+ ## Money
800
+
801
+ - **Numbers are no longer parsed by locale.** Price, variant, payment, refund, store credit, gift card, discount and fee amounts take a number or a canonical decimal string (`"1234.56"`); any other text raises `Spree::Money::InvalidFormat`, which the API answers with `invalid_money_format`. Before 6.0 they were re-read under the request's language, so a store whose language writes a comma decimal (Dutch, German, French) saved the dashboard's `49.50` as 4950, and an unchanged price grew tenfold on each save. Send canonical decimal strings (`"1234.56"`) and convert localized input in the client. `Spree::LocalizedNumber` still works with a warning until 6.1. If your prices were saved in a comma-decimal store before upgrading, check them.
802
+ - **Rounding follows the currency.** Taxes, percentage discounts, promotion splits and shipping markups round to the currency's own decimal places from the ISO 4217 table: whole yen, three decimals for dinar. Two-decimal currencies are unchanged. Open carts in other currencies may change by less than one minor unit the next time they are recalculated. Placed orders do not change. Spree now gives the Hungarian forint two decimal places, as ISO 4217 does.
803
+ - **Money on the API is written to each currency's decimals.** Every amount in the Store, Admin and Seller APIs, and so in webhook payloads and email variables, is a decimal string with exactly its currency's decimal places: `"10.00"` (was `"10.0"`), `"1000"` in yen (was `"1000.0"`), `"1.500"` in dinar. Unit prices keep up to four decimals. Fields that were JSON numbers are now strings: `cart.order_minimum` and `order_minimum_shortfall`, the product filter price range `min`/`max`, report money metrics and percentages, and the store's `preferred_default_minimum_payout_amount` and `preferred_default_commission_tax_rate`. Clients comparing these strings, or parsing them as numbers, should switch to exact decimal arithmetic; the SDKs export `sumMoney`, `subtractMoney`, `multiplyMoney`, `compareMoney` and `isZeroMoney`.
804
+ - **Admin and Seller writes refuse JSON numbers for money.** Amounts and rates, including those inside `preferences`, must be canonical decimal strings (`"19.99"`). A number, a localized or grouped string, or more decimals than the field holds is answered with `422` and `invalid_money_format`, naming the field.
805
+ - **Amounts may not carry more decimals than they can keep.** Now that the columns hold four decimals, the database no longer rounds away a fraction of a cent, so a payment, refund, store credit, gift card, fee or discount with more decimals than its currency has (`10.0049` dollars) fails validation with `too_many_decimals`. Unit prices and cost prices allow four, tax rates five decimals of the fraction (`rate_percent` `"7.125"`, not `"7.1255"`), and price list percentages three. Round in your own code before saving. A manual order discount's `value` and a commission rate's `value` are read as strictly as other money fields.
806
+ - **The Admin and Seller APIs no longer return `display_*` money fields.** Responses carry the amount (`"29.99"`) with its currency, and the client formats it in the reader's own language. Before 6.0 the server formatted a copy in the request's language, which could disagree with the editable amount beside it. Format with `Intl.NumberFormat` or your platform's equivalent. The Store API, webhook payloads and email templates keep their `display_*` fields, and labels such as `display_name` are unchanged.
807
+ - **Money preferences have their own type.** Calculator, rule and store preferences holding an amount (`amount`, `first_item`, `minimal_amount`, `amount_min`, `min_amount`, `default_minimum_payout_amount` and the like) are declared `:money` instead of `:decimal`, report `money` in `preference_schema`, and are written with the decimals of the calculator's currency (`"12.50"` rather than `"12.5"`). Declare your own extensions' amounts with `:money` so the dashboard shows their currency. A `:decimal` or `:money` preference now refuses text such as `"1,599.99"` instead of reading it as 1.
808
+ - **Rates are decimal strings, and tax rates are renamed.** Rates and percentages read and write as strings without trailing zeros. A tax rate's `amount` (a fraction) is now `rate`, and `amount_percentage` is `rate_percent`; `Spree::TaxRate#amount_percentage` keeps working with a warning until 6.1.
809
+ - **`amount_in_cents` and `compare_at_amount_in_cents` are removed** from prices and price history. Read `amount`, and each currency's `decimal_places` (new on `GET /api/v3/store/currencies`) if you need minor units.
810
+ - **Money columns widen to `decimal(19,4)`.** They now hold a Kuwaiti dinar's third decimal, unit prices below a cent (`0.0125`), and very large amounts in currencies like the Vietnamese dong. No stored value changes. Totals, payments and refunds are still rounded to the currency's decimals; only unit prices (`price`, `compare_at_amount`, `cost_price`, `unit_cost`) keep up to four. The migration rewrites each money table while it runs, which locks `spree_orders`, `spree_line_items` and `spree_adjustments` for as long as that takes. If you cannot take that lock, widen those columns online first (add a `decimal(19,4)` shadow column, backfill it in batches, swap it in), and the migration skips any column already at `(19,4)`. Extensions with their own money tables, such as `spree_stripe_payment_intents` from the standalone Stripe gem, should widen theirs the same way.
811
+ - **Payment gateways receive the amount with its currency.** `authorize`, `purchase`, `capture` and `credit` are called with a `Spree::Money` (amount and currency) instead of an integer in hundredths, which was wrong for yen and dinar. A gateway opts in with `self.accepts_money_amounts = true` and converts the amount to its provider's unit (Stripe's rules live in `SpreeStripe::Units`). A gateway that has not opted in still receives hundredths, with a deprecation warning, until 6.1. `Spree.payment_capture_workflow.call(amount:)` takes the amount in the currency's own units; an Integer is still read as hundredths, with a warning.
812
+ - **Stripe refuses amounts it cannot take.** Stripe charges three-decimal currencies (Bahraini, Jordanian, Kuwaiti and Omani dinar, Tunisian dinar) only in steps of 0.010, and pays out Hungarian forint and New Taiwan dollars only in whole units. `spree_stripe` now raises a gateway error naming the rule, rather than rounding to a sum other than the one the order records.
813
+ - **Capture records in yen and dinar written before 6.0 may be wrong.** A capture in a currency without two decimals could be recorded in the wrong unit: 100 times too much in yen, a tenth in dinar. New captures are recorded exactly. To list the old records, writing nothing, run:
814
+
815
+
816
+ ```bash Spree CLI (Docker)
817
+ spree rake spree:money:audit_capture_events
818
+ ```
819
+
820
+ ```bash Without Spree CLI
821
+ bundle exec rake spree:money:audit_capture_events
822
+ ```
823
+
824
+
799
825
  ## Translations ship with Spree
800
826
 
801
827
  Spree's translations for emails, API messages and validation messages are now part of Spree itself, in 43 languages besides English. Regional English (`en-GB` and the like) now falls back to `en`. A key a language does not translate yet falls back to English, unless your app configured its own `config.i18n.fallbacks`. See [Translations](../core-concepts/translations.md#translating-the-interface).
@@ -855,6 +881,10 @@ Before 6.0 a cart was an incomplete order, so extensions written for 5.x (paymen
855
881
  | `.with_metafield_key`, `.with_metafield_key_value` | `.with_custom_field_key`, `.with_custom_field_key_value` |
856
882
  | `Spree.metafields` | `Spree.custom_fields` |
857
883
  | `Spree.t`, `Spree.translate` | `I18n.t` with the full key, e.g. `I18n.t('spree.free')` |
884
+ | `Spree::LocalizedNumber.parse` | `BigDecimal(value)` on a canonical decimal string; Spree no longer parses numbers by locale |
885
+ | `Spree::TaxRate#amount_percentage`, `#amount_percentage=` | `#rate_percent`, `#rate_percent=` (`#rate` is the fraction) |
886
+ | Gateway methods receiving an integer amount in hundredths | `self.accepts_money_amounts = true` and a `Spree::Money` argument |
887
+ | `Spree.payment_capture_workflow.call(amount: Integer)` (hundredths) | `amount:` as a `BigDecimal` in the currency's own units |
858
888
  | `CustomFieldDefinition#name`, `#metafield_type`, `#display_on` | `#label`, `#field_type`, `#storefront_visible` (columns renamed) |
859
889
  | `Spree::SearchProvider::Meilisearch` | `SpreeMeilisearch::SearchProvider` (moved to the `spree_meilisearch` gem) |
860
890
  | `Spree::SearchProvider::ProductPresenter` | `SpreeMeilisearch::ProductPresenter` (moved to the `spree_meilisearch` gem) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spree/docs",
3
- "version": "0.1.303",
3
+ "version": "0.1.305",
4
4
  "description": "Spree Commerce developer documentation for AI agents and local reference",
5
5
  "type": "module",
6
6
  "license": "CC-BY-4.0",