1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use crate::prelude::*;
/// Input which has been validated and is ready for processing.
/// Controls which language to use, the month for which to generate the invoice,
/// the items to be invoiced, the layout of the invoice, and an optional output path
/// for the generated PDF file.
#[derive(Debug, Clone, Display, Builder, Getters)]
#[display("Layout: {}, Period: {}, out: {:?}, items: {}, language: {}", layout, period, maybe_output_path.as_ref().map(|d|d.display()), items, language)]
pub struct ValidInput {
/// The language to use for the invoice, used on labels, headers etc.
/// Defaults to English (`Language::EN`).
#[builder(default)]
#[getset(get = "pub")]
language: Language,
/// The period for which to generate the invoice, this affects the invoice
/// number as well as the invoice date and due date.
///
/// Note: We use the period type with the highest granularity, so that we
/// always can convert it to a kind of period of more coarse granularity.
/// For example, if the period is `YearMonthAndFortnight`, we can always
/// convert it to `YearAndMonth` later in the flow if that matches the invoice
/// cadence.
#[getset(get = "pub")]
period: YearMonthAndFortnight,
/// The items to be invoiced, either services or expenses.
#[builder(default)]
#[getset(get = "pub")]
items: InvoicedItems,
/// The layout of the invoice to use
#[builder(default)]
#[getset(get = "pub")]
layout: Layout,
/// An optional override of where to save the output PDF file.
#[getset(get = "pub")]
maybe_output_path: Option<PathBuf>,
/// If set, the invoice will be sent via email after generation.
///
/// If set to true but email is not configured, an error will be thrown later.
#[getset(get = "pub")]
email: Option<DecryptedEmailSettings>,
}
impl HasSample for ValidInput {
fn sample() -> Self {
Self::builder()
.period(YearMonthAndFortnight::sample())
.items(InvoicedItems::sample())
.maybe_output_path(PathBuf::from("invoice.pdf"))
.build()
}
fn sample_other() -> Self {
Self::builder()
.period(YearMonthAndFortnight::sample_other())
.items(InvoicedItems::sample_other())
.build()
}
}
#[cfg(test)]
mod tests {
use super::*;
use test_log::test;
type Sut = ValidInput;
#[test]
fn valid_input_sample() {
let sample = Sut::sample();
assert!(sample.maybe_output_path.is_some());
}
#[test]
fn valid_input_sample_other() {
let sample = Sut::sample_other();
assert!(sample.maybe_output_path.is_none());
}
}