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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
//! The UBL 2.1 binding, both directions.
//!
//! UBL has **two document elements** where CII has one: `Invoice` and
//! `CreditNote`, in different namespaces, with different names for the type
//! code and the line. [`en16931::DocumentKind`] is what selects between them,
//! and it exists in the model precisely because CEN's own credit-note fixtures
//! carry no BT-3 to infer it from.
//!
//! ```
//! use en16931::Invoice;
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let xml = en16931_formats::ubl::to_string(&Invoice::default());
//! assert!(xml.starts_with("<?xml"));
//!
//! let back = en16931_formats::ubl::from_str(&xml)?;
//! assert_eq!(back.invoice.kind, Invoice::default().kind);
//! # Ok(()) }
//! ```
use Invoice;
pub use Reader;
pub use ;
/// Write a **validated** invoice, stamping BT-24 from the profile it proved.
///
/// This is the path worth using, and the reason `en16931` has a typed proof at
/// all. Two things become impossible rather than merely discouraged:
///
/// * An unvalidated invoice cannot be serialised — there is no way to construct
/// the argument without having run the rules.
/// * BT-24 cannot disagree with the rules that were actually applied. A
/// document claiming `XRechnung` 3.0 because someone typed the string, having
/// been checked against the bare core model, is the single most common way an
/// invoice passes local validation and is rejected on receipt.
///
/// ```
/// use en16931::profiles::XRechnung;
/// use en16931::validation::profile::Validated;
///
/// # fn demo(inv: en16931::Invoice) {
/// let Ok(proof) = Validated::<XRechnung>::new(inv) else { return };
/// let out = en16931_formats::ubl::write_validated(&proof);
/// assert!(out.xml.contains("xrechnung_3.0"));
/// # }
/// ```
/// Write an invoice as UBL, discarding the report of anything the syntax could
/// not carry.
///
/// A convenience for the common case where the model is known to fit — which is
/// every ordinary invoice. Use [`fn@write`] when it might not: BT-11 on a credit
/// note has nowhere to go, and finding that out from the counterparty is worse
/// than finding it out here.
///
/// # Why this returns `String` and not `Result<String, _>`
///
/// **Serialisation cannot fail, and that is a property of the model rather than
/// an omission.** Every field of [`Invoice`] already holds a value UBL can
/// carry: [`en16931::InvoiceAmount`] cannot hold a third decimal,
/// [`en16931::Date`] cannot hold something that is not a calendar day, a code is
/// a string. There is no state a writer could be handed that it would have to
/// refuse. Writing into a `String` does no I/O, so there is nothing else to go
/// wrong either.
///
/// **Validity is a separate question, and it is the caller's.** An invoice with
/// no seller serialises perfectly into a document no counterparty will accept.
/// Run [`en16931::validate`] first — or use [`to_string_for`], which will not
/// hand you a document until you have.
/// Write an invoice as UBL **for a profile**, or refuse and say why.
///
/// The call that turns "we forgot to validate before submitting" from a
/// rejection letter into an `Err` on the line that would have shipped it. It
/// validates against `profile`, stamps BT-24 from it, and only then writes.
///
/// ```
/// use en16931::profiles::XRECHNUNG;
///
/// # fn demo(invoice: &en16931::Invoice) {
/// match en16931_formats::ubl::to_string_for(invoice, &XRECHNUNG) {
/// Ok(xml) => submit(&xml),
/// // Neither a panic nor a silent fallback: the report says exactly which
/// // BR-DE rules the document still owes.
/// Err(e) => eprintln!("{e}\n{}", e.report()),
/// }
/// # }
/// # fn submit(_: &str) {}
/// ```
///
/// # This and [`write_validated`] are the same guarantee, twice
///
/// [`write_validated`] takes a [`Validated<P>`] and is *unconditional* — the
/// proof was produced elsewhere and the type carries it. Reach for that when
/// the proof travels: across a function boundary, into a queue, through a trait.
///
/// This one validates on the spot and returns a `Result`. Reach for it when the
/// profile is a runtime choice, which it is whenever a counterparty's preferred
/// CIUS comes out of a database rather than out of the source.
///
/// Neither can produce a document whose BT-24 disagrees with the rules that
/// were actually run.
///
/// # Errors
/// [`NotValid`](crate::NotValid), carrying the full report, when any fatal
/// finding was raised.
///
/// [`Validated<P>`]: en16931::validation::profile::Validated
/// [`write_validated`]: fn@write_validated
/// As [`to_string_for`], keeping the report of anything the syntax could not
/// carry.
///
/// # Errors
/// [`NotValid`](crate::NotValid), carrying the full report, when any fatal
/// finding was raised.
/// The UBL namespaces, for a caller that needs to recognise a document before
/// handing it over.
/// What reading a UBL document produced.
///
/// The unmapped and malformed lists are not diagnostics to be ignored: a reader
/// that returns an `Invoice` and says nothing about the six elements it skipped
/// is how a validation run comes back green having checked nothing.
/// Anything that stopped a document being read at all.
/// Read a UBL `Invoice` or `CreditNote`.
///
/// # Errors
///
/// [`Error::Xml`] if the input is not well-formed, [`Error::NotUbl`] if the
/// document element is something else.