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}