decimal precision constrained
This commit is contained in:
32
Cargo.lock
generated
32
Cargo.lock
generated
@@ -207,7 +207,7 @@ dependencies = [
|
|||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
"x11rb",
|
"x11rb",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1161,7 +1161,7 @@ checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "client"
|
name = "client"
|
||||||
version = "0.8.46"
|
version = "0.8.48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -1282,7 +1282,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "common"
|
name = "common"
|
||||||
version = "0.8.46"
|
version = "0.8.48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"prost",
|
"prost",
|
||||||
"prost-build",
|
"prost-build",
|
||||||
@@ -2571,7 +2571,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"option-ext",
|
"option-ext",
|
||||||
"redox_users",
|
"redox_users",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2735,7 +2735,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4730,7 +4730,7 @@ version = "0.50.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5906,7 +5906,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6590,7 +6590,7 @@ dependencies = [
|
|||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6647,7 +6647,7 @@ dependencies = [
|
|||||||
"security-framework",
|
"security-framework",
|
||||||
"security-framework-sys",
|
"security-framework-sys",
|
||||||
"webpki-root-certs",
|
"webpki-root-certs",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6754,7 +6754,7 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "search"
|
name = "search"
|
||||||
version = "0.8.46"
|
version = "0.8.48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"common",
|
"common",
|
||||||
@@ -6942,7 +6942,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "server"
|
name = "server"
|
||||||
version = "0.8.46"
|
version = "0.8.48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bcrypt",
|
"bcrypt",
|
||||||
@@ -7931,7 +7931,7 @@ dependencies = [
|
|||||||
"getrandom 0.4.2",
|
"getrandom 0.4.2",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -8534,7 +8534,7 @@ checksum = "e78122066b0cb818b8afd08f7ed22f7fdbc3e90815035726f0840d0d26c0747a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tui-canvas"
|
name = "tui-canvas"
|
||||||
version = "0.8.46"
|
version = "0.8.48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arboard",
|
"arboard",
|
||||||
@@ -8565,7 +8565,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tui-canvas-validation-core"
|
name = "tui-canvas-validation-core"
|
||||||
version = "0.8.46"
|
version = "0.8.48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -8575,7 +8575,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tui-pages"
|
name = "tui-pages"
|
||||||
version = "0.8.46"
|
version = "0.8.48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"criterion",
|
"criterion",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
@@ -9286,7 +9286,7 @@ version = "0.1.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -3,6 +3,10 @@
|
|||||||
TUI accounting system. Client/server application with two extracted open-source
|
TUI accounting system. Client/server application with two extracted open-source
|
||||||
libraries.
|
libraries.
|
||||||
|
|
||||||
|
Column designers default to unconstrained exact decimals. The legacy-compatible
|
||||||
|
fixed-scale form is an explicit advanced option; see
|
||||||
|
[`docs/fixed-scale-decimal.md`](docs/fixed-scale-decimal.md).
|
||||||
|
|
||||||
## Crates
|
## Crates
|
||||||
|
|
||||||
| Crate | What | Published |
|
| Crate | What | Published |
|
||||||
|
|||||||
2
client
2
client
Submodule client updated: fc712732df...1e0b6f9ede
26
docs/fixed-scale-decimal.md
Normal file
26
docs/fixed-scale-decimal.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Decimal column policy
|
||||||
|
|
||||||
|
Use the bare `numeric` column type for ordinary exact base-10 values. It stores
|
||||||
|
the value without a schema-defined decimal-place limit and is the recommended
|
||||||
|
choice for quantities, percentages, rates, ratios and measurements. Use
|
||||||
|
`money` for currency amounts; its currency and rounding policy are separate
|
||||||
|
from this document.
|
||||||
|
|
||||||
|
`decimal(p,s)` is an advanced, opt-in compatibility type for strict external
|
||||||
|
data contracts. `p` limits the total digits and `s` limits the fractional
|
||||||
|
digits. It is hidden from the normal table-designer type list until fixed-scale
|
||||||
|
decimal is enabled for that editing session.
|
||||||
|
|
||||||
|
Fixed scale is intentionally strict:
|
||||||
|
|
||||||
|
- API input outside the declared precision or scale is rejected, never
|
||||||
|
silently rounded by PostgreSQL.
|
||||||
|
- A table script targeting a fixed-scale column must round explicitly before
|
||||||
|
returning its value.
|
||||||
|
- A fixed-scale type cannot be changed through the table editor after the
|
||||||
|
table contains data.
|
||||||
|
- Display precision, allowed increments, minimums and maximums are business
|
||||||
|
validation concerns; `decimal(p,s)` is not a substitute for them.
|
||||||
|
|
||||||
|
Existing fixed-scale columns remain supported. The opt-in changes discovery,
|
||||||
|
not storage compatibility.
|
||||||
2
server
2
server
Submodule server updated: 0fd5a16ba6...cf752c7ee9
@@ -212,6 +212,15 @@ td-precision = Přesnost
|
|||||||
td-precision-hint = Celkový počet uložených číslic, alespoň 1.
|
td-precision-hint = Celkový počet uložených číslic, alespoň 1.
|
||||||
td-scale = Desetinná místa
|
td-scale = Desetinná místa
|
||||||
td-scale-hint = Číslice za desetinnou čárkou, nejvýše tolik jako přesnost.
|
td-scale-hint = Číslice za desetinnou čárkou, nejvýše tolik jako přesnost.
|
||||||
|
td-fixed-decimal-access = Pokročilé číselné typy
|
||||||
|
td-fixed-decimal-disabled = Pouze doporučené typy
|
||||||
|
td-fixed-decimal-enabled = Povolit desetinné číslo s pevným měřítkem
|
||||||
|
td-fixed-decimal-access-hint = Doporučuje se přesný typ NUMERIC. Tuto možnost povolte pouze pro přísný externí datový kontrakt.
|
||||||
|
td-fixed-decimal-warning-title = Pokročilé desetinné číslo s pevným měřítkem
|
||||||
|
td-fixed-decimal-warning = Tento typ omezuje celkový počet číslic i desetinná místa. Hodnoty mimo měřítko se odmítnou, výpočty musí zaokrouhlovat explicitně a typ po vložení dat nelze změnit.
|
||||||
|
td-fixed-decimal-enable-first = Před použitím tohoto typu povolte pokročilé desetinné číslo s pevným měřítkem.
|
||||||
|
td-exact-decimal = Desetinné číslo — přesné (doporučeno)
|
||||||
|
td-fixed-decimal-type = Desetinné číslo s pevným měřítkem — pokročilé
|
||||||
td-referenced-table = Odkazovaná tabulka
|
td-referenced-table = Odkazovaná tabulka
|
||||||
td-choose-table = Vyberte tabulku
|
td-choose-table = Vyberte tabulku
|
||||||
td-group-global = Globální
|
td-group-global = Globální
|
||||||
|
|||||||
@@ -216,6 +216,15 @@ td-precision = Precision
|
|||||||
td-precision-hint = Total digits stored, at least 1.
|
td-precision-hint = Total digits stored, at least 1.
|
||||||
td-scale = Scale
|
td-scale = Scale
|
||||||
td-scale-hint = Digits after the point, no more than the precision.
|
td-scale-hint = Digits after the point, no more than the precision.
|
||||||
|
td-fixed-decimal-access = Advanced number types
|
||||||
|
td-fixed-decimal-disabled = Recommended types only
|
||||||
|
td-fixed-decimal-enabled = Enable fixed-scale decimal
|
||||||
|
td-fixed-decimal-access-hint = Exact NUMERIC is recommended. Enable this only for a strict external data contract.
|
||||||
|
td-fixed-decimal-warning-title = Advanced fixed-scale decimal
|
||||||
|
td-fixed-decimal-warning = This type limits total and fractional digits. Values outside the declared scale are refused, calculations must round explicitly, and the type cannot be changed after the table contains data.
|
||||||
|
td-fixed-decimal-enable-first = Enable advanced fixed-scale decimal before using this type.
|
||||||
|
td-exact-decimal = Decimal — exact (recommended)
|
||||||
|
td-fixed-decimal-type = Fixed-scale decimal — advanced
|
||||||
td-referenced-table = Referenced table
|
td-referenced-table = Referenced table
|
||||||
td-choose-table = Choose a table
|
td-choose-table = Choose a table
|
||||||
td-group-global = Global
|
td-group-global = Global
|
||||||
|
|||||||
@@ -212,6 +212,15 @@ td-precision = Presnosť
|
|||||||
td-precision-hint = Celkový počet uložených číslic, aspoň 1.
|
td-precision-hint = Celkový počet uložených číslic, aspoň 1.
|
||||||
td-scale = Desatinné miesta
|
td-scale = Desatinné miesta
|
||||||
td-scale-hint = Číslice za desatinnou čiarkou, najviac toľko ako presnosť.
|
td-scale-hint = Číslice za desatinnou čiarkou, najviac toľko ako presnosť.
|
||||||
|
td-fixed-decimal-access = Pokročilé číselné typy
|
||||||
|
td-fixed-decimal-disabled = Iba odporúčané typy
|
||||||
|
td-fixed-decimal-enabled = Povoliť desatinné číslo s pevnou mierkou
|
||||||
|
td-fixed-decimal-access-hint = Odporúča sa presný typ NUMERIC. Túto možnosť povoľte iba pre prísnu externú dátovú zmluvu.
|
||||||
|
td-fixed-decimal-warning-title = Pokročilé desatinné číslo s pevnou mierkou
|
||||||
|
td-fixed-decimal-warning = Tento typ obmedzuje celkový počet číslic aj desatinné miesta. Hodnoty mimo mierky sa odmietnu, výpočty musia zaokrúhľovať explicitne a typ sa po vložení údajov nedá zmeniť.
|
||||||
|
td-fixed-decimal-enable-first = Pred použitím tohto typu povoľte pokročilé desatinné číslo s pevnou mierkou.
|
||||||
|
td-exact-decimal = Desatinné číslo — presné (odporúčané)
|
||||||
|
td-fixed-decimal-type = Desatinné číslo s pevnou mierkou — pokročilé
|
||||||
td-referenced-table = Odkazovaná tabuľka
|
td-referenced-table = Odkazovaná tabuľka
|
||||||
td-choose-table = Vyberte tabuľku
|
td-choose-table = Vyberte tabuľku
|
||||||
td-group-global = Globálne
|
td-group-global = Globálne
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ pub(crate) struct BuilderForm {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub decimal_scale_input: String,
|
pub decimal_scale_input: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub fixed_decimal_input: String,
|
||||||
|
#[serde(default)]
|
||||||
pub column_indexing_input: String,
|
pub column_indexing_input: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub column_quantity_ledger_input: String,
|
pub column_quantity_ledger_input: String,
|
||||||
@@ -128,6 +130,7 @@ impl BuilderForm {
|
|||||||
link_table_input: self.link_table_input.clone(),
|
link_table_input: self.link_table_input.clone(),
|
||||||
decimal_precision_input: self.decimal_precision_input.clone(),
|
decimal_precision_input: self.decimal_precision_input.clone(),
|
||||||
decimal_scale_input: self.decimal_scale_input.clone(),
|
decimal_scale_input: self.decimal_scale_input.clone(),
|
||||||
|
fixed_decimal_input: self.fixed_decimal_input.clone(),
|
||||||
indexing_input: self.column_indexing_input.clone(),
|
indexing_input: self.column_indexing_input.clone(),
|
||||||
quantity_ledger_input: self.column_quantity_ledger_input.clone(),
|
quantity_ledger_input: self.column_quantity_ledger_input.clone(),
|
||||||
required_input: self.column_required_input.clone(),
|
required_input: self.column_required_input.clone(),
|
||||||
|
|||||||
@@ -245,11 +245,18 @@ mod tests {
|
|||||||
assert!(html.contains("Every profile can use this shared table."));
|
assert!(html.contains("Every profile can use this shared table."));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Every type the server accepts has to be reachable from the picker, or
|
/// Fixed-scale decimal is the one intentionally gated type; enabling the
|
||||||
/// the web UI silently offers less than the backend does.
|
/// advanced control makes it reachable without removing server support.
|
||||||
#[test]
|
#[test]
|
||||||
fn the_type_picker_offers_the_parameterised_and_interval_types() {
|
fn the_type_picker_offers_the_parameterised_and_interval_types() {
|
||||||
let html = render_builder(&page());
|
let mut state = page();
|
||||||
|
let html = render_builder(&state);
|
||||||
|
|
||||||
|
assert!(!html.contains(r#"<option value="decimal""#));
|
||||||
|
assert!(html.contains(r#"name="fixed_decimal_input""#));
|
||||||
|
|
||||||
|
state.draft.columns.fixed_decimal_input = "yes".to_string();
|
||||||
|
let html = render_builder(&state);
|
||||||
|
|
||||||
for column_type in ["decimal", "duration", "period", "accounting"] {
|
for column_type in ["decimal", "duration", "period", "accounting"] {
|
||||||
assert!(
|
assert!(
|
||||||
@@ -273,10 +280,12 @@ mod tests {
|
|||||||
assert!(render_builder(&state).contains(r#"name="gtin_type_input""#));
|
assert!(render_builder(&state).contains(r#"name="gtin_type_input""#));
|
||||||
|
|
||||||
// Decimal reveals its precision and scale.
|
// Decimal reveals its precision and scale.
|
||||||
|
state.draft.columns.fixed_decimal_input = "yes".to_string();
|
||||||
state.draft.columns.type_input = "decimal".to_string();
|
state.draft.columns.type_input = "decimal".to_string();
|
||||||
let html = render_builder(&state);
|
let html = render_builder(&state);
|
||||||
assert!(html.contains(r#"name="decimal_precision_input""#));
|
assert!(html.contains(r#"name="decimal_precision_input""#));
|
||||||
assert!(html.contains(r#"name="decimal_scale_input""#));
|
assert!(html.contains(r#"name="decimal_scale_input""#));
|
||||||
|
assert!(html.contains("Advanced fixed-scale decimal"));
|
||||||
|
|
||||||
// Money reveals its currency and rounding inputs.
|
// Money reveals its currency and rounding inputs.
|
||||||
state.draft.columns.type_input = "money".to_string();
|
state.draft.columns.type_input = "money".to_string();
|
||||||
|
|||||||
@@ -475,6 +475,10 @@ pub(crate) struct ColumnDraft {
|
|||||||
pub link_table_input: String,
|
pub link_table_input: String,
|
||||||
pub decimal_precision_input: String,
|
pub decimal_precision_input: String,
|
||||||
pub decimal_scale_input: String,
|
pub decimal_scale_input: String,
|
||||||
|
/// Explicit opt-in for the fixed-scale decimal type. It is intentionally
|
||||||
|
/// absent from the normal type picker because PostgreSQL coerces values to
|
||||||
|
/// its declared scale and populated tables cannot later change the type.
|
||||||
|
pub fixed_decimal_input: String,
|
||||||
pub indexing_input: String,
|
pub indexing_input: String,
|
||||||
pub quantity_ledger_input: String,
|
pub quantity_ledger_input: String,
|
||||||
pub required_input: String,
|
pub required_input: String,
|
||||||
@@ -528,6 +532,7 @@ impl ColumnDraft {
|
|||||||
required_input: "no".to_string(),
|
required_input: "no".to_string(),
|
||||||
rounding_input: "none".to_string(),
|
rounding_input: "none".to_string(),
|
||||||
currency_input: "EUR".to_string(),
|
currency_input: "EUR".to_string(),
|
||||||
|
fixed_decimal_input: "no".to_string(),
|
||||||
catalog,
|
catalog,
|
||||||
..Self::default()
|
..Self::default()
|
||||||
}
|
}
|
||||||
@@ -536,7 +541,15 @@ impl ColumnDraft {
|
|||||||
/// The types this panel offers, which is the only place the creation-only
|
/// The types this panel offers, which is the only place the creation-only
|
||||||
/// rule shows up in the markup.
|
/// rule shows up in the markup.
|
||||||
pub(crate) fn offered_types(&self) -> Vec<String> {
|
pub(crate) fn offered_types(&self) -> Vec<String> {
|
||||||
self.catalog.offered_types(self.creating_table, self.global)
|
self.catalog
|
||||||
|
.offered_types(self.creating_table, self.global)
|
||||||
|
.into_iter()
|
||||||
|
.filter(|column_type| column_type != "decimal" || self.fixed_decimal_enabled())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn fixed_decimal_enabled(&self) -> bool {
|
||||||
|
self.fixed_decimal_input.trim().eq_ignore_ascii_case("yes")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn temporal_types(&self) -> Vec<String> {
|
pub(crate) fn temporal_types(&self) -> Vec<String> {
|
||||||
@@ -639,6 +652,9 @@ impl ColumnDraft {
|
|||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
if self.catalog.is_parameterised(&column_type) {
|
if self.catalog.is_parameterised(&column_type) {
|
||||||
|
if !self.fixed_decimal_enabled() {
|
||||||
|
return Err(crate::tr!(locale, "td-fixed-decimal-enable-first"));
|
||||||
|
}
|
||||||
let precision = self.decimal_precision_input.trim();
|
let precision = self.decimal_precision_input.trim();
|
||||||
let scale = self.decimal_scale_input.trim();
|
let scale = self.decimal_scale_input.trim();
|
||||||
if precision.is_empty() && scale.is_empty() {
|
if precision.is_empty() && scale.is_empty() {
|
||||||
@@ -1442,6 +1458,8 @@ pub(crate) struct ColumnForm {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub decimal_scale_input: String,
|
pub decimal_scale_input: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub fixed_decimal_input: String,
|
||||||
|
#[serde(default)]
|
||||||
pub column_indexing_input: String,
|
pub column_indexing_input: String,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub column_quantity_ledger_input: String,
|
pub column_quantity_ledger_input: String,
|
||||||
@@ -1487,6 +1505,7 @@ impl ColumnForm {
|
|||||||
link_table_input: self.link_table_input.clone(),
|
link_table_input: self.link_table_input.clone(),
|
||||||
decimal_precision_input: self.decimal_precision_input.clone(),
|
decimal_precision_input: self.decimal_precision_input.clone(),
|
||||||
decimal_scale_input: self.decimal_scale_input.clone(),
|
decimal_scale_input: self.decimal_scale_input.clone(),
|
||||||
|
fixed_decimal_input: self.fixed_decimal_input.clone(),
|
||||||
indexing_input: self.column_indexing_input.clone(),
|
indexing_input: self.column_indexing_input.clone(),
|
||||||
quantity_ledger_input: self.column_quantity_ledger_input.clone(),
|
quantity_ledger_input: self.column_quantity_ledger_input.clone(),
|
||||||
required_input: self.column_required_input.clone(),
|
required_input: self.column_required_input.clone(),
|
||||||
@@ -1755,7 +1774,10 @@ pub(crate) mod tests {
|
|||||||
assert!(offered.contains(&"numeric".to_string()));
|
assert!(offered.contains(&"numeric".to_string()));
|
||||||
assert!(offered.contains(&"account".to_string()));
|
assert!(offered.contains(&"account".to_string()));
|
||||||
assert!(offered.contains(&"accounting_transfer".to_string()));
|
assert!(offered.contains(&"accounting_transfer".to_string()));
|
||||||
assert!(offered.contains(&"decimal".to_string()));
|
assert!(!offered.contains(&"decimal".to_string()));
|
||||||
|
let mut advanced = draft();
|
||||||
|
advanced.fixed_decimal_input = "yes".to_string();
|
||||||
|
assert!(advanced.offered_types().contains(&"decimal".to_string()));
|
||||||
// Families are one choice, resolved by a follow-up field.
|
// Families are one choice, resolved by a follow-up field.
|
||||||
assert!(offered.contains(&"temporal".to_string()));
|
assert!(offered.contains(&"temporal".to_string()));
|
||||||
assert!(offered.contains(&"gtin".to_string()));
|
assert!(offered.contains(&"gtin".to_string()));
|
||||||
@@ -1803,6 +1825,7 @@ pub(crate) mod tests {
|
|||||||
assert_eq!(draft.added[1].data_type, "gtin_13");
|
assert_eq!(draft.added[1].data_type, "gtin_13");
|
||||||
|
|
||||||
draft.name_input = "weight".to_string();
|
draft.name_input = "weight".to_string();
|
||||||
|
draft.fixed_decimal_input = "yes".to_string();
|
||||||
draft.type_input = "decimal".to_string();
|
draft.type_input = "decimal".to_string();
|
||||||
assert_eq!(draft.canonical_type_input(crate::i18n::Locale::default()).unwrap(), None);
|
assert_eq!(draft.canonical_type_input(crate::i18n::Locale::default()).unwrap(), None);
|
||||||
assert!(draft.show_decimal_arguments());
|
assert!(draft.show_decimal_arguments());
|
||||||
@@ -1843,6 +1866,7 @@ pub(crate) mod tests {
|
|||||||
fn decimal_arguments_follow_the_servers_rules() {
|
fn decimal_arguments_follow_the_servers_rules() {
|
||||||
let mut draft = draft();
|
let mut draft = draft();
|
||||||
draft.name_input = "weight".to_string();
|
draft.name_input = "weight".to_string();
|
||||||
|
draft.fixed_decimal_input = "yes".to_string();
|
||||||
draft.type_input = "decimal".to_string();
|
draft.type_input = "decimal".to_string();
|
||||||
|
|
||||||
for (precision, scale) in [("0", "0"), ("3", "5"), ("-2", "1"), ("08", "2"), ("4.5", "1")] {
|
for (precision, scale) in [("0", "0"), ("3", "5"), ("-2", "1"), ("08", "2"), ("4.5", "1")] {
|
||||||
@@ -1946,6 +1970,7 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
// A parameterised decimal counts, through its head.
|
// A parameterised decimal counts, through its head.
|
||||||
draft.name_input = "quantity".to_string();
|
draft.name_input = "quantity".to_string();
|
||||||
|
draft.fixed_decimal_input = "yes".to_string();
|
||||||
draft.type_input = "decimal".to_string();
|
draft.type_input = "decimal".to_string();
|
||||||
draft.decimal_precision_input = "12".to_string();
|
draft.decimal_precision_input = "12".to_string();
|
||||||
draft.decimal_scale_input = "3".to_string();
|
draft.decimal_scale_input = "3".to_string();
|
||||||
|
|||||||
@@ -127,13 +127,22 @@
|
|||||||
{% if page.draft.columns.show_link_target() %}<small>{{ nav.tr("td-link-alias-hint") }}</small>{% endif %}
|
{% if page.draft.columns.show_link_target() %}<small>{{ nav.tr("td-link-alias-hint") }}</small>{% endif %}
|
||||||
</label>
|
</label>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<label>{{ nav.tr("td-fixed-decimal-access") }}
|
||||||
|
<select name="fixed_decimal_input" hx-post="/admin/tables/builder" hx-trigger="change"
|
||||||
|
hx-include="#table-form" hx-target="#builder" hx-swap="innerHTML"
|
||||||
|
hx-vals='{"action": "refresh"}'>
|
||||||
|
<option value="no" {% if !page.draft.columns.fixed_decimal_enabled() %}selected{% endif %}>{{ nav.tr("td-fixed-decimal-disabled") }}</option>
|
||||||
|
<option value="yes" {% if page.draft.columns.fixed_decimal_enabled() %}selected{% endif %}>{{ nav.tr("td-fixed-decimal-enabled") }}</option>
|
||||||
|
</select>
|
||||||
|
<small>{{ nav.tr("td-fixed-decimal-access-hint") }}</small>
|
||||||
|
</label>
|
||||||
<label>{{ nav.tr("td-column-type") }}
|
<label>{{ nav.tr("td-column-type") }}
|
||||||
<select name="column_type_input" hx-post="/admin/tables/builder" hx-trigger="change"
|
<select name="column_type_input" hx-post="/admin/tables/builder" hx-trigger="change"
|
||||||
hx-include="#table-form" hx-target="#builder" hx-swap="innerHTML"
|
hx-include="#table-form" hx-target="#builder" hx-swap="innerHTML"
|
||||||
hx-vals='{"action": "refresh"}'>
|
hx-vals='{"action": "refresh"}'>
|
||||||
<option value="">{{ nav.tr("td-choose-type") }}</option>
|
<option value="">{{ nav.tr("td-choose-type") }}</option>
|
||||||
{% for column_type in column_types %}
|
{% for column_type in column_types %}
|
||||||
<option value="{{ column_type }}" {% if page.draft.columns.type_input == *column_type %}selected{% endif %}>{% if *column_type == "link" %}{{ nav.tr("td-fk-link") }}{% else %}{{ column_type }}{% endif %}</option>
|
<option value="{{ column_type }}" {% if page.draft.columns.type_input == *column_type %}selected{% endif %}>{% if *column_type == "link" %}{{ nav.tr("td-fk-link") }}{% else if *column_type == "numeric" %}{{ nav.tr("td-exact-decimal") }}{% else if *column_type == "decimal" %}{{ nav.tr("td-fixed-decimal-type") }}{% else %}{{ column_type }}{% endif %}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
@@ -161,6 +170,10 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if page.draft.columns.show_decimal_arguments() %}
|
{% if page.draft.columns.show_decimal_arguments() %}
|
||||||
|
<div class="field-note col-span-full">
|
||||||
|
<span class="field-label">{{ nav.tr("td-fixed-decimal-warning-title") }}</span>
|
||||||
|
<p class="hint">{{ nav.tr("td-fixed-decimal-warning") }}</p>
|
||||||
|
</div>
|
||||||
<label>{{ nav.tr("td-precision") }}
|
<label>{{ nav.tr("td-precision") }}
|
||||||
<input name="decimal_precision_input" value="{{ page.draft.columns.decimal_precision_input }}"
|
<input name="decimal_precision_input" value="{{ page.draft.columns.decimal_precision_input }}"
|
||||||
inputmode="numeric" placeholder="12">
|
inputmode="numeric" placeholder="12">
|
||||||
|
|||||||
@@ -29,6 +29,17 @@
|
|||||||
<input name="column_name_input" value="{{ page.columns.name_input }}" placeholder="issued_on">
|
<input name="column_name_input" value="{{ page.columns.name_input }}" placeholder="issued_on">
|
||||||
{% if page.columns.show_link_target() %}<small>{{ nav.tr("td-link-alias-hint") }}</small>{% endif %}
|
{% if page.columns.show_link_target() %}<small>{{ nav.tr("td-link-alias-hint") }}</small>{% endif %}
|
||||||
</label>
|
</label>
|
||||||
|
<label>{{ nav.tr("td-fixed-decimal-access") }}
|
||||||
|
<select name="fixed_decimal_input"
|
||||||
|
hx-post="/admin/tables/columns/add/builder{{ page.selection.query() }}"
|
||||||
|
hx-trigger="change" hx-include="#column-form"
|
||||||
|
hx-target="#column-panel" hx-swap="innerHTML"
|
||||||
|
hx-vals='{"action": "refresh"}'>
|
||||||
|
<option value="no" {% if !page.columns.fixed_decimal_enabled() %}selected{% endif %}>{{ nav.tr("td-fixed-decimal-disabled") }}</option>
|
||||||
|
<option value="yes" {% if page.columns.fixed_decimal_enabled() %}selected{% endif %}>{{ nav.tr("td-fixed-decimal-enabled") }}</option>
|
||||||
|
</select>
|
||||||
|
<small>{{ nav.tr("td-fixed-decimal-access-hint") }}</small>
|
||||||
|
</label>
|
||||||
<label>{{ nav.tr("td-column-type") }}
|
<label>{{ nav.tr("td-column-type") }}
|
||||||
<select name="column_type_input"
|
<select name="column_type_input"
|
||||||
hx-post="/admin/tables/columns/add/builder{{ page.selection.query() }}"
|
hx-post="/admin/tables/columns/add/builder{{ page.selection.query() }}"
|
||||||
@@ -37,7 +48,7 @@
|
|||||||
hx-vals='{"action": "refresh"}'>
|
hx-vals='{"action": "refresh"}'>
|
||||||
<option value="">{{ nav.tr("td-choose-type") }}</option>
|
<option value="">{{ nav.tr("td-choose-type") }}</option>
|
||||||
{% for column_type in column_types %}
|
{% for column_type in column_types %}
|
||||||
<option value="{{ column_type }}" {% if page.columns.type_input == *column_type %}selected{% endif %}>{% if *column_type == "link" %}{{ nav.tr("td-fk-link") }}{% else %}{{ column_type }}{% endif %}</option>
|
<option value="{{ column_type }}" {% if page.columns.type_input == *column_type %}selected{% endif %}>{% if *column_type == "link" %}{{ nav.tr("td-fk-link") }}{% else if *column_type == "numeric" %}{{ nav.tr("td-exact-decimal") }}{% else if *column_type == "decimal" %}{{ nav.tr("td-fixed-decimal-type") }}{% else %}{{ column_type }}{% endif %}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
@@ -65,6 +76,10 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if page.columns.show_decimal_arguments() %}
|
{% if page.columns.show_decimal_arguments() %}
|
||||||
|
<div class="field-note col-span-full">
|
||||||
|
<span class="field-label">{{ nav.tr("td-fixed-decimal-warning-title") }}</span>
|
||||||
|
<p class="hint">{{ nav.tr("td-fixed-decimal-warning") }}</p>
|
||||||
|
</div>
|
||||||
<label>{{ nav.tr("td-precision") }}
|
<label>{{ nav.tr("td-precision") }}
|
||||||
<input name="decimal_precision_input" value="{{ page.columns.decimal_precision_input }}"
|
<input name="decimal_precision_input" value="{{ page.columns.decimal_precision_input }}"
|
||||||
inputmode="numeric" placeholder="12">
|
inputmode="numeric" placeholder="12">
|
||||||
|
|||||||
Reference in New Issue
Block a user