Basic framework for executing reports
This commit is contained in:
parent
9e34360abf
commit
db89814498
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -82,6 +82,12 @@ version = "0.1.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c2d035d21af5cde1a6f5c7b444a5bf963520a9f142e5d06931178433d7d5388"
|
checksum = "5c2d035d21af5cde1a6f5c7b444a5bf963520a9f142e5d06931178433d7d5388"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dyn-hash"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "15401da73a9ed8c80e3b2d4dc05fe10e7b72d7243b9f614e516a44fa99986e88"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iana-time-zone"
|
name = "iana-time-zone"
|
||||||
version = "0.1.63"
|
version = "0.1.63"
|
||||||
@ -130,6 +136,7 @@ dependencies = [
|
|||||||
"downcast-rs",
|
"downcast-rs",
|
||||||
"dyn-clone",
|
"dyn-clone",
|
||||||
"dyn-eq",
|
"dyn-eq",
|
||||||
|
"dyn-hash",
|
||||||
"solvent",
|
"solvent",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -8,4 +8,5 @@ chrono = "0.4.41"
|
|||||||
downcast-rs = "2.0.1"
|
downcast-rs = "2.0.1"
|
||||||
dyn-clone = "1.0.19"
|
dyn-clone = "1.0.19"
|
||||||
dyn-eq = "0.1.3"
|
dyn-eq = "0.1.3"
|
||||||
|
dyn-hash = "0.2.2"
|
||||||
solvent = "0.8.3"
|
solvent = "0.8.3"
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
pub mod reporting;
|
pub mod reporting;
|
||||||
pub mod transaction;
|
pub mod transaction;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
|
pub type QuantityInt = u64;
|
||||||
|
40
src/main.rs
40
src/main.rs
@ -18,13 +18,12 @@
|
|||||||
|
|
||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
use libdrcr::reporting::builders::register_dynamic_builders;
|
use libdrcr::reporting::builders::register_dynamic_builders;
|
||||||
use libdrcr::reporting::calculator::steps_for_targets;
|
use libdrcr::reporting::generate_report;
|
||||||
use libdrcr::reporting::steps::{
|
use libdrcr::reporting::steps::{
|
||||||
register_lookup_fns, AllTransactionsExceptRetainedEarnings,
|
register_lookup_fns, AllTransactionsExceptRetainedEarnings, CalculateIncomeTax,
|
||||||
AllTransactionsIncludingRetainedEarnings, CalculateIncomeTax,
|
|
||||||
};
|
};
|
||||||
use libdrcr::reporting::types::{
|
use libdrcr::reporting::types::{
|
||||||
DateArgs, DateStartDateEndArgs, ReportingContext, ReportingProductKind, ReportingStep,
|
DateStartDateEndArgs, ReportingContext, ReportingProductKind, ReportingStep,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -43,36 +42,7 @@ fn main() {
|
|||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
println!("For income statement:");
|
let products = generate_report(targets, &context);
|
||||||
match steps_for_targets(targets, context) {
|
|
||||||
Ok(steps) => {
|
|
||||||
for step in steps {
|
|
||||||
println!("- {}", step);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => panic!("Error: {:?}", err),
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut context = ReportingContext::new(NaiveDate::from_ymd_opt(2025, 6, 30).unwrap());
|
println!("{:?}", products);
|
||||||
register_lookup_fns(&mut context);
|
|
||||||
register_dynamic_builders(&mut context);
|
|
||||||
|
|
||||||
let targets: Vec<Box<dyn ReportingStep>> = vec![
|
|
||||||
Box::new(CalculateIncomeTax {}),
|
|
||||||
Box::new(AllTransactionsIncludingRetainedEarnings {
|
|
||||||
args: DateArgs {
|
|
||||||
date: NaiveDate::from_ymd_opt(2025, 6, 30).unwrap(),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
|
|
||||||
println!("For balance sheet:");
|
|
||||||
match steps_for_targets(targets, context) {
|
|
||||||
Ok(steps) => {
|
|
||||||
for step in steps {
|
|
||||||
println!("- {}", step);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(err) => panic!("Error: {:?}", err),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -150,7 +150,7 @@ fn would_be_ready_to_execute(
|
|||||||
/// Recursively resolve the dependencies of the target [ReportingStep]s and return a sorted [Vec] of [ReportingStep]s
|
/// Recursively resolve the dependencies of the target [ReportingStep]s and return a sorted [Vec] of [ReportingStep]s
|
||||||
pub fn steps_for_targets(
|
pub fn steps_for_targets(
|
||||||
targets: Vec<Box<dyn ReportingStep>>,
|
targets: Vec<Box<dyn ReportingStep>>,
|
||||||
context: ReportingContext,
|
context: &ReportingContext,
|
||||||
) -> Result<Vec<Box<dyn ReportingStep>>, ReportingCalculationError> {
|
) -> Result<Vec<Box<dyn ReportingStep>>, ReportingCalculationError> {
|
||||||
let mut steps: Vec<Box<dyn ReportingStep>> = Vec::new();
|
let mut steps: Vec<Box<dyn ReportingStep>> = Vec::new();
|
||||||
let mut dependencies = ReportingGraphDependencies { vec: Vec::new() };
|
let mut dependencies = ReportingGraphDependencies { vec: Vec::new() };
|
||||||
|
37
src/reporting/executor.rs
Normal file
37
src/reporting/executor.rs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
DrCr: Web-based double-entry bookkeeping framework
|
||||||
|
Copyright (C) 2022-2025 Lee Yingtong Li (RunasSudo)
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use super::types::{ReportingContext, ReportingProducts, ReportingStep};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ReportingExecutionError {
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute_steps(
|
||||||
|
steps: Vec<Box<dyn ReportingStep>>,
|
||||||
|
context: &ReportingContext,
|
||||||
|
) -> Result<ReportingProducts, ReportingExecutionError> {
|
||||||
|
let mut products = ReportingProducts::new();
|
||||||
|
|
||||||
|
for step in steps {
|
||||||
|
step.execute(context, &mut products)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(products)
|
||||||
|
}
|
@ -16,7 +16,43 @@
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use calculator::{steps_for_targets, ReportingCalculationError};
|
||||||
|
use executor::{execute_steps, ReportingExecutionError};
|
||||||
|
use types::{ReportingContext, ReportingProducts, ReportingStep};
|
||||||
|
|
||||||
pub mod builders;
|
pub mod builders;
|
||||||
pub mod calculator;
|
pub mod calculator;
|
||||||
|
pub mod executor;
|
||||||
pub mod steps;
|
pub mod steps;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ReportingError {
|
||||||
|
ReportingCalculationError(ReportingCalculationError),
|
||||||
|
ReportingExecutionError(ReportingExecutionError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ReportingCalculationError> for ReportingError {
|
||||||
|
fn from(err: ReportingCalculationError) -> Self {
|
||||||
|
ReportingError::ReportingCalculationError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ReportingExecutionError> for ReportingError {
|
||||||
|
fn from(err: ReportingExecutionError) -> Self {
|
||||||
|
ReportingError::ReportingExecutionError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_report(
|
||||||
|
targets: Vec<Box<dyn ReportingStep>>,
|
||||||
|
context: &ReportingContext,
|
||||||
|
) -> Result<ReportingProducts, ReportingError> {
|
||||||
|
// Solve dependencies
|
||||||
|
let sorted_steps = steps_for_targets(targets, context)?;
|
||||||
|
|
||||||
|
// Execute steps
|
||||||
|
let products = execute_steps(sorted_steps, context)?;
|
||||||
|
|
||||||
|
Ok(products)
|
||||||
|
}
|
||||||
|
@ -16,15 +16,22 @@
|
|||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use chrono::Datelike;
|
use chrono::Datelike;
|
||||||
|
|
||||||
use crate::reporting::types::{BalancesAt, DateStartDateEndArgs, ReportingProduct, ReportingProductId};
|
use crate::reporting::types::{
|
||||||
|
BalancesAt, DateStartDateEndArgs, ReportingProduct, ReportingProductId,
|
||||||
|
};
|
||||||
use crate::util::sofy_from_eofy;
|
use crate::util::sofy_from_eofy;
|
||||||
|
|
||||||
use super::calculator::ReportingGraphDependencies;
|
use super::calculator::ReportingGraphDependencies;
|
||||||
use super::types::{DateArgs, ReportingContext, ReportingProductKind, ReportingProducts, ReportingStep, ReportingStepArgs, ReportingStepId, VoidArgs};
|
use super::executor::ReportingExecutionError;
|
||||||
|
use super::types::{
|
||||||
|
DateArgs, ReportingContext, ReportingProductKind, ReportingProducts, ReportingStep,
|
||||||
|
ReportingStepArgs, ReportingStepId, VoidArgs,
|
||||||
|
};
|
||||||
|
|
||||||
pub fn register_lookup_fns(context: &mut ReportingContext) {
|
pub fn register_lookup_fns(context: &mut ReportingContext) {
|
||||||
context.register_lookup_fn(
|
context.register_lookup_fn(
|
||||||
@ -322,6 +329,29 @@ impl ReportingStep for DBBalances {
|
|||||||
args: Box::new(self.args.clone()),
|
args: Box::new(self.args.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn execute(
|
||||||
|
&self,
|
||||||
|
_context: &ReportingContext,
|
||||||
|
products: &mut ReportingProducts,
|
||||||
|
) -> Result<(), ReportingExecutionError> {
|
||||||
|
eprintln!("Stub: DBBalances.execute");
|
||||||
|
|
||||||
|
let balances = BalancesAt {
|
||||||
|
balances: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
products.insert(
|
||||||
|
ReportingProductId {
|
||||||
|
name: self.id().name,
|
||||||
|
kind: ReportingProductKind::BalancesAt,
|
||||||
|
args: Box::new(self.args.clone()),
|
||||||
|
},
|
||||||
|
ReportingProduct::BalancesAt(balances),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -28,6 +28,7 @@ use dyn_hash::DynHash;
|
|||||||
use crate::QuantityInt;
|
use crate::QuantityInt;
|
||||||
|
|
||||||
use super::calculator::ReportingGraphDependencies;
|
use super::calculator::ReportingGraphDependencies;
|
||||||
|
use super::executor::ReportingExecutionError;
|
||||||
|
|
||||||
// -----------------
|
// -----------------
|
||||||
// REPORTING CONTEXT
|
// REPORTING CONTEXT
|
||||||
@ -143,6 +144,7 @@ pub enum ReportingProductKind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the result of a [ReportingStep]
|
/// Represents the result of a [ReportingStep]
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum ReportingProduct {
|
pub enum ReportingProduct {
|
||||||
Transactions(Transactions),
|
Transactions(Transactions),
|
||||||
BalancesAt(BalancesAt),
|
BalancesAt(BalancesAt),
|
||||||
@ -151,18 +153,21 @@ pub enum ReportingProduct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Records a list of transactions generated by a [ReportingStep]
|
/// Records a list of transactions generated by a [ReportingStep]
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Transactions {}
|
pub struct Transactions {}
|
||||||
|
|
||||||
/// Records cumulative account balances at a particular point in time
|
/// Records cumulative account balances at a particular point in time
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct BalancesAt {
|
pub struct BalancesAt {
|
||||||
pub balances: HashMap<String, QuantityInt>,
|
pub balances: HashMap<String, QuantityInt>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Records the total value of transactions in each account between two points in time
|
/// Records the total value of transactions in each account between two points in time
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct BalancesBetween {}
|
pub struct BalancesBetween {}
|
||||||
|
|
||||||
/// Represents a custom [ReportingProduct] generated by a [ReportingStep]
|
/// Represents a custom [ReportingProduct] generated by a [ReportingStep]
|
||||||
pub trait GenericReportingProduct {}
|
pub trait GenericReportingProduct: Debug {}
|
||||||
|
|
||||||
/// Convenience type mapping [ReportingProductId] to [ReportingProduct]
|
/// Convenience type mapping [ReportingProductId] to [ReportingProduct]
|
||||||
pub type ReportingProducts = HashMap<ReportingProductId, ReportingProduct>;
|
pub type ReportingProducts = HashMap<ReportingProductId, ReportingProduct>;
|
||||||
@ -222,8 +227,12 @@ pub trait ReportingStep: Debug + Display + Downcast {
|
|||||||
|
|
||||||
/// Called to generate the [ReportingProduct] for this [ReportingStep]
|
/// Called to generate the [ReportingProduct] for this [ReportingStep]
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn execute(&self, context: &ReportingContext, products: &mut ReportingProducts) {
|
fn execute(
|
||||||
todo!();
|
&self,
|
||||||
|
context: &ReportingContext,
|
||||||
|
products: &mut ReportingProducts,
|
||||||
|
) -> Result<(), ReportingExecutionError> {
|
||||||
|
todo!("{}", self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user