Implement GenerateBalances dynamic builder
This commit is contained in:
parent
a7e9c74dd1
commit
4add6292a1
@ -29,6 +29,12 @@ pub fn register_dynamic_builders(context: &mut ReportingContext) {
|
||||
build: BalancesAtToBalancesBetween::build,
|
||||
});
|
||||
|
||||
context.register_dynamic_builder(ReportingStepDynamicBuilder {
|
||||
name: "GenerateBalances",
|
||||
can_build: GenerateBalances::can_build,
|
||||
build: GenerateBalances::build,
|
||||
});
|
||||
|
||||
context.register_dynamic_builder(ReportingStepDynamicBuilder {
|
||||
name: "UpdateBalancesBetween",
|
||||
can_build: UpdateBalancesBetween::can_build,
|
||||
@ -55,11 +61,15 @@ impl BalancesAtToBalancesBetween {
|
||||
) -> bool {
|
||||
// Check for BalancesAt, BalancesAt -> BalancesBetween
|
||||
if kind == ReportingProductKind::BalancesBetween {
|
||||
let args = args.downcast_ref::<DateStartDateEndArgs>().unwrap();
|
||||
|
||||
match has_step_or_can_build(
|
||||
&ReportingProductId {
|
||||
name,
|
||||
kind: ReportingProductKind::BalancesAt,
|
||||
args: args.clone(),
|
||||
args: Box::new(DateArgs {
|
||||
date: args.date_start.clone(),
|
||||
}),
|
||||
},
|
||||
steps,
|
||||
dependencies,
|
||||
@ -100,14 +110,9 @@ impl ReportingStep for BalancesAtToBalancesBetween {
|
||||
}
|
||||
}
|
||||
|
||||
fn init_graph(
|
||||
&self,
|
||||
_steps: &Vec<Box<dyn ReportingStep>>,
|
||||
dependencies: &mut ReportingGraphDependencies,
|
||||
) {
|
||||
fn requires(&self) -> Vec<ReportingProductId> {
|
||||
// BalancesAtToBalancesBetween depends on BalancesAt at both time points
|
||||
dependencies.add_dependency(
|
||||
self.id(),
|
||||
vec![
|
||||
ReportingProductId {
|
||||
name: self.step_name,
|
||||
kind: ReportingProductKind::BalancesAt,
|
||||
@ -115,9 +120,6 @@ impl ReportingStep for BalancesAtToBalancesBetween {
|
||||
date: self.args.date_start.clone(),
|
||||
}),
|
||||
},
|
||||
);
|
||||
dependencies.add_dependency(
|
||||
self.id(),
|
||||
ReportingProductId {
|
||||
name: self.step_name,
|
||||
kind: ReportingProductKind::BalancesAt,
|
||||
@ -125,7 +127,89 @@ impl ReportingStep for BalancesAtToBalancesBetween {
|
||||
date: self.args.date_end.clone(),
|
||||
}),
|
||||
},
|
||||
);
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GenerateBalances {
|
||||
step_name: &'static str,
|
||||
args: DateArgs,
|
||||
}
|
||||
|
||||
impl GenerateBalances {
|
||||
// Implements (() -> Transactions) -> BalancesAt
|
||||
|
||||
fn can_build(
|
||||
name: &'static str,
|
||||
kind: ReportingProductKind,
|
||||
args: &Box<dyn ReportingStepArgs>,
|
||||
steps: &Vec<Box<dyn ReportingStep>>,
|
||||
dependencies: &ReportingGraphDependencies,
|
||||
context: &ReportingContext,
|
||||
) -> bool {
|
||||
// Check for Transactions -> BalancesAt
|
||||
if kind == ReportingProductKind::BalancesAt {
|
||||
match has_step_or_can_build(
|
||||
&ReportingProductId {
|
||||
name,
|
||||
kind: ReportingProductKind::Transactions,
|
||||
args: args.clone(),
|
||||
},
|
||||
steps,
|
||||
dependencies,
|
||||
context,
|
||||
) {
|
||||
HasStepOrCanBuild::HasStep(step) => {
|
||||
// Check for () -> Transactions
|
||||
if dependencies.dependencies_for_step(&step.id()).len() == 0 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
HasStepOrCanBuild::CanLookup(lookup_fn) => {
|
||||
// Check for () -> Transactions
|
||||
let step = lookup_fn(args.clone());
|
||||
if step.requires().len() == 0 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
HasStepOrCanBuild::CanBuild(_) | HasStepOrCanBuild::None => {}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn build(
|
||||
name: &'static str,
|
||||
_kind: ReportingProductKind,
|
||||
args: Box<dyn ReportingStepArgs>,
|
||||
_steps: &Vec<Box<dyn ReportingStep>>,
|
||||
_dependencies: &ReportingGraphDependencies,
|
||||
_context: &ReportingContext,
|
||||
) -> Box<dyn ReportingStep> {
|
||||
Box::new(GenerateBalances {
|
||||
step_name: name,
|
||||
args: *args.downcast().unwrap(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ReportingStep for GenerateBalances {
|
||||
fn id(&self) -> ReportingStepId {
|
||||
ReportingStepId {
|
||||
name: self.step_name,
|
||||
product_kinds: &[ReportingProductKind::BalancesAt],
|
||||
args: Box::new(self.args.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
fn requires(&self) -> Vec<ReportingProductId> {
|
||||
// GenerateBalances depends on Transactions
|
||||
vec![ReportingProductId {
|
||||
name: self.step_name,
|
||||
kind: ReportingProductKind::Transactions,
|
||||
args: Box::new(self.args.clone()),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
use super::{
|
||||
ReportingContext, ReportingProductId, ReportingProductKind, ReportingStep,
|
||||
ReportingStepDynamicBuilder, ReportingStepId, ReportingStepLookupFn,
|
||||
ReportingStepDynamicBuilder, ReportingStepFromArgsFn, ReportingStepId,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -80,7 +80,7 @@ pub enum ReportingCalculationError {
|
||||
|
||||
pub enum HasStepOrCanBuild<'a, 'b> {
|
||||
HasStep(&'a Box<dyn ReportingStep>),
|
||||
CanLookup(ReportingStepLookupFn),
|
||||
CanLookup(ReportingStepFromArgsFn),
|
||||
CanBuild(&'b ReportingStepDynamicBuilder),
|
||||
None,
|
||||
}
|
||||
@ -105,7 +105,10 @@ pub fn has_step_or_can_build<'a, 'b>(
|
||||
.keys()
|
||||
.find(|(name, kinds)| *name == product.name && kinds.contains(&product.kind))
|
||||
{
|
||||
return HasStepOrCanBuild::CanLookup(*context.step_lookup_fn.get(lookup_key).unwrap());
|
||||
let (takes_args_fn, from_args_fn) = context.step_lookup_fn.get(lookup_key).unwrap();
|
||||
if takes_args_fn(&product.args) {
|
||||
return HasStepOrCanBuild::CanLookup(*from_args_fn);
|
||||
}
|
||||
}
|
||||
|
||||
// No explicit step for product - try builders
|
||||
@ -173,6 +176,9 @@ pub fn solve_for(
|
||||
for target in targets {
|
||||
steps.push(target);
|
||||
let target = steps.last().unwrap();
|
||||
for dependency in target.requires() {
|
||||
dependencies.add_dependency(target.id(), dependency);
|
||||
}
|
||||
target.as_ref().init_graph(&steps, &mut dependencies);
|
||||
}
|
||||
|
||||
@ -200,7 +206,7 @@ pub fn solve_for(
|
||||
*name == dependency.dependency.name
|
||||
&& kinds.contains(&dependency.dependency.kind)
|
||||
}) {
|
||||
let lookup_fn = context.step_lookup_fn.get(lookup_key).unwrap();
|
||||
let (_, lookup_fn) = context.step_lookup_fn.get(lookup_key).unwrap();
|
||||
let new_step = lookup_fn(dependency.dependency.args.clone());
|
||||
|
||||
// Check new step meets the dependency
|
||||
@ -255,6 +261,9 @@ pub fn solve_for(
|
||||
new_step_indexes.push(steps.len());
|
||||
steps.push(new_step);
|
||||
let new_step = steps.last().unwrap();
|
||||
for dependency in new_step.requires() {
|
||||
dependencies.add_dependency(new_step.id(), dependency);
|
||||
}
|
||||
new_step.as_ref().init_graph(&steps, &mut dependencies);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,10 @@ pub mod steps;
|
||||
|
||||
pub struct ReportingContext {
|
||||
_eofy_date: NaiveDate,
|
||||
step_lookup_fn: HashMap<(&'static str, &'static [ReportingProductKind]), ReportingStepLookupFn>,
|
||||
step_lookup_fn: HashMap<
|
||||
(&'static str, &'static [ReportingProductKind]),
|
||||
(ReportingStepTakesArgsFn, ReportingStepFromArgsFn),
|
||||
>,
|
||||
step_dynamic_builders: Vec<ReportingStepDynamicBuilder>,
|
||||
}
|
||||
|
||||
@ -48,9 +51,11 @@ impl ReportingContext {
|
||||
&mut self,
|
||||
name: &'static str,
|
||||
product_kinds: &'static [ReportingProductKind],
|
||||
builder: ReportingStepLookupFn,
|
||||
takes_args_fn: ReportingStepTakesArgsFn,
|
||||
from_args_fn: ReportingStepFromArgsFn,
|
||||
) {
|
||||
self.step_lookup_fn.insert((name, product_kinds), builder);
|
||||
self.step_lookup_fn
|
||||
.insert((name, product_kinds), (takes_args_fn, from_args_fn));
|
||||
}
|
||||
|
||||
fn register_dynamic_builder(&mut self, builder: ReportingStepDynamicBuilder) {
|
||||
@ -121,18 +126,24 @@ pub trait ReportingStep: Debug + Downcast {
|
||||
fn id(&self) -> ReportingStepId;
|
||||
|
||||
// Methods
|
||||
fn requires(&self) -> Vec<ReportingProductId> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn init_graph(
|
||||
&self,
|
||||
_steps: &Vec<Box<dyn ReportingStep>>,
|
||||
_dependencies: &mut ReportingGraphDependencies,
|
||||
) {
|
||||
}
|
||||
|
||||
fn after_init_graph(
|
||||
&self,
|
||||
_steps: &Vec<Box<dyn ReportingStep>>,
|
||||
_dependencies: &mut ReportingGraphDependencies,
|
||||
) {
|
||||
}
|
||||
|
||||
//fn execute(&self, _context: &ReportingContext, _products: &mut ReportingProducts) {
|
||||
// todo!();
|
||||
//}
|
||||
@ -146,7 +157,8 @@ downcast_rs::impl_downcast!(ReportingStepArgs);
|
||||
dyn_clone::clone_trait_object!(ReportingStepArgs);
|
||||
dyn_eq::eq_trait_object!(ReportingStepArgs);
|
||||
|
||||
pub type ReportingStepLookupFn = fn(args: Box<dyn ReportingStepArgs>) -> Box<dyn ReportingStep>;
|
||||
pub type ReportingStepTakesArgsFn = fn(args: &Box<dyn ReportingStepArgs>) -> bool;
|
||||
pub type ReportingStepFromArgsFn = fn(args: Box<dyn ReportingStepArgs>) -> Box<dyn ReportingStep>;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct DateArgs {
|
||||
|
@ -28,26 +28,37 @@ pub fn register_lookup_fns(context: &mut ReportingContext) {
|
||||
context.register_lookup_fn(
|
||||
"AllTransactionsExceptRetainedEarnings",
|
||||
&[ReportingProductKind::BalancesBetween],
|
||||
AllTransactionsExceptRetainedEarnings::takes_args,
|
||||
AllTransactionsExceptRetainedEarnings::from_args,
|
||||
);
|
||||
|
||||
context.register_lookup_fn(
|
||||
"CalculateIncomeTax",
|
||||
&[ReportingProductKind::Transactions],
|
||||
CalculateIncomeTax::takes_args,
|
||||
CalculateIncomeTax::from_args,
|
||||
);
|
||||
|
||||
context.register_lookup_fn(
|
||||
"CombineOrdinaryTransactions",
|
||||
&[ReportingProductKind::BalancesAt],
|
||||
CombineOrdinaryTransactions::takes_args,
|
||||
CombineOrdinaryTransactions::from_args,
|
||||
);
|
||||
|
||||
context.register_lookup_fn(
|
||||
"DBBalances",
|
||||
&[ReportingProductKind::BalancesAt],
|
||||
DBBalances::takes_args,
|
||||
DBBalances::from_args,
|
||||
);
|
||||
|
||||
context.register_lookup_fn(
|
||||
"PostUnreconciledStatementLines",
|
||||
&[ReportingProductKind::Transactions],
|
||||
PostUnreconciledStatementLines::takes_args,
|
||||
PostUnreconciledStatementLines::from_args,
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -56,6 +67,10 @@ pub struct AllTransactionsExceptRetainedEarnings {
|
||||
}
|
||||
|
||||
impl AllTransactionsExceptRetainedEarnings {
|
||||
fn takes_args(args: &Box<dyn ReportingStepArgs>) -> bool {
|
||||
args.is::<DateStartDateEndArgs>()
|
||||
}
|
||||
|
||||
fn from_args(args: Box<dyn ReportingStepArgs>) -> Box<dyn ReportingStep> {
|
||||
Box::new(AllTransactionsExceptRetainedEarnings {
|
||||
args: *args.downcast().unwrap(),
|
||||
@ -79,6 +94,10 @@ pub struct CalculateIncomeTax {
|
||||
}
|
||||
|
||||
impl CalculateIncomeTax {
|
||||
fn takes_args(args: &Box<dyn ReportingStepArgs>) -> bool {
|
||||
args.is::<DateEofyArgs>()
|
||||
}
|
||||
|
||||
fn from_args(args: Box<dyn ReportingStepArgs>) -> Box<dyn ReportingStep> {
|
||||
Box::new(CalculateIncomeTax {
|
||||
args: *args.downcast().unwrap(),
|
||||
@ -95,23 +114,16 @@ impl ReportingStep for CalculateIncomeTax {
|
||||
}
|
||||
}
|
||||
|
||||
fn init_graph(
|
||||
&self,
|
||||
_steps: &Vec<Box<dyn ReportingStep>>,
|
||||
dependencies: &mut ReportingGraphDependencies,
|
||||
) {
|
||||
fn requires(&self) -> Vec<ReportingProductId> {
|
||||
// CalculateIncomeTax depends on CombineOrdinaryTransactions
|
||||
dependencies.add_dependency(
|
||||
self.id(),
|
||||
ReportingProductId {
|
||||
name: "CombineOrdinaryTransactions",
|
||||
kind: ReportingProductKind::BalancesBetween,
|
||||
args: Box::new(DateStartDateEndArgs {
|
||||
date_start: sofy_from_eofy(self.args.date_eofy),
|
||||
date_end: self.args.date_eofy.clone(),
|
||||
}),
|
||||
},
|
||||
);
|
||||
vec![ReportingProductId {
|
||||
name: "CombineOrdinaryTransactions",
|
||||
kind: ReportingProductKind::BalancesBetween,
|
||||
args: Box::new(DateStartDateEndArgs {
|
||||
date_start: sofy_from_eofy(self.args.date_eofy),
|
||||
date_end: self.args.date_eofy.clone(),
|
||||
}),
|
||||
}]
|
||||
}
|
||||
|
||||
fn after_init_graph(
|
||||
@ -138,6 +150,10 @@ pub struct CombineOrdinaryTransactions {
|
||||
}
|
||||
|
||||
impl CombineOrdinaryTransactions {
|
||||
fn takes_args(args: &Box<dyn ReportingStepArgs>) -> bool {
|
||||
args.is::<DateArgs>()
|
||||
}
|
||||
|
||||
fn from_args(args: Box<dyn ReportingStepArgs>) -> Box<dyn ReportingStep> {
|
||||
Box::new(CombineOrdinaryTransactions {
|
||||
args: *args.downcast().unwrap(),
|
||||
@ -154,20 +170,21 @@ impl ReportingStep for CombineOrdinaryTransactions {
|
||||
}
|
||||
}
|
||||
|
||||
fn init_graph(
|
||||
&self,
|
||||
_steps: &Vec<Box<dyn ReportingStep>>,
|
||||
dependencies: &mut ReportingGraphDependencies,
|
||||
) {
|
||||
// CombineOrdinaryTransactions depends on DBBalances
|
||||
dependencies.add_dependency(
|
||||
self.id(),
|
||||
fn requires(&self) -> Vec<ReportingProductId> {
|
||||
vec![
|
||||
// CombineOrdinaryTransactions depends on DBBalances
|
||||
ReportingProductId {
|
||||
name: "DBBalances",
|
||||
kind: ReportingProductKind::BalancesAt,
|
||||
args: Box::new(self.args.clone()),
|
||||
},
|
||||
);
|
||||
// CombineOrdinaryTransactions depends on PostUnreconciledStatementLines
|
||||
ReportingProductId {
|
||||
name: "PostUnreconciledStatementLines",
|
||||
kind: ReportingProductKind::BalancesAt,
|
||||
args: Box::new(self.args.clone()),
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,6 +194,10 @@ pub struct DBBalances {
|
||||
}
|
||||
|
||||
impl DBBalances {
|
||||
fn takes_args(args: &Box<dyn ReportingStepArgs>) -> bool {
|
||||
args.is::<DateArgs>()
|
||||
}
|
||||
|
||||
fn from_args(args: Box<dyn ReportingStepArgs>) -> Box<dyn ReportingStep> {
|
||||
Box::new(DBBalances {
|
||||
args: *args.downcast().unwrap(),
|
||||
@ -193,3 +214,30 @@ impl ReportingStep for DBBalances {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PostUnreconciledStatementLines {
|
||||
pub args: DateArgs,
|
||||
}
|
||||
|
||||
impl PostUnreconciledStatementLines {
|
||||
fn takes_args(args: &Box<dyn ReportingStepArgs>) -> bool {
|
||||
args.is::<DateArgs>()
|
||||
}
|
||||
|
||||
fn from_args(args: Box<dyn ReportingStepArgs>) -> Box<dyn ReportingStep> {
|
||||
Box::new(PostUnreconciledStatementLines {
|
||||
args: *args.downcast().unwrap(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ReportingStep for PostUnreconciledStatementLines {
|
||||
fn id(&self) -> ReportingStepId {
|
||||
ReportingStepId {
|
||||
name: "PostUnreconciledStatementLines",
|
||||
product_kinds: &[ReportingProductKind::Transactions],
|
||||
args: Box::new(self.args.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user