diff --git a/common/proto/accounting.proto b/common/proto/accounting.proto index cf9cd00..64ec40d 100644 --- a/common/proto/accounting.proto +++ b/common/proto/accounting.proto @@ -39,10 +39,15 @@ service Accounting { returns (AccountingPeriod); // Closing snapshots balances and blocks mutations through the period end. - // A closed period may be reopened; approval makes it final. + // A closed period may be reopened until the profile is approved. rpc CloseAccountingPeriod(CloseAccountingPeriodRequest) returns (AccountingPeriod); rpc ReopenAccountingPeriod(ReopenAccountingPeriodRequest) returns (AccountingPeriod); - rpc ApproveAccountingPeriod(ApproveAccountingPeriodRequest) returns (AccountingPeriod); + + // Approves the profile's financial statement. One profile is one accounting + // period, and approval happens once for it, not once per period inside it. + // Every period must be closed first, and none may be reopened afterwards. + rpc ApproveProfile(ApproveProfileRequest) returns (ProfileApproval); + rpc GetProfileApproval(GetProfileApprovalRequest) returns (ProfileApproval); rpc GetAccountingPeriod(GetAccountingPeriodRequest) returns (AccountingPeriod); rpc ListAccountingPeriods(ListAccountingPeriodsRequest) @@ -56,11 +61,12 @@ enum JournalSide { JOURNAL_SIDE_CREDIT = 2; } +// A period is only ever open or closed. Approval is a fact about the whole +// profile, because the profile is the accounting period being reported on. enum AccountingPeriodStatus { ACCOUNTING_PERIOD_STATUS_UNSPECIFIED = 0; ACCOUNTING_PERIOD_STATUS_OPEN = 1; ACCOUNTING_PERIOD_STATUS_CLOSED = 2; - ACCOUNTING_PERIOD_STATUS_APPROVED = 3; } // How long one accounting period lasts. MONTH and YEAR span whole months, so @@ -261,7 +267,6 @@ message ConfigureAccountingPeriodRequest { string profile_name = 1; // First day of the period, YYYY-MM-DD. Must be the first day of a month. string period_start = 2; - reserved 3; // Optional link to the preceding period in a carry chain. optional int64 previous_period_id = 4; // Required. Decides the length of the period. @@ -279,8 +284,21 @@ message ReopenAccountingPeriodRequest { int64 period_id = 1; } -message ApproveAccountingPeriodRequest { - int64 period_id = 1; +message ApproveProfileRequest { + string profile_name = 1; +} + +message GetProfileApprovalRequest { + string profile_name = 1; +} + +// Approval state of one profile's financial statement. +message ProfileApproval { + string profile_name = 1; + bool approved = 2; + // Empty while the profile is unapproved. + string approved_at = 3; + string approved_by_user_id = 4; } message GetAccountingPeriodRequest { @@ -304,8 +322,6 @@ message AccountingPeriod { int64 previous_period_id = 6; string closed_at = 7; string closed_by_user_id = 8; - string approved_at = 9; - string approved_by_user_id = 10; AccountingPeriodType period_type = 11; } diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index d16f322..bc4d217 100644 Binary files a/common/src/proto/descriptor.bin and b/common/src/proto/descriptor.bin differ diff --git a/common/src/proto/komp_ac.accounting.rs b/common/src/proto/komp_ac.accounting.rs index 8f82501..c038859 100644 --- a/common/src/proto/komp_ac.accounting.rs +++ b/common/src/proto/komp_ac.accounting.rs @@ -280,10 +280,28 @@ pub struct ReopenAccountingPeriodRequest { #[prost(int64, tag = "1")] pub period_id: i64, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] -pub struct ApproveAccountingPeriodRequest { - #[prost(int64, tag = "1")] - pub period_id: i64, +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ApproveProfileRequest { + #[prost(string, tag = "1")] + pub profile_name: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct GetProfileApprovalRequest { + #[prost(string, tag = "1")] + pub profile_name: ::prost::alloc::string::String, +} +/// Approval state of one profile's financial statement. +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct ProfileApproval { + #[prost(string, tag = "1")] + pub profile_name: ::prost::alloc::string::String, + #[prost(bool, tag = "2")] + pub approved: bool, + /// Empty while the profile is unapproved. + #[prost(string, tag = "3")] + pub approved_at: ::prost::alloc::string::String, + #[prost(string, tag = "4")] + pub approved_by_user_id: ::prost::alloc::string::String, } #[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)] pub struct GetAccountingPeriodRequest { @@ -318,10 +336,6 @@ pub struct AccountingPeriod { pub closed_at: ::prost::alloc::string::String, #[prost(string, tag = "8")] pub closed_by_user_id: ::prost::alloc::string::String, - #[prost(string, tag = "9")] - pub approved_at: ::prost::alloc::string::String, - #[prost(string, tag = "10")] - pub approved_by_user_id: ::prost::alloc::string::String, #[prost(enumeration = "AccountingPeriodType", tag = "11")] pub period_type: i32, } @@ -382,13 +396,14 @@ impl JournalSide { } } } +/// A period is only ever open or closed. Approval is a fact about the whole +/// profile, because the profile is the accounting period being reported on. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)] #[repr(i32)] pub enum AccountingPeriodStatus { Unspecified = 0, Open = 1, Closed = 2, - Approved = 3, } impl AccountingPeriodStatus { /// String value of the enum field names used in the ProtoBuf definition. @@ -400,7 +415,6 @@ impl AccountingPeriodStatus { Self::Unspecified => "ACCOUNTING_PERIOD_STATUS_UNSPECIFIED", Self::Open => "ACCOUNTING_PERIOD_STATUS_OPEN", Self::Closed => "ACCOUNTING_PERIOD_STATUS_CLOSED", - Self::Approved => "ACCOUNTING_PERIOD_STATUS_APPROVED", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -409,7 +423,6 @@ impl AccountingPeriodStatus { "ACCOUNTING_PERIOD_STATUS_UNSPECIFIED" => Some(Self::Unspecified), "ACCOUNTING_PERIOD_STATUS_OPEN" => Some(Self::Open), "ACCOUNTING_PERIOD_STATUS_CLOSED" => Some(Self::Closed), - "ACCOUNTING_PERIOD_STATUS_APPROVED" => Some(Self::Approved), _ => None, } } @@ -790,7 +803,7 @@ pub mod accounting_client { self.inner.unary(req, path, codec).await } /// Closing snapshots balances and blocks mutations through the period end. - /// A closed period may be reopened; approval makes it final. + /// A closed period may be reopened until the profile is approved. pub async fn close_accounting_period( &mut self, request: impl tonic::IntoRequest, @@ -849,11 +862,14 @@ pub mod accounting_client { ); self.inner.unary(req, path, codec).await } - pub async fn approve_accounting_period( + /// Approves the profile's financial statement. One profile is one accounting + /// period, and approval happens once for it, not once per period inside it. + /// Every period must be closed first, and none may be reopened afterwards. + pub async fn approve_profile( &mut self, - request: impl tonic::IntoRequest, + request: impl tonic::IntoRequest, ) -> std::result::Result< - tonic::Response, + tonic::Response, tonic::Status, > { self.inner @@ -866,14 +882,40 @@ pub mod accounting_client { })?; let codec = tonic_prost::ProstCodec::default(); let path = http::uri::PathAndQuery::from_static( - "/komp_ac.accounting.Accounting/ApproveAccountingPeriod", + "/komp_ac.accounting.Accounting/ApproveProfile", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("komp_ac.accounting.Accounting", "ApproveProfile"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn get_profile_approval( + &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/GetProfileApproval", ); let mut req = request.into_request(); req.extensions_mut() .insert( GrpcMethod::new( "komp_ac.accounting.Accounting", - "ApproveAccountingPeriod", + "GetProfileApproval", ), ); self.inner.unary(req, path, codec).await @@ -1041,7 +1083,7 @@ pub mod accounting_server { tonic::Status, >; /// Closing snapshots balances and blocks mutations through the period end. - /// A closed period may be reopened; approval makes it final. + /// A closed period may be reopened until the profile is approved. async fn close_accounting_period( &self, request: tonic::Request, @@ -1056,13 +1098,17 @@ pub mod accounting_server { tonic::Response, tonic::Status, >; - async fn approve_accounting_period( + /// Approves the profile's financial statement. One profile is one accounting + /// period, and approval happens once for it, not once per period inside it. + /// Every period must be closed first, and none may be reopened afterwards. + async fn approve_profile( &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + async fn get_profile_approval( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; async fn get_accounting_period( &self, request: tonic::Request, @@ -1673,30 +1719,70 @@ pub mod accounting_server { }; Box::pin(fut) } - "/komp_ac.accounting.Accounting/ApproveAccountingPeriod" => { + "/komp_ac.accounting.Accounting/ApproveProfile" => { #[allow(non_camel_case_types)] - struct ApproveAccountingPeriodSvc(pub Arc); + struct ApproveProfileSvc(pub Arc); impl< T: Accounting, - > tonic::server::UnaryService - for ApproveAccountingPeriodSvc { - type Response = super::AccountingPeriod; + > tonic::server::UnaryService + for ApproveProfileSvc { + type Response = super::ProfileApproval; type Future = BoxFuture< tonic::Response, tonic::Status, >; fn call( &mut self, - request: tonic::Request< - super::ApproveAccountingPeriodRequest, - >, + request: tonic::Request, ) -> Self::Future { let inner = Arc::clone(&self.0); let fut = async move { - ::approve_accounting_period( - &inner, - request, - ) + ::approve_profile(&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 = ApproveProfileSvc(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/GetProfileApproval" => { + #[allow(non_camel_case_types)] + struct GetProfileApprovalSvc(pub Arc); + impl< + T: Accounting, + > tonic::server::UnaryService + for GetProfileApprovalSvc { + type Response = super::ProfileApproval; + 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_profile_approval(&inner, request) .await }; Box::pin(fut) @@ -1708,7 +1794,7 @@ pub mod accounting_server { let max_encoding_message_size = self.max_encoding_message_size; let inner = self.inner.clone(); let fut = async move { - let method = ApproveAccountingPeriodSvc(inner); + let method = GetProfileApprovalSvc(inner); let codec = tonic_prost::ProstCodec::default(); let mut grpc = tonic::server::Grpc::new(codec) .apply_compression_config( diff --git a/server b/server index 828c338..7a1a8f9 160000 --- a/server +++ b/server @@ -1 +1 @@ -Subproject commit 828c3382b97ceb25c055e7f4d9a7a98f3182477e +Subproject commit 7a1a8f9742b0f0c18f3106d8b14ad07bb6fd974a