From a96d95f1b2b679874b44e10bd8b325eba5d8db47 Mon Sep 17 00:00:00 2001 From: Priec Date: Tue, 21 Jul 2026 10:11:46 +0200 Subject: [PATCH] accounting name --- common/proto/accounting.proto | 46 ++++++++- common/src/proto/descriptor.bin | Bin 117785 -> 120159 bytes common/src/proto/komp_ac.accounting.rs | 136 +++++++++++++++++++++++++ tui-pages | 2 +- 4 files changed, 179 insertions(+), 5 deletions(-) diff --git a/common/proto/accounting.proto b/common/proto/accounting.proto index 3818eda..0eca8bd 100644 --- a/common/proto/accounting.proto +++ b/common/proto/accounting.proto @@ -15,6 +15,10 @@ service Accounting { // Return journal lines and credits-minus-debits informational balance. rpc GetJournal(GetJournalRequest) returns (Journal); + // Search profile journals by user-facing name while retaining journal ids + // as the stable relationship keys. + rpc SearchJournals(SearchJournalsRequest) returns (SearchJournalsResponse); + // Return the profile-wide count of balanced and unbalanced journals. rpc GetAccountingStatus(GetAccountingStatusRequest) returns (AccountingStatus); @@ -26,10 +30,6 @@ service Accounting { rpc SoftDeleteJournalLine(SoftDeleteJournalLineRequest) returns (Journal); } -// Tables with an active posting script define journal_id as a permanent BIGINT -// column. PostTableDataRequest.data must include it; the value is stored on the -// source row and selects the journal receiving generated lines. - enum JournalSide { JOURNAL_SIDE_UNSPECIFIED = 0; JOURNAL_SIDE_DEBIT = 1; @@ -53,6 +53,10 @@ message PostJournalRequest { // At least one line is required. The lines are inserted atomically and the // journal is allowed to remain unbalanced. repeated JournalLineInput lines = 5; + + // Required and unique within the profile when creating. Must be empty when + // appending to an existing journal selected by journal_id. + string journal_name = 6; } message JournalLineInput { @@ -80,6 +84,38 @@ message GetAccountingStatusRequest { string profile_name = 1; } +message SearchJournalsRequest { + string profile_name = 1; + + // Case-insensitive literal substring. Empty returns all profile journals. + string name_query = 2; + + // Zero uses 50. The maximum is 500. + int32 page_size = 3; + + // Opaque cursor returned by the previous response. + string page_token = 4; +} + +message JournalSummary { + int64 journal_id = 1; + string journal_name = 2; + string currency = 3; + string description = 4; + string total_debit = 5; + string total_credit = 6; + string balance = 7; + int64 active_line_count = 8; + bool locked = 9; + string created_at = 10; +} + +message SearchJournalsResponse { + repeated JournalSummary journals = 1; + int64 total_count = 2; + string next_page_token = 3; +} + message AccountingStatus { bool all_journals_balanced = 1; int64 journal_count = 2; @@ -117,6 +153,7 @@ message UnbalancedJournalSummary { string missing_amount = 8; int64 active_line_count = 9; string created_at = 10; + string journal_name = 11; } message ListUnbalancedJournalsResponse { @@ -161,4 +198,5 @@ message Journal { bool locked = 10; string locked_at = 11; string locked_by_user_id = 12; + string journal_name = 13; } diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index 08d5faaa4c7bc1bfb381959c04c225044962ce8f..f4e6650e6feb9019b2ab60784583c633c3e05343 100644 GIT binary patch delta 6210 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 diff --git a/common/src/proto/komp_ac.accounting.rs b/common/src/proto/komp_ac.accounting.rs index 2b83439..11eedb9 100644 --- a/common/src/proto/komp_ac.accounting.rs +++ b/common/src/proto/komp_ac.accounting.rs @@ -18,6 +18,10 @@ pub struct PostJournalRequest { /// journal is allowed to remain unbalanced. #[prost(message, repeated, tag = "5")] pub lines: ::prost::alloc::vec::Vec, + /// Required and unique within the profile when creating. Must be empty when + /// appending to an existing journal selected by journal_id. + #[prost(string, tag = "6")] + pub journal_name: ::prost::alloc::string::String, } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct JournalLineInput { @@ -54,6 +58,52 @@ pub struct GetAccountingStatusRequest { pub profile_name: ::prost::alloc::string::String, } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct SearchJournalsRequest { + #[prost(string, tag = "1")] + pub profile_name: ::prost::alloc::string::String, + /// Case-insensitive literal substring. Empty returns all profile journals. + #[prost(string, tag = "2")] + pub name_query: ::prost::alloc::string::String, + /// Zero uses 50. The maximum is 500. + #[prost(int32, tag = "3")] + pub page_size: i32, + /// Opaque cursor returned by the previous response. + #[prost(string, tag = "4")] + pub page_token: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct JournalSummary { + #[prost(int64, tag = "1")] + pub journal_id: i64, + #[prost(string, tag = "2")] + pub journal_name: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub currency: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub description: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub total_debit: ::prost::alloc::string::String, + #[prost(string, tag = "6")] + pub total_credit: ::prost::alloc::string::String, + #[prost(string, tag = "7")] + pub balance: ::prost::alloc::string::String, + #[prost(int64, tag = "8")] + pub active_line_count: i64, + #[prost(bool, tag = "9")] + pub locked: bool, + #[prost(string, tag = "10")] + pub created_at: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct SearchJournalsResponse { + #[prost(message, repeated, tag = "1")] + pub journals: ::prost::alloc::vec::Vec, + #[prost(int64, tag = "2")] + pub total_count: i64, + #[prost(string, tag = "3")] + pub next_page_token: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct AccountingStatus { #[prost(bool, tag = "1")] pub all_journals_balanced: bool, @@ -105,6 +155,8 @@ pub struct UnbalancedJournalSummary { pub active_line_count: i64, #[prost(string, tag = "10")] pub created_at: ::prost::alloc::string::String, + #[prost(string, tag = "11")] + pub journal_name: ::prost::alloc::string::String, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct ListUnbalancedJournalsResponse { @@ -180,6 +232,8 @@ pub struct Journal { pub locked_at: ::prost::alloc::string::String, #[prost(string, tag = "12")] pub locked_by_user_id: ::prost::alloc::string::String, + #[prost(string, tag = "13")] + pub journal_name: ::prost::alloc::string::String, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] @@ -371,6 +425,34 @@ pub mod accounting_client { .insert(GrpcMethod::new("komp_ac.accounting.Accounting", "GetJournal")); self.inner.unary(req, path, codec).await } + /// Search profile journals by user-facing name while retaining journal ids + /// as the stable relationship keys. + pub async fn search_journals( + &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.accounting.Accounting/SearchJournals", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("komp_ac.accounting.Accounting", "SearchJournals"), + ); + self.inner.unary(req, path, codec).await + } /// Return the profile-wide count of balanced and unbalanced journals. pub async fn get_accounting_status( &mut self, @@ -490,6 +572,15 @@ pub mod accounting_server { &self, request: tonic::Request, ) -> std::result::Result, tonic::Status>; + /// Search profile journals by user-facing name while retaining journal ids + /// as the stable relationship keys. + async fn search_journals( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; /// Return the profile-wide count of balanced and unbalanced journals. async fn get_accounting_status( &self, @@ -725,6 +816,51 @@ pub mod accounting_server { }; Box::pin(fut) } + "/komp_ac.accounting.Accounting/SearchJournals" => { + #[allow(non_camel_case_types)] + struct SearchJournalsSvc(pub Arc); + impl< + T: Accounting, + > tonic::server::UnaryService + for SearchJournalsSvc { + type Response = super::SearchJournalsResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::search_journals(&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 = SearchJournalsSvc(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.accounting.Accounting/GetAccountingStatus" => { #[allow(non_camel_case_types)] struct GetAccountingStatusSvc(pub Arc); diff --git a/tui-pages b/tui-pages index 30b2bf7..cfce2e5 160000 --- a/tui-pages +++ b/tui-pages @@ -1 +1 @@ -Subproject commit 30b2bf78914c0a18a872e0680059e7fd4bd18867 +Subproject commit cfce2e590b2277e0defcc0efbc3b227c0060d141