From 1c6183cf0997bb939034d19767354466d91d4118 Mon Sep 17 00:00:00 2001 From: Priec Date: Mon, 20 Jul 2026 16:49:05 +0200 Subject: [PATCH] accounting kernel3 --- common/proto/accounting.proto | 56 ++++++ common/src/proto/descriptor.bin | Bin 121715 -> 125041 bytes common/src/proto/komp_ac.accounting.rs | 235 +++++++++++++++++++++++++ 3 files changed, 291 insertions(+) diff --git a/common/proto/accounting.proto b/common/proto/accounting.proto index 82e0a46..5ad5851 100644 --- a/common/proto/accounting.proto +++ b/common/proto/accounting.proto @@ -10,6 +10,13 @@ service Accounting { // Return journal lines and credits-minus-debits informational balance. rpc GetJournal(GetJournalRequest) returns (Journal); + // Return the profile-wide count of balanced and unbalanced journals. + rpc GetAccountingStatus(GetAccountingStatusRequest) returns (AccountingStatus); + + // Return an oldest-first, paginated queue of unbalanced journals. + rpc ListUnbalancedJournals(ListUnbalancedJournalsRequest) + returns (ListUnbalancedJournalsResponse); + // Append one manual debit or credit line to an existing journal. rpc AddJournalLine(AddJournalLineRequest) returns (Journal); @@ -39,6 +46,55 @@ message GetJournalRequest { bool include_deleted = 3; } +message GetAccountingStatusRequest { + string profile_name = 1; +} + +message AccountingStatus { + bool all_journals_balanced = 1; + int64 journal_count = 2; + int64 balanced_journal_count = 3; + int64 unbalanced_journal_count = 4; + string calculated_at = 5; +} + +message ListUnbalancedJournalsRequest { + string profile_name = 1; + + // Zero uses 50. The maximum is 500. + int32 page_size = 2; + + // Opaque cursor returned by the previous response. Empty starts at the + // oldest unbalanced journal. + string page_token = 3; + + // Optional ISO 4217 currency filter. Empty includes every currency. + string currency = 4; +} + +message UnbalancedJournalSummary { + int64 journal_id = 1; + string description = 2; + string currency = 3; + string total_debit = 4; + string total_credit = 5; + + // Signed credits-minus-debits difference. + string balance = 6; + + // Side and positive amount needed to make the journal balance zero. + JournalSide missing_side = 7; + string missing_amount = 8; + int64 active_line_count = 9; + string created_at = 10; +} + +message ListUnbalancedJournalsResponse { + repeated UnbalancedJournalSummary journals = 1; + int64 total_unbalanced_count = 2; + string next_page_token = 3; +} + message AddJournalLineRequest { string profile_name = 1; int64 journal_id = 2; diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index 3e26fae03bf7b1987a89fb7954381e7254432ef0..dc71e2f07465f5ed41e10b809d5419f3dc621d56 100644 GIT binary patch delta 5611 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 delta 2477 zcmX|?xpE{$5Qe*}s%LsyqpMjRGrC5xBQ2|wSV@HLYb03R3ayR98*K0ZZSV+VVDJDK zSi}b4i_&yx5a-S|6n`mhcB{cXZ|() zi{j`0A49)1{%RGq(k02e{*TR0I{xAJ=C^5aSGZbYOlgPvUya^un3TV2FN$W7$-m|Q z6DtE{Q9Fmll}8X`{Xa)P-?SiOwHa-)AY-$;10`L(>*6^rOqP^xDw*kjIrdylWn;xq z;j+XerJXhl(k_Bg)22O8jGCUC*G5V$)6!DvmA46&(%71s)<#4-&XD`G&4gldpZ0XC z=oW=>*qKWf)1oM>lY{5-S()Ixr+L%<=KH&JwF>{CykI6}3gt8tl@FBE8sh`Sg%@5- z=pc^k1kYdwtP?RY)@k?~NDZvR4a8Skx|hkT;47_YdzrWVyi}Ie4Oepr=5=)*ipFlk zUsP($>vBfsJ-qx?vhLgS`JgcW-gl7#}RHZ>zixJ}K7E!~^s)39VQ^(OE7c~+LZ zrS=ib+fo}S8n@Ivig8=&-pWF@by*0o?Xcs@A*HBGM!{|CwygZ1cFe5583JxcpA8CZ zCl9ehf$g+sd_-L7c9YM7d)duy9=74c{hkSnLNKn{(|Jfb_wvG@g<{^`@QA;)lcV;{ zw3fvFe#FH6J_pEemqxJt$tlHff1tM}XGG*cBN9?~Fj7{^iTwk;wG(luOGa?qp)MK4 zafiBOlyvHnokZkFBZ2@sikPh7NFzcG?8rx?a+s#`STlm~Dr5u&cdQXX!5xPeAsF{L zF@uZOz)tk%O9||xKBAYaft`$(x|DipPvb7DI^1crS%*7q3})8hPUAB3(w;>w2Rn;c z4t5r?9PBJ&jnbZ*jyh?8oky&ZmX$qk`0oMtX~3P&EvU_+v^_JgTmjdMkG$ZxUOtFJ z0oI!dFCk}!N_$}z6&nJ(h}aO=MIPRFG=g2sR~tH!G=s6l{sNMrI`Tk8!mU`$txL!^br<#Qv%87JIMc d@gpIh;(-$Ur^c9%1~tH^uir0z_kJ<`^?y2Bk~07R diff --git a/common/src/proto/komp_ac.accounting.rs b/common/src/proto/komp_ac.accounting.rs index 7839d8c..e83e445 100644 --- a/common/src/proto/komp_ac.accounting.rs +++ b/common/src/proto/komp_ac.accounting.rs @@ -18,6 +18,73 @@ pub struct GetJournalRequest { pub include_deleted: bool, } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct GetAccountingStatusRequest { + #[prost(string, tag = "1")] + pub profile_name: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct AccountingStatus { + #[prost(bool, tag = "1")] + pub all_journals_balanced: bool, + #[prost(int64, tag = "2")] + pub journal_count: i64, + #[prost(int64, tag = "3")] + pub balanced_journal_count: i64, + #[prost(int64, tag = "4")] + pub unbalanced_journal_count: i64, + #[prost(string, tag = "5")] + pub calculated_at: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ListUnbalancedJournalsRequest { + #[prost(string, tag = "1")] + pub profile_name: ::prost::alloc::string::String, + /// Zero uses 50. The maximum is 500. + #[prost(int32, tag = "2")] + pub page_size: i32, + /// Opaque cursor returned by the previous response. Empty starts at the + /// oldest unbalanced journal. + #[prost(string, tag = "3")] + pub page_token: ::prost::alloc::string::String, + /// Optional ISO 4217 currency filter. Empty includes every currency. + #[prost(string, tag = "4")] + pub currency: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct UnbalancedJournalSummary { + #[prost(int64, tag = "1")] + pub journal_id: i64, + #[prost(string, tag = "2")] + pub description: ::prost::alloc::string::String, + #[prost(string, tag = "3")] + pub currency: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub total_debit: ::prost::alloc::string::String, + #[prost(string, tag = "5")] + pub total_credit: ::prost::alloc::string::String, + /// Signed credits-minus-debits difference. + #[prost(string, tag = "6")] + pub balance: ::prost::alloc::string::String, + /// Side and positive amount needed to make the journal balance zero. + #[prost(enumeration = "JournalSide", tag = "7")] + pub missing_side: i32, + #[prost(string, tag = "8")] + pub missing_amount: ::prost::alloc::string::String, + #[prost(int64, tag = "9")] + pub active_line_count: i64, + #[prost(string, tag = "10")] + pub created_at: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListUnbalancedJournalsResponse { + #[prost(message, repeated, tag = "1")] + pub journals: ::prost::alloc::vec::Vec, + #[prost(int64, tag = "2")] + pub total_unbalanced_count: i64, + #[prost(string, tag = "3")] + pub next_page_token: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct AddJournalLineRequest { #[prost(string, tag = "1")] pub profile_name: ::prost::alloc::string::String, @@ -260,6 +327,66 @@ pub mod accounting_client { .insert(GrpcMethod::new("komp_ac.accounting.Accounting", "GetJournal")); 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, + 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/GetAccountingStatus", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "komp_ac.accounting.Accounting", + "GetAccountingStatus", + ), + ); + self.inner.unary(req, path, codec).await + } + /// Return an oldest-first, paginated queue of unbalanced journals. + pub async fn list_unbalanced_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/ListUnbalancedJournals", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new( + "komp_ac.accounting.Accounting", + "ListUnbalancedJournals", + ), + ); + self.inner.unary(req, path, codec).await + } /// Append one manual debit or credit line to an existing journal. pub async fn add_journal_line( &mut self, @@ -336,6 +463,22 @@ pub mod accounting_server { &self, request: tonic::Request, ) -> std::result::Result, tonic::Status>; + /// Return the profile-wide count of balanced and unbalanced journals. + async fn get_accounting_status( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Return an oldest-first, paginated queue of unbalanced journals. + async fn list_unbalanced_journals( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; /// Append one manual debit or credit line to an existing journal. async fn add_journal_line( &self, @@ -515,6 +658,98 @@ pub mod accounting_server { }; Box::pin(fut) } + "/komp_ac.accounting.Accounting/GetAccountingStatus" => { + #[allow(non_camel_case_types)] + struct GetAccountingStatusSvc(pub Arc); + impl< + T: Accounting, + > tonic::server::UnaryService + for GetAccountingStatusSvc { + type Response = super::AccountingStatus; + 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 { + ::get_accounting_status(&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 = GetAccountingStatusSvc(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/ListUnbalancedJournals" => { + #[allow(non_camel_case_types)] + struct ListUnbalancedJournalsSvc(pub Arc); + impl< + T: Accounting, + > tonic::server::UnaryService + for ListUnbalancedJournalsSvc { + type Response = super::ListUnbalancedJournalsResponse; + 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 { + ::list_unbalanced_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 = ListUnbalancedJournalsSvc(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/AddJournalLine" => { #[allow(non_camel_case_types)] struct AddJournalLineSvc(pub Arc);