1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct PluginInput {
11 pub directives: Vec<DirectiveWrapper>,
13 pub options: PluginOptions,
15 pub config: Option<String>,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct PluginOutput {
22 pub directives: Vec<DirectiveWrapper>,
24 pub errors: Vec<PluginError>,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct DirectiveWrapper {
34 #[serde(skip_serializing, default)]
36 pub directive_type: String,
37 pub date: String,
39 #[serde(skip_serializing_if = "Option::is_none", default)]
42 pub filename: Option<String>,
43 #[serde(skip_serializing_if = "Option::is_none", default)]
46 pub lineno: Option<u32>,
47 #[serde(flatten)]
49 pub data: DirectiveData,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54#[serde(tag = "type")]
55pub enum DirectiveData {
56 #[serde(rename = "transaction")]
58 Transaction(TransactionData),
59 #[serde(rename = "balance")]
61 Balance(BalanceData),
62 #[serde(rename = "open")]
64 Open(OpenData),
65 #[serde(rename = "close")]
67 Close(CloseData),
68 #[serde(rename = "commodity")]
70 Commodity(CommodityData),
71 #[serde(rename = "pad")]
73 Pad(PadData),
74 #[serde(rename = "event")]
76 Event(EventData),
77 #[serde(rename = "note")]
79 Note(NoteData),
80 #[serde(rename = "document")]
82 Document(DocumentData),
83 #[serde(rename = "price")]
85 Price(PriceData),
86 #[serde(rename = "query")]
88 Query(QueryData),
89 #[serde(rename = "custom")]
91 Custom(CustomData),
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct TransactionData {
97 pub flag: String,
99 pub payee: Option<String>,
101 pub narration: String,
103 pub tags: Vec<String>,
105 pub links: Vec<String>,
107 pub metadata: Vec<(String, MetaValueData)>,
109 pub postings: Vec<PostingData>,
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize)]
115pub struct PostingData {
116 pub account: String,
118 pub units: Option<AmountData>,
120 pub cost: Option<CostData>,
122 pub price: Option<PriceAnnotationData>,
124 pub flag: Option<String>,
126 pub metadata: Vec<(String, MetaValueData)>,
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct AmountData {
133 pub number: String,
135 pub currency: String,
137}
138
139#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct CostData {
142 pub number_per: Option<String>,
144 pub number_total: Option<String>,
146 pub currency: Option<String>,
148 pub date: Option<String>,
150 pub label: Option<String>,
152 pub merge: bool,
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize)]
158pub struct PriceAnnotationData {
159 pub is_total: bool,
161 pub amount: Option<AmountData>,
163 pub number: Option<String>,
165 pub currency: Option<String>,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
171#[serde(tag = "type", content = "value")]
172pub enum MetaValueData {
173 #[serde(rename = "string")]
175 String(String),
176 #[serde(rename = "number")]
178 Number(String),
179 #[serde(rename = "date")]
181 Date(String),
182 #[serde(rename = "account")]
184 Account(String),
185 #[serde(rename = "currency")]
187 Currency(String),
188 #[serde(rename = "tag")]
190 Tag(String),
191 #[serde(rename = "link")]
193 Link(String),
194 #[serde(rename = "amount")]
196 Amount(AmountData),
197 #[serde(rename = "bool")]
199 Bool(bool),
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
204pub struct BalanceData {
205 pub account: String,
207 pub amount: AmountData,
209 pub tolerance: Option<String>,
211 #[serde(default)]
213 pub metadata: Vec<(String, MetaValueData)>,
214}
215
216#[derive(Debug, Clone, Serialize, Deserialize)]
218pub struct OpenData {
219 pub account: String,
221 pub currencies: Vec<String>,
223 pub booking: Option<String>,
225 #[serde(default)]
227 pub metadata: Vec<(String, MetaValueData)>,
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
232pub struct CloseData {
233 pub account: String,
235 #[serde(default)]
237 pub metadata: Vec<(String, MetaValueData)>,
238}
239
240#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct CommodityData {
243 pub currency: String,
245 #[serde(default)]
247 pub metadata: Vec<(String, MetaValueData)>,
248}
249
250#[derive(Debug, Clone, Serialize, Deserialize)]
252pub struct PadData {
253 pub account: String,
255 pub source_account: String,
257 #[serde(default)]
259 pub metadata: Vec<(String, MetaValueData)>,
260}
261
262#[derive(Debug, Clone, Serialize, Deserialize)]
264pub struct EventData {
265 pub event_type: String,
267 pub value: String,
269 #[serde(default)]
271 pub metadata: Vec<(String, MetaValueData)>,
272}
273
274#[derive(Debug, Clone, Serialize, Deserialize)]
276pub struct NoteData {
277 pub account: String,
279 pub comment: String,
281 #[serde(default)]
283 pub metadata: Vec<(String, MetaValueData)>,
284}
285
286#[derive(Debug, Clone, Serialize, Deserialize)]
288pub struct DocumentData {
289 pub account: String,
291 pub path: String,
293 #[serde(default)]
295 pub metadata: Vec<(String, MetaValueData)>,
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize)]
300pub struct PriceData {
301 pub currency: String,
303 pub amount: AmountData,
305 #[serde(default)]
307 pub metadata: Vec<(String, MetaValueData)>,
308}
309
310#[derive(Debug, Clone, Serialize, Deserialize)]
312pub struct QueryData {
313 pub name: String,
315 pub query: String,
317 #[serde(default)]
319 pub metadata: Vec<(String, MetaValueData)>,
320}
321
322#[derive(Debug, Clone, Serialize, Deserialize)]
324pub struct CustomData {
325 pub custom_type: String,
327 pub values: Vec<MetaValueData>,
329 #[serde(default)]
331 pub metadata: Vec<(String, MetaValueData)>,
332}
333
334#[derive(Debug, Clone, Default, Serialize, Deserialize)]
336pub struct PluginOptions {
337 pub operating_currencies: Vec<String>,
339 pub title: Option<String>,
341}
342
343#[derive(Debug, Clone, Serialize, Deserialize)]
345pub struct PluginError {
346 pub message: String,
348 pub source_file: Option<String>,
350 pub line_number: Option<u32>,
352 pub severity: PluginErrorSeverity,
354}
355
356#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
358pub enum PluginErrorSeverity {
359 #[serde(rename = "warning")]
361 Warning,
362 #[serde(rename = "error")]
364 Error,
365}
366
367impl PluginError {
368 pub fn error(message: impl Into<String>) -> Self {
370 Self {
371 message: message.into(),
372 source_file: None,
373 line_number: None,
374 severity: PluginErrorSeverity::Error,
375 }
376 }
377
378 pub fn warning(message: impl Into<String>) -> Self {
380 Self {
381 message: message.into(),
382 source_file: None,
383 line_number: None,
384 severity: PluginErrorSeverity::Warning,
385 }
386 }
387
388 pub fn at(mut self, file: impl Into<String>, line: u32) -> Self {
390 self.source_file = Some(file.into());
391 self.line_number = Some(line);
392 self
393 }
394}
395
396impl PluginOutput {
397 pub const fn passthrough(directives: Vec<DirectiveWrapper>) -> Self {
399 Self {
400 directives,
401 errors: Vec::new(),
402 }
403 }
404}
405
406impl DirectiveWrapper {
407 pub const fn type_sort_order(&self) -> i8 {
416 match &self.data {
417 DirectiveData::Open(_) => -2,
418 DirectiveData::Balance(_) => -1,
419 DirectiveData::Document(_) => 1,
420 DirectiveData::Close(_) => 2,
421 _ => 0, }
423 }
424
425 pub fn sort_key(&self) -> (&str, i8, u32) {
430 (
431 &self.date,
432 self.type_sort_order(),
433 self.lineno.unwrap_or(u32::MAX), )
435 }
436}
437
438pub fn sort_directives(directives: &mut [DirectiveWrapper]) {
445 directives.sort_by(|a, b| a.sort_key().cmp(&b.sort_key()));
446}