Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .changeset/30648-currency-cldr-fraction-digits-spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@objectstack/spec': patch
---

docs(spec): a currency amount's decimal places are named as its currency's CLDR fraction digits, not its ISO 4217 minor unit

Clause-②: no
Metadata-protocol: none

The currency `scale` refusal, the inline grid column's currency `scale` refusal, the `currencyConfig` decimal-places prescription, the `precision` and `scale` describes and the ADR-0087 upgrade-guide entries said "the currency's ISO 4217 minor unit". The platform's digit source is CLDR's fraction digits: `CURRENCY_FRACTION_DIGITS` is a CLDR `currencyData` snapshot, and every display face asks `Intl`, which reads the same data. For sixteen codes the two differ and CLDR's count applies: IQD has 0 (ISO 4217: 3), and AFN, ALL, COP, HUF, IDR, IRR, KPW, LAK, LBP, MGA, MMK, PKR, SOS, SYP and YER have 0 (ISO 4217: 2).

Words only. Nothing is newly accepted or refused, and the remedy is unchanged: delete `scale` on a `currency` field or column. The refusal now reads "the currency's CLDR fraction digits (2 for USD, 0 for JPY, 3 for KWD) decide how the amount displays". A check that matches the old text "ISO 4217 minor unit" in the message no longer matches.
10 changes: 10 additions & 0 deletions .changeset/30648-currency-cldr-fraction-digits-ui-fields.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@object-ui/fields': patch
---

docs(fields): `currencyFractionDigits` is documented as CLDR's fraction digits, not ISO 4217's

Clause-②: no
Metadata-protocol: none

The published declaration of `currencyFractionDigits` said it returns "the number of fraction digits ISO 4217 gives" a currency. It asks `Intl`, which reads CLDR's `currencyData`, so it now says CLDR. For sixteen codes the two differ (IQD 0 where ISO 4217 says 3, and fifteen codes 0 where ISO 4217 says 2), and the function has always answered CLDR's count. Words only: no return value changes.
10 changes: 10 additions & 0 deletions .changeset/30648-currency-cldr-fraction-digits-ui-plugin-form.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@object-ui/plugin-form': patch
---

fix(plugin-form): the warning for a `scale` on a currency inline grid column names the currency's CLDR fraction digits

Clause-②: no
Metadata-protocol: none

The console warning for an inline grid column that renders as `currency` and carries `scale` repeats the spec's refusal, which now says "the currency's CLDR fraction digits (2 for USD, 0 for JPY, 3 for KWD) decide how the cell displays the amount" instead of naming the ISO 4217 minor unit. Words only: the same columns are reported, and the column still renders at its currency's digits.
10 changes: 10 additions & 0 deletions .changeset/30648-currency-cldr-fraction-digits-ui-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@object-ui/types': patch
---

fix(types): the form face's currency `scale` refusal names the currency's CLDR fraction digits, the spec's wording

Clause-②: no
Metadata-protocol: none

`CURRENCY_FIELD_SCALE_REFUSAL` is held equal to `@objectstack/spec`'s currency `scale` refusal, which now says "the currency's CLDR fraction digits (2 for USD, 0 for JPY, 3 for KWD) decide how the amount displays" instead of naming the ISO 4217 minor unit. Words only: the same entries are refused at the same path.
12 changes: 7 additions & 5 deletions content/docs/data-modeling/field-types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,11 @@ what a record-currency amount refuses.
{ name: 'price', label: 'Price', type: 'currency', currencyConfig: { currencyMode: 'fixed', defaultCurrency: 'USD' } }
```

A currency amount's decimal places are its currency's ISO 4217 minor unit
(2 for USD, 0 for JPY, 3 for KWD), not a field setting, and they are declared
nowhere. A `currency` field takes no `scale`, and `currencyConfig` has no
A currency amount's decimal places are its currency's CLDR fraction digits
(2 for USD, 0 for JPY, 3 for KWD; not ISO 4217's minor units, which differ for
sixteen codes such as IQD, 0 in CLDR and 3 in ISO 4217: see
[Currency fields](/docs/data-modeling/currency)), not a field setting, and they
are declared nowhere. A `currency` field takes no `scale`, and `currencyConfig` has no
decimal-places key: publish-time validation refuses `scale` on the field and
`currencyConfig.precision` (removed in `@objectstack/spec` 17.5.0 — no renderer
or runtime ever read it), each with a prescription to delete the key. The
Expand All @@ -245,7 +247,7 @@ amount declares `precision: 18` — and is never compared with the currency.

**In the Console:** a numeric input with the currency's symbol. The read-only display, the
grid cell, the input's `step` and the rounding applied when the input loses focus all use the
currency's minor unit, so a JPY amount shows no decimals and a KWD amount shows three. With no
currency's CLDR fraction digits, so a JPY amount shows no decimals and a KWD amount shows three. With no
currency resolved at all, an amount shows two decimals. A `record`-mode amount resolves only
its own record's code, never the tenant default. A field-level `currency` key is
refused: the currency is `currencyConfig`. The input is a native number box; see
Expand Down Expand Up @@ -593,7 +595,7 @@ the parent's form edits the children as rows of a table:
- **Booleans.** A derived `boolean` or `toggle` child field becomes a `select` cell storing
`'true'` / `'false'`, labelled in the session language.
- **Currency.** A `currency` cell shows the resolved currency's symbol, and decimals of that
currency's minor unit; `prefix` replaces the symbol only.
currency's CLDR fraction digits; `prefix` replaces the symbol only.
- **Order.** When the columns are derived and the child object has a field named `position`, `sort_order`, `sequence`,
`line_no`, `line_number` or `sort`, the grid stamps each row's index into it whenever a row is
added, removed, duplicated or dragged, so the order is saved with the rows.
Expand Down
2 changes: 1 addition & 1 deletion content/docs/data-modeling/validation-rules.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ These properties apply to **all** field types and are validated by the base `Fie
| `currencyConfig.currencyField` | `string` | — | Required under `record` and refused under the other two modes: a `text` field of the same object declaring `valueDomain: 'iso_4217_currency'` (the object refuses a pointer at anything else). A write that leaves a record-mode amount holding a value beside a blank code is refused, `ERR_CURRENCY_CODE_REQUIRED` / 400 |
| `currencyConfig.homeAmount` | `object` | — | Optional under `record` and refused under the other two modes: the stored home-currency projection, three pointers into the same object, all required — `field` (a `dynamic`-mode `currency` field, `readonly: true`), `rateDate` (a `date` or `datetime` field, the document date that picks the rate) and `rateField` (a `number` field, `readonly: true`). See [Declaring the home amount](/docs/data-modeling/currency#declaring-the-home-amount) |

**Default constraints:** Stored as a **bare number** (a finite numeric scalar — `valueSchemaFor` routes `currency` to `z.number().finite()`); there is no `{ value, currency }` envelope on the value path. The amount never carries its currency code: under `dynamic` and `fixed` the code is field configuration, carried by `currencyConfig` above, and under `record` it is the value of the record's own code field, an ordinary `text` column judged by its `valueDomain` ([Currency fields](/docs/data-modeling/currency)). Decimal places are the currency's ISO 4217 minor unit (2 for USD, 0 for JPY, 3 for KWD) and are declared nowhere — `currencyConfig` has no decimal-places key (`currencyConfig.precision` is refused, with a prescription to delete it), and the field-level `precision` is the total digit count, never compared with the currency.
**Default constraints:** Stored as a **bare number** (a finite numeric scalar — `valueSchemaFor` routes `currency` to `z.number().finite()`); there is no `{ value, currency }` envelope on the value path. The amount never carries its currency code: under `dynamic` and `fixed` the code is field configuration, carried by `currencyConfig` above, and under `record` it is the value of the record's own code field, an ordinary `text` column judged by its `valueDomain` ([Currency fields](/docs/data-modeling/currency)). Decimal places are the currency's CLDR fraction digits (2 for USD, 0 for JPY, 3 for KWD; not ISO 4217's minor units, which differ for sixteen codes such as IQD) and are declared nowhere — `currencyConfig` has no decimal-places key (`currencyConfig.precision` is refused, with a prescription to delete it), and the field-level `precision` is the total digit count, never compared with the currency.

### `percent`

Expand Down
2 changes: 1 addition & 1 deletion content/docs/protocol/objectql/schema.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ fields:
| `valueDomain` | `string` | `text` | Standard the written value must belong to: `iana_time_zone`, `iso_4217_currency` or `iso_3166_alpha2` (the closed vocabulary shared with settings specifiers). A `record`-mode `currency` amount's code field is a `text` field declaring `iso_4217_currency` ([Currency fields](/docs/data-modeling/currency)). |
| `min` | `number` | `number`, `currency` | Minimum numeric value. |
| `max` | `number` | `number`, `currency` | Maximum numeric value. |
| `scale` | `number` | `number`, `percent`, `rating`, `slider` | Decimal places, enforced on writes. Refused on `currency` — delete it there: a currency amount's decimal places are its currency's, so its ISO 4217 minor unit decides the display. |
| `scale` | `number` | `number`, `percent`, `rating`, `slider` | Decimal places, enforced on writes. Refused on `currency` — delete it there: a currency amount's decimal places are its currency's, so its CLDR fraction digits decide the display. |
| `precision` | `number` | `number`, `currency` | Total digits (including scale). |
| `currencyConfig` | `object` | `currency` | Where the amount's currency comes from: `currencyMode` `dynamic` (the tenant default, the default), `fixed` (with `defaultCurrency`) or `record` (with `currencyField`, the sibling code field, and optionally `homeAmount`, the stored home-currency projection: `field` a `dynamic`-mode `currency` field, `rateDate` a `date` or `datetime` field, `rateField` a `number` field — see [Declaring the home amount](/docs/data-modeling/currency#declaring-the-home-amount)). |
| `options` | `array` | `select`, `multiselect` | List of valid values. |
Expand Down
4 changes: 2 additions & 2 deletions content/docs/protocol/objectql/types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ revenue:
# - Store a bare number, never a currency code beside it: it shows in
# the tenant default currency (plain if none is set), one fixed on the
# field, or each record's code in a declared sibling field, at that
# currency's ISO 4217 decimal places
# currency's CLDR fraction digits
# - UI shows currency symbol
# - Validate numeric precision
# - Format for display ($1,234.56)
Expand Down Expand Up @@ -340,7 +340,7 @@ been removed from the spec.
record's code is judged by its field's `valueDomain: iso_4217_currency`, so
only ISO 4217 codes pass there
- No decimal-places setting: an amount's decimal places are its currency's
ISO 4217 minor unit. The field-level `precision` is the amount's **total**
CLDR fraction digits (not ISO 4217's minor units). The field-level `precision` is the amount's **total**
digit count (a DECIMAL(18,2) amount declares `precision: 18`), refused on
write when exceeded, with the amount's written decimals counted in it

Expand Down
Loading
Loading