diff --git a/client b/client index 455e109f..42f163be 160000 --- a/client +++ b/client @@ -1 +1 @@ -Subproject commit 455e109f476770d04966802e8272a8bc606e864b +Subproject commit 42f163beaec0c66337487698542924e02f5172b3 diff --git a/server b/server index 03a8e188..8d8f1538 160000 --- a/server +++ b/server @@ -1 +1 @@ -Subproject commit 03a8e1887af639bbc582e5583eb72d2967558a88 +Subproject commit 8d8f1538635343768000bbca8e9f08000ad1d008 diff --git a/web/src/schema/mod.rs b/web/src/schema/mod.rs index aaec6a94..ab62c4aa 100644 --- a/web/src/schema/mod.rs +++ b/web/src/schema/mod.rs @@ -33,6 +33,9 @@ use crate::definitions::table_definition::{ /// The compound type that posts a row to the profile's books. pub(crate) const ACCOUNTING_FIELD_TYPE: &str = "accounting"; +/// The public text path for a row in the profile's account catalogue. +pub(crate) const ACCOUNT_FIELD_TYPE: &str = "account"; + /// The compound type that moves a balance between two accounting periods. pub(crate) const ACCOUNTING_TRANSFER_FIELD_TYPE: &str = "accounting_transfer"; @@ -41,7 +44,11 @@ pub(crate) const ACCOUNTING_TRANSFER_FIELD_TYPE: &str = "accounting_transfer"; /// Both post to a profile's books, and a global table belongs to every profile /// at once — there is no one set of books for it to post to, so the server /// refuses the pair outright rather than picking a profile for them. -const PROFILE_ONLY_TYPES: [&str; 2] = [ACCOUNTING_FIELD_TYPE, ACCOUNTING_TRANSFER_FIELD_TYPE]; +const PROFILE_ONLY_TYPES: [&str; 3] = [ + ACCOUNT_FIELD_TYPE, + ACCOUNTING_FIELD_TYPE, + ACCOUNTING_TRANSFER_FIELD_TYPE, +]; /// The profile's chart of accounts. A row reaches it through an ACCOUNTING /// definition row, never through a link declared by hand. @@ -51,6 +58,7 @@ const TYPE_DISPLAY_ORDER: &[&str] = &[ "text", "boolean", "money", + "account", "accounting", "accounting_transfer", "int", @@ -154,7 +162,7 @@ impl ColumnCatalog { /// the creation-only types: they bring schema-managed companion columns /// that cannot be bolted onto a table that already exists. /// - /// `global` drops the two types that post to a profile's books, which a + /// `global` drops the profile accounting types, which a /// table shared by every profile has no single one of. pub(crate) fn offered_types(&self, creating_table: bool, global: bool) -> Vec { let mut offered = Vec::new(); @@ -1615,6 +1623,11 @@ pub(crate) mod tests { /// the types a client may not declare as well as the ones it may. pub(crate) fn catalog() -> ColumnCatalog { ColumnCatalog::new(vec![ + ColumnType { + sql_type: "BIGINT".to_string(), + creation_only: true, + ..declarable("account") + }, ColumnType { requires_currency: true, // The companions the server reports with the type, in the @@ -1730,6 +1743,7 @@ pub(crate) mod tests { let offered = draft().offered_types(); assert!(offered.contains(&"numeric".to_string())); + assert!(offered.contains(&"account".to_string())); assert!(offered.contains(&"accounting_transfer".to_string())); assert!(offered.contains(&"decimal".to_string())); // Families are one choice, resolved by a follow-up field. @@ -1752,6 +1766,7 @@ pub(crate) mod tests { assert!(!appendable.contains(&"accounting".to_string())); assert!(!appendable.contains(&"accounting_transfer".to_string())); + assert!(!appendable.contains(&"account".to_string())); assert!(appendable.contains(&"money".to_string())); } @@ -1849,7 +1864,7 @@ pub(crate) mod tests { #[test] fn an_append_panel_refuses_a_creation_only_column() { - for field_type in ["accounting", "accounting_transfer"] { + for field_type in ["account", "accounting", "accounting_transfer"] { let mut draft = ColumnDraft::for_append(catalog()); draft.type_input = field_type.to_string(); assert!(draft.add_from_inputs(crate::i18n::Locale::default()).is_err()); @@ -1935,7 +1950,7 @@ pub(crate) mod tests { /// type's name and there is nothing to index. #[test] fn a_compound_column_is_named_after_its_type_and_never_indexed() { - for field_type in ["accounting", "accounting_transfer"] { + for field_type in ["account", "accounting", "accounting_transfer"] { let mut draft = draft(); draft.name_input = "whatever".to_string(); draft.type_input = field_type.to_string(); @@ -2262,9 +2277,10 @@ pub(crate) mod tests { let offered = draft.offered_types(); assert!(!offered.contains(&"accounting".to_string())); assert!(!offered.contains(&"accounting_transfer".to_string())); + assert!(!offered.contains(&"account".to_string())); assert!(offered.contains(&"money".to_string())); - for field_type in ["accounting", "accounting_transfer"] { + for field_type in ["account", "accounting", "accounting_transfer"] { let mut draft = draft.clone(); draft.type_input = field_type.to_string(); let error = draft.add_from_inputs(crate::i18n::Locale::default()).unwrap_err();