rustledger_plugin/native/plugins/
auto_accounts.rs1use crate::types::{
4 DirectiveData, DirectiveWrapper, OpenData, PluginInput, PluginOutput, sort_directives,
5};
6
7use super::super::NativePlugin;
8
9pub struct AutoAccountsPlugin;
11
12impl NativePlugin for AutoAccountsPlugin {
13 fn name(&self) -> &'static str {
14 "auto_accounts"
15 }
16
17 fn description(&self) -> &'static str {
18 "Auto-generate Open directives for used accounts"
19 }
20
21 fn process(&self, input: PluginInput) -> PluginOutput {
22 use std::collections::{HashMap, HashSet};
23
24 let mut opened_accounts: HashSet<String> = HashSet::new();
25 let mut account_first_use: HashMap<String, String> = HashMap::new(); for wrapper in &input.directives {
30 match &wrapper.data {
31 DirectiveData::Open(data) => {
32 opened_accounts.insert(data.account.clone());
33 }
34 DirectiveData::Transaction(txn) => {
35 for posting in &txn.postings {
36 account_first_use
37 .entry(posting.account.clone())
38 .and_modify(|existing| {
39 if wrapper.date < *existing {
40 existing.clone_from(&wrapper.date);
41 }
42 })
43 .or_insert_with(|| wrapper.date.clone());
44 }
45 }
46 DirectiveData::Balance(data) => {
47 account_first_use
48 .entry(data.account.clone())
49 .and_modify(|existing| {
50 if wrapper.date < *existing {
51 existing.clone_from(&wrapper.date);
52 }
53 })
54 .or_insert_with(|| wrapper.date.clone());
55 }
56 DirectiveData::Pad(data) => {
57 account_first_use
58 .entry(data.account.clone())
59 .and_modify(|existing| {
60 if wrapper.date < *existing {
61 existing.clone_from(&wrapper.date);
62 }
63 })
64 .or_insert_with(|| wrapper.date.clone());
65 account_first_use
66 .entry(data.source_account.clone())
67 .and_modify(|existing| {
68 if wrapper.date < *existing {
69 existing.clone_from(&wrapper.date);
70 }
71 })
72 .or_insert_with(|| wrapper.date.clone());
73 }
74 _ => {}
75 }
76 }
77
78 let mut accounts_to_open: Vec<_> = account_first_use
81 .iter()
82 .filter(|(account, _)| !opened_accounts.contains(*account))
83 .collect();
84 accounts_to_open.sort_by_key(|(account, _)| *account);
85
86 let mut new_directives: Vec<DirectiveWrapper> = Vec::new();
87 for (index, (account, date)) in accounts_to_open.into_iter().enumerate() {
88 new_directives.push(DirectiveWrapper {
89 directive_type: "open".to_string(),
90 date: date.clone(),
91 filename: Some("<auto_accounts>".to_string()),
92 lineno: Some(index as u32), data: DirectiveData::Open(OpenData {
94 account: account.clone(),
95 currencies: vec![],
96 booking: None,
97 metadata: vec![],
98 }),
99 });
100 }
101
102 new_directives.extend(input.directives);
104
105 sort_directives(&mut new_directives);
107
108 PluginOutput {
109 directives: new_directives,
110 errors: Vec::new(),
111 }
112 }
113}