From 06447e13f3ca6a10c601c829942483a7ca630876 Mon Sep 17 00:00:00 2001 From: Priec Date: Wed, 29 Jul 2026 20:25:24 +0200 Subject: [PATCH] qunatity ledger in table definition --- client | 2 +- common/proto/table_definition.proto | 4 +++- common/proto/table_structure.proto | 5 ++--- common/src/proto/descriptor.bin | Bin 134570 -> 134661 bytes common/src/proto/komp_ac.table_definition.rs | 4 ++++ common/src/proto/komp_ac.table_structure.rs | 3 +++ graphs/src/pages/add_table/state.rs | 4 +++- graphs/src/pages/add_table/ui.rs | 2 +- graphs/src/pages/admin/admin/loader.rs | 1 + graphs/src/pages/admin/admin/state.rs | 1 + graphs/src/pages/admin/admin/ui.rs | 3 +++ server | 2 +- 12 files changed, 23 insertions(+), 8 deletions(-) diff --git a/client b/client index 71b5cff..c7ba851 160000 --- a/client +++ b/client @@ -1 +1 @@ -Subproject commit 71b5cff16d9a51543b964eee23b2d311584b6916 +Subproject commit c7ba851c7313955e9b84bae4e766696da878632d diff --git a/common/proto/table_definition.proto b/common/proto/table_definition.proto index 9f6adbc..5ab5ae3 100644 --- a/common/proto/table_definition.proto +++ b/common/proto/table_definition.proto @@ -197,7 +197,9 @@ message ColumnDefinition { // MONEY rounding applied before a value is stored. MoneyRounding rounding = 4; - reserved 5; + // When true, this numeric column is server-owned and projected from the + // profile quantity ledger. + bool quantity_ledger = 5; } // Response after table creation (success + DDL preview). diff --git a/common/proto/table_structure.proto b/common/proto/table_structure.proto index e533265..d840f2f 100644 --- a/common/proto/table_structure.proto +++ b/common/proto/table_structure.proto @@ -73,9 +73,8 @@ message TableColumn { // Typically true for the "id" column created by the system. bool is_primary_key = 4; - // True for a user-defined column whose logic should be recomputed whenever - // one of its dependencies changes. False for system and foreign-key columns. - reserved 5; + // True when this column is projected from the profile quantity ledger. + bool quantity_ledger = 5; // True when the server created this as a companion of another logical column. bool generated = 6; diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index 031a8996b1d6b03d285e75341729d690f2627473..7cc2fdb2db8a9b22f284c9292cb3d9a2fa9b73ee 100644 GIT binary patch delta 4561 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 X+z;Uen78IY+z#OdJuh#g>g<024P-_@ delta 4424 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 diff --git a/common/src/proto/komp_ac.table_definition.rs b/common/src/proto/komp_ac.table_definition.rs index 4c8d4d0..0a98666 100644 --- a/common/src/proto/komp_ac.table_definition.rs +++ b/common/src/proto/komp_ac.table_definition.rs @@ -166,6 +166,10 @@ pub struct ColumnDefinition { /// MONEY rounding applied before a value is stored. #[prost(enumeration = "MoneyRounding", tag = "4")] pub rounding: i32, + /// When true, this numeric column is server-owned and projected from the + /// profile quantity ledger. + #[prost(bool, tag = "5")] + pub quantity_ledger: bool, } /// Response after table creation (success + DDL preview). #[derive(serde::Serialize, serde::Deserialize)] diff --git a/common/src/proto/komp_ac.table_structure.rs b/common/src/proto/komp_ac.table_structure.rs index 5a1a591..6f66e7d 100644 --- a/common/src/proto/komp_ac.table_structure.rs +++ b/common/src/proto/komp_ac.table_structure.rs @@ -55,6 +55,9 @@ pub struct TableColumn { /// Typically true for the "id" column created by the system. #[prost(bool, tag = "4")] pub is_primary_key: bool, + /// True when this column is projected from the profile quantity ledger. + #[prost(bool, tag = "5")] + pub quantity_ledger: bool, /// True when the server created this as a companion of another logical column. #[prost(bool, tag = "6")] pub generated: bool, diff --git a/graphs/src/pages/add_table/state.rs b/graphs/src/pages/add_table/state.rs index 110528d..48c95c8 100644 --- a/graphs/src/pages/add_table/state.rs +++ b/graphs/src/pages/add_table/state.rs @@ -74,6 +74,7 @@ impl CreateTableForm { name: name.to_string(), field_type: field_type.to_string(), rounding: rounding.into(), + quantity_ledger: flags.contains(&"quantity-ledger"), }); } if columns.is_empty() { @@ -143,7 +144,7 @@ mod tests { let request = CreateTableForm { profile_name: "accounting".into(), table_name: "invoice".into(), - columns: "number: text:indexed\namount: money:half-up".into(), + columns: "number: text:indexed\namount: money:half-up,quantity-ledger".into(), required_links: "customer".into(), base_currency: "eur".into(), row_display_columns: "number, amount".into(), @@ -157,5 +158,6 @@ mod tests { assert!(request.links[0].required); assert_eq!(request.base_currency, "EUR"); assert_eq!(request.row_display_columns, vec!["number", "amount"]); + assert!(request.columns[1].quantity_ledger); } } diff --git a/graphs/src/pages/add_table/ui.rs b/graphs/src/pages/add_table/ui.rs index ae6f3f9..86aefc8 100644 --- a/graphs/src/pages/add_table/ui.rs +++ b/graphs/src/pages/add_table/ui.rs @@ -21,7 +21,7 @@ pub(crate) fn render_page(page: &AddTablePageState) -> String { .map(render_submission_error) .unwrap_or_default(); format!( - "Add table
Komp Accounting
← Admin panel

Table definition

Add table

Create a table through the existing gRPC table-definition service.

{error}
Cancel
", + "Add table
Komp Accounting
← Admin panel

Table definition

Add table

Create a table through the existing gRPC table-definition service.

{error}
Cancel
", crate::escape_html(&page.form.table_name), crate::escape_html(&page.form.columns), crate::escape_html(&page.form.indexed_columns), diff --git a/graphs/src/pages/admin/admin/loader.rs b/graphs/src/pages/admin/admin/loader.rs index 95ebfb8..440e1b9 100644 --- a/graphs/src/pages/admin/admin/loader.rs +++ b/graphs/src/pages/admin/admin/loader.rs @@ -113,6 +113,7 @@ pub(crate) async fn load_admin_page( data_type: column.data_type.clone(), nullable: column.is_nullable, primary_key: column.is_primary_key, + quantity_ledger: column.quantity_ledger, }) .collect() } diff --git a/graphs/src/pages/admin/admin/state.rs b/graphs/src/pages/admin/admin/state.rs index 668b702..12c2918 100644 --- a/graphs/src/pages/admin/admin/state.rs +++ b/graphs/src/pages/admin/admin/state.rs @@ -35,6 +35,7 @@ pub(crate) struct ColumnView { pub data_type: String, pub nullable: bool, pub primary_key: bool, + pub quantity_ledger: bool, } #[derive(Debug)] diff --git a/graphs/src/pages/admin/admin/ui.rs b/graphs/src/pages/admin/admin/ui.rs index fe7feec..8ca68bd 100644 --- a/graphs/src/pages/admin/admin/ui.rs +++ b/graphs/src/pages/admin/admin/ui.rs @@ -95,6 +95,9 @@ fn render_columns(page: &AdminPageState) -> String { } else { flags.push("required"); } + if column.quantity_ledger { + flags.push("quantity ledger"); + } format!( "
{}{}{}
", crate::escape_html(&column.name), diff --git a/server b/server index b44238e..d4343fe 160000 --- a/server +++ b/server @@ -1 +1 @@ -Subproject commit b44238ec3b3cca9e5dcf2367767fdba64db41f82 +Subproject commit d4343fe48bcec8c87ef77e181a41a02f9f599d5b