rustledger_plugin/native/plugins/
close_tree.rs1use crate::types::{
4 CloseData, DirectiveData, DirectiveWrapper, PluginInput, PluginOutput, sort_directives,
5};
6
7use super::super::NativePlugin;
8
9pub struct CloseTreePlugin;
14
15impl NativePlugin for CloseTreePlugin {
16 fn name(&self) -> &'static str {
17 "close_tree"
18 }
19
20 fn description(&self) -> &'static str {
21 "Close descendant accounts automatically"
22 }
23
24 fn process(&self, input: PluginInput) -> PluginOutput {
25 use std::collections::HashSet;
26
27 let mut all_accounts: HashSet<String> = HashSet::new();
29 for wrapper in &input.directives {
30 if let DirectiveData::Open(data) = &wrapper.data {
31 all_accounts.insert(data.account.clone());
32 }
33 if let DirectiveData::Transaction(txn) = &wrapper.data {
34 for posting in &txn.postings {
35 all_accounts.insert(posting.account.clone());
36 }
37 }
38 }
39
40 let mut closed_parents: Vec<(String, String)> = Vec::new(); for wrapper in &input.directives {
43 if let DirectiveData::Close(data) = &wrapper.data {
44 closed_parents.push((data.account.clone(), wrapper.date.clone()));
45 }
46 }
47
48 let mut new_directives = input.directives;
50
51 for (parent, close_date) in &closed_parents {
52 let prefix = format!("{parent}:");
53 for account in &all_accounts {
54 if account.starts_with(&prefix) {
55 let already_closed = new_directives.iter().any(|w| {
57 if let DirectiveData::Close(data) = &w.data {
58 &data.account == account
59 } else {
60 false
61 }
62 });
63
64 if !already_closed {
65 new_directives.push(DirectiveWrapper {
66 directive_type: "close".to_string(),
67 date: close_date.clone(),
68 filename: None, lineno: None,
70 data: DirectiveData::Close(CloseData {
71 account: account.clone(),
72 metadata: vec![],
73 }),
74 });
75 }
76 }
77 }
78 }
79
80 sort_directives(&mut new_directives);
82
83 PluginOutput {
84 directives: new_directives,
85 errors: Vec::new(),
86 }
87 }
88}