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