Skip to main content

rustledger_plugin/native/plugins/
implicit_prices.rs

1//! Plugin that generates price entries from transaction costs and prices.
2
3use crate::types::{DirectiveWrapper, PluginInput, PluginOutput};
4
5use super::super::NativePlugin;
6
7/// Plugin that generates price entries from transaction costs and prices.
8///
9/// When a transaction has a posting with a cost or price annotation,
10/// this plugin generates a corresponding Price directive.
11pub struct ImplicitPricesPlugin;
12
13impl NativePlugin for ImplicitPricesPlugin {
14    fn name(&self) -> &'static str {
15        "implicit_prices"
16    }
17
18    fn description(&self) -> &'static str {
19        "Generate price entries from transaction costs/prices"
20    }
21
22    fn process(&self, input: PluginInput) -> PluginOutput {
23        let mut new_directives = Vec::new();
24        let mut generated_prices = Vec::new();
25
26        for wrapper in &input.directives {
27            new_directives.push(wrapper.clone());
28
29            // Only process transactions
30            if wrapper.directive_type != "transaction" {
31                continue;
32            }
33
34            // Extract prices from transaction data
35            if let crate::types::DirectiveData::Transaction(ref txn) = wrapper.data {
36                for posting in &txn.postings {
37                    // Check for price annotation
38                    if let Some(ref units) = posting.units {
39                        if let Some(ref price) = posting.price {
40                            // Generate a price directive only if we have a complete amount
41                            if let Some(ref price_amount) = price.amount {
42                                let price_wrapper = DirectiveWrapper {
43                                    directive_type: "price".to_string(),
44                                    date: wrapper.date.clone(),
45                                    filename: None, // Plugin-generated
46                                    lineno: None,
47                                    data: crate::types::DirectiveData::Price(
48                                        crate::types::PriceData {
49                                            currency: units.currency.clone(),
50                                            amount: price_amount.clone(),
51                                            metadata: vec![],
52                                        },
53                                    ),
54                                };
55                                generated_prices.push(price_wrapper);
56                            }
57                        }
58
59                        // Check for cost with price info
60                        if let Some(ref cost) = posting.cost
61                            && let (Some(number), Some(currency)) =
62                                (&cost.number_per, &cost.currency)
63                        {
64                            let price_wrapper = DirectiveWrapper {
65                                directive_type: "price".to_string(),
66                                date: wrapper.date.clone(),
67                                filename: None, // Plugin-generated
68                                lineno: None,
69                                data: crate::types::DirectiveData::Price(crate::types::PriceData {
70                                    currency: units.currency.clone(),
71                                    amount: crate::types::AmountData {
72                                        number: number.clone(),
73                                        currency: currency.clone(),
74                                    },
75                                    metadata: vec![],
76                                }),
77                            };
78                            generated_prices.push(price_wrapper);
79                        }
80                    }
81                }
82            }
83        }
84
85        // Add generated prices
86        new_directives.extend(generated_prices);
87
88        PluginOutput {
89            directives: new_directives,
90            errors: Vec::new(),
91        }
92    }
93}