From fedf89d94abd7265c4671c39fe87b9436581dd77 Mon Sep 17 00:00:00 2001 From: Filipriec Date: Sun, 30 Aug 2026 20:29:19 +0200 Subject: [PATCH] implement client grid and typst on the backend --- client | 2 +- client-gui2 | 2 +- common/proto/table_definition.proto | 45 +++++ common/src/proto/descriptor.bin | Bin 206002 -> 209251 bytes common/src/proto/komp_ac.table_definition.rs | 191 +++++++++++++++++++ flake.nix | 4 +- 6 files changed, 240 insertions(+), 4 deletions(-) diff --git a/client b/client index 534f7236..f4eb4c32 160000 --- a/client +++ b/client @@ -1 +1 @@ -Subproject commit 534f72363dd0cd53799fd740f65c16a6002ce39b +Subproject commit f4eb4c32abe815f7acf808918359e3a0d37452cf diff --git a/client-gui2 b/client-gui2 index 58593ae5..acac1b05 160000 --- a/client-gui2 +++ b/client-gui2 @@ -1 +1 @@ -Subproject commit 58593ae57767d068fba037e6399784bab6edb214 +Subproject commit acac1b056ca82d5f9e477cd5cf192dd5b8067792 diff --git a/common/proto/table_definition.proto b/common/proto/table_definition.proto index 67946424..045c08c3 100644 --- a/common/proto/table_definition.proto +++ b/common/proto/table_definition.proto @@ -23,6 +23,10 @@ service TableDefinition { // by the user; templates do not provision tables merely by existing. rpc CreateInvoiceTemplateTable(CreateInvoiceTemplateTableRequest) returns (CreateInvoiceTemplateTableResponse); + // Applies the administrator-reviewed, explicitly typed table bundle and + // exact komp_ac_fields bindings for an imported Typst template. + rpc ApplyInvoiceTemplateTable(ApplyInvoiceTemplateTableRequest) returns (CreateInvoiceTemplateTableResponse); + // Appends new user-defined columns to an existing table. // Existing columns, links, and table logic are never changed by this call. rpc AddTableColumns(AddTableColumnsRequest) returns (TableDefinitionResponse); @@ -170,6 +174,46 @@ message CreateInvoiceTemplateTableRequest { repeated string row_display_columns = 3; } +message ApplyInvoiceTemplateTableRequest { + string profile_name = 1; + string template_name = 2; + repeated InvoiceTemplateTableDefinition tables = 3; + repeated InvoiceTemplateFieldBinding field_bindings = 4; + + // The immutable version whose komp_ac_fields the administrator mapped. + // Applying never silently switches to a newer version with a different + // contract between inspection and submission. + int64 template_version_id = 5; +} + +// One administrator-designed table in the template input bundle. The empty +// collection_path is the root; a path ending in [] owns that repeated scope. +// The nested table definition retains every normal table option, including +// ACCOUNTING, generated aliases, ledgers, indexes, links and display columns. +message InvoiceTemplateTableDefinition { + string collection_path = 1; + PostTableDefinitionRequest definition = 2; +} + +enum InvoiceTemplateAccountingRole { + INVOICE_TEMPLATE_ACCOUNTING_ROLE_UNSPECIFIED = 0; + INVOICE_TEMPLATE_ACCOUNTING_NAME = 1; + INVOICE_TEMPLATE_ACCOUNTING_TAX_POINT_DATE = 2; + INVOICE_TEMPLATE_ACCOUNTING_ACCOUNT = 3; + INVOICE_TEMPLATE_ACCOUNTING_DEBIT = 4; + INVOICE_TEMPLATE_ACCOUNTING_CREDIT = 5; +} + +// Maps one path from komp_ac_fields to one table column. A regular binding +// names a declared column. An accounting binding names a semantic generated +// role, so aliases and the order of Typst fields cannot change its meaning. +message InvoiceTemplateFieldBinding { + string field_path = 1; + string collection_path = 2; + string column_name = 3; + InvoiceTemplateAccountingRole accounting_role = 4; +} + // One physical dynamic table created for an invoice template scope. The root // has an empty collection_path and parent_table_name. Each [] scope names its // collection and the generated table that owns those repeated rows. @@ -184,6 +228,7 @@ message GeneratedInvoiceTemplateTable { message CreateInvoiceTemplateTableResponse { bool success = 1; repeated GeneratedInvoiceTemplateTable tables = 2; + int64 template_version_id = 3; } // Defines append-only column additions for an existing table. diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index 53877eda8f632ecd2640f6a25e02c0d95ca3a601..da6d65db2ed37fc11b677db67f07435a82f5a10b 100644 GIT binary patch delta 14304 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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 27cd74db..38150198 100644 --- a/common/src/proto/komp_ac.table_definition.rs +++ b/common/src/proto/komp_ac.table_definition.rs @@ -114,6 +114,50 @@ pub struct CreateInvoiceTemplateTableRequest { #[prost(string, repeated, tag = "3")] pub row_display_columns: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, } +#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ApplyInvoiceTemplateTableRequest { + #[prost(string, tag = "1")] + pub profile_name: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub template_name: ::prost::alloc::string::String, + #[prost(message, repeated, tag = "3")] + pub tables: ::prost::alloc::vec::Vec, + #[prost(message, repeated, tag = "4")] + pub field_bindings: ::prost::alloc::vec::Vec, + /// The immutable version whose komp_ac_fields the administrator mapped. + /// Applying never silently switches to a newer version with a different + /// contract between inspection and submission. + #[prost(int64, tag = "5")] + pub template_version_id: i64, +} +/// One administrator-designed table in the template input bundle. The empty +/// collection_path is the root; a path ending in \[\] owns that repeated scope. +/// The nested table definition retains every normal table option, including +/// ACCOUNTING, generated aliases, ledgers, indexes, links and display columns. +#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct InvoiceTemplateTableDefinition { + #[prost(string, tag = "1")] + pub collection_path: ::prost::alloc::string::String, + #[prost(message, optional, tag = "2")] + pub definition: ::core::option::Option, +} +/// Maps one path from komp_ac_fields to one table column. A regular binding +/// names a declared column. An accounting binding names a semantic generated +/// role, so aliases and the order of Typst fields cannot change its meaning. +#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct InvoiceTemplateFieldBinding { + #[prost(string, tag = "1")] + pub field_path: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub collection_path: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub column_name: ::prost::alloc::string::String, + #[prost(enumeration = "InvoiceTemplateAccountingRole", tag = "4")] + pub accounting_role: i32, +} /// One physical dynamic table created for an invoice template scope. The root /// has an empty collection_path and parent_table_name. Each \[\] scope names its /// collection and the generated table that owns those repeated rows. @@ -137,6 +181,8 @@ pub struct CreateInvoiceTemplateTableResponse { pub success: bool, #[prost(message, repeated, tag = "2")] pub tables: ::prost::alloc::vec::Vec, + #[prost(int64, tag = "3")] + pub template_version_id: i64, } /// Defines append-only column additions for an existing table. #[derive(serde::Serialize, serde::Deserialize)] @@ -704,6 +750,59 @@ pub mod list_column_types_response { #[derive(serde::Serialize, serde::Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] +pub enum InvoiceTemplateAccountingRole { + Unspecified = 0, + InvoiceTemplateAccountingName = 1, + InvoiceTemplateAccountingTaxPointDate = 2, + InvoiceTemplateAccountingAccount = 3, + InvoiceTemplateAccountingDebit = 4, + InvoiceTemplateAccountingCredit = 5, +} +impl InvoiceTemplateAccountingRole { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + Self::Unspecified => "INVOICE_TEMPLATE_ACCOUNTING_ROLE_UNSPECIFIED", + Self::InvoiceTemplateAccountingName => "INVOICE_TEMPLATE_ACCOUNTING_NAME", + Self::InvoiceTemplateAccountingTaxPointDate => { + "INVOICE_TEMPLATE_ACCOUNTING_TAX_POINT_DATE" + } + Self::InvoiceTemplateAccountingAccount => { + "INVOICE_TEMPLATE_ACCOUNTING_ACCOUNT" + } + Self::InvoiceTemplateAccountingDebit => "INVOICE_TEMPLATE_ACCOUNTING_DEBIT", + Self::InvoiceTemplateAccountingCredit => "INVOICE_TEMPLATE_ACCOUNTING_CREDIT", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "INVOICE_TEMPLATE_ACCOUNTING_ROLE_UNSPECIFIED" => Some(Self::Unspecified), + "INVOICE_TEMPLATE_ACCOUNTING_NAME" => { + Some(Self::InvoiceTemplateAccountingName) + } + "INVOICE_TEMPLATE_ACCOUNTING_TAX_POINT_DATE" => { + Some(Self::InvoiceTemplateAccountingTaxPointDate) + } + "INVOICE_TEMPLATE_ACCOUNTING_ACCOUNT" => { + Some(Self::InvoiceTemplateAccountingAccount) + } + "INVOICE_TEMPLATE_ACCOUNTING_DEBIT" => { + Some(Self::InvoiceTemplateAccountingDebit) + } + "INVOICE_TEMPLATE_ACCOUNTING_CREDIT" => { + Some(Self::InvoiceTemplateAccountingCredit) + } + _ => None, + } + } +} +#[derive(serde::Serialize, serde::Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] +#[repr(i32)] pub enum MoneyRounding { None = 0, HalfUp = 1, @@ -983,6 +1082,37 @@ pub mod table_definition_client { ); self.inner.unary(req, path, codec).await } + /// Applies the administrator-reviewed, explicitly typed table bundle and + /// exact komp_ac_fields bindings for an imported Typst template. + pub async fn apply_invoice_template_table( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/komp_ac.table_definition.TableDefinition/ApplyInvoiceTemplateTable", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "komp_ac.table_definition.TableDefinition", + "ApplyInvoiceTemplateTable", + ), + ); + self.inner.unary(req, path, codec).await + } /// Appends new user-defined columns to an existing table. /// Existing columns, links, and table logic are never changed by this call. pub async fn add_table_columns( @@ -1367,6 +1497,15 @@ pub mod table_definition_server { tonic::Response, tonic::Status, >; + /// Applies the administrator-reviewed, explicitly typed table bundle and + /// exact komp_ac_fields bindings for an imported Typst template. + async fn apply_invoice_template_table( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; /// Appends new user-defined columns to an existing table. /// Existing columns, links, and table logic are never changed by this call. async fn add_table_columns( @@ -1701,6 +1840,58 @@ pub mod table_definition_server { }; Box::pin(fut) } + "/komp_ac.table_definition.TableDefinition/ApplyInvoiceTemplateTable" => { + #[allow(non_camel_case_types)] + struct ApplyInvoiceTemplateTableSvc(pub Arc); + impl< + T: TableDefinition, + > tonic::server::UnaryService< + super::ApplyInvoiceTemplateTableRequest, + > for ApplyInvoiceTemplateTableSvc { + type Response = super::CreateInvoiceTemplateTableResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request< + super::ApplyInvoiceTemplateTableRequest, + >, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::apply_invoice_template_table( + &inner, + request, + ) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ApplyInvoiceTemplateTableSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } "/komp_ac.table_definition.TableDefinition/AddTableColumns" => { #[allow(non_camel_case_types)] struct AddTableColumnsSvc(pub Arc); diff --git a/flake.nix b/flake.nix index 1f68d047..b6621f00 100644 --- a/flake.nix +++ b/flake.nix @@ -35,8 +35,8 @@ ]; # Keep font discovery deterministic when running the prebuilt GUI. - FONTCONFIG_FILE = "${pkgs.fontconfig}/etc/fonts/fonts.conf"; - FONTCONFIG_PATH = "${pkgs.fontconfig}/etc/fonts"; + FONTCONFIG_FILE = "${pkgs.fontconfig.out}/etc/fonts/fonts.conf"; + FONTCONFIG_PATH = "${pkgs.fontconfig.out}/etc/fonts"; buildInputs = with pkgs; [ mermaid-cli