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
//! The UN/CEFACT Cross Industry Invoice **D16B** binding, both directions.
//!
//! CII has **one** document element where UBL has two — `rsm:CrossIndustryInvoice`
//! carries invoices and credit notes alike, distinguished only by BT-3. So the
//! writer never branches on [`en16931::DocumentKind`], and the reader infers it
//! from the type code.
//!
//! # Three things CII does differently
//!
//! **Dates are wrapped and formatted.** Where UBL writes
//! `<cbc:IssueDate>2026-01-15</cbc:IssueDate>`, CII writes
//! `<ram:IssueDateTime><udt:DateTimeString format="102">20260115</udt:DateTimeString></ram:IssueDateTime>`.
//! Format `102` is `CCYYMMDD`; it is the only format EN 16931 permits, and
//! [`read`] rejects anything else rather than guessing.
//!
//! **Allowances and charges share an element.** `ram:SpecifiedTradeAllowanceCharge`
//! carries both, told apart by `ram:ChargeIndicator/udt:Indicator`. UBL does the
//! same with `cbc:ChargeIndicator`, so the model's split into `allowances` and
//! `charges` costs one boolean in each binding.
//!
//! **Party identifiers split by whether they have a scheme.** A scheme-qualified
//! BT-29 is `ram:GlobalID`; an unqualified one is `ram:ID`. Two elements for one
//! repeatable business term, and the sequence fixes their order — so a party
//! carrying both kinds gets them back in a **different order** than they went
//! in. That is not lossy: EN 16931 gives the order of repeated BT-29 occurrences
//! no meaning, and the set is preserved exactly. It is stated here because a
//! round-trip test that compared them positionally would fail for a reason that
//! looks like a bug and is not.
//!
//! **The document is three-part.** `ExchangedDocumentContext` (BT-23, BT-24),
//! `ExchangedDocument` (BT-1, BT-2, BT-3, notes), and
//! `SupplyChainTradeTransaction` (everything else, split across *agreement*,
//! *delivery* and *settlement*). Which of those three a term lives in is not
//! guessable, which is why the element order here was derived from 170
//! published instances rather than recalled — see [`order`].
//!
//! ```
//! use en16931::Invoice;
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let xml = en16931_formats::cii::to_string(&Invoice::default());
//! assert!(xml.contains("CrossIndustryInvoice"));
//!
//! let back = en16931_formats::cii::from_str(&xml)?;
//! assert!(back.unmapped.is_empty());
//! # Ok(()) }
//! ```
use Invoice;
pub use Reader;
pub use ;
/// The CII namespaces. Fixed by UN/CEFACT; not configurable.
/// Write an invoice as CII, discarding the report of anything the syntax could
/// not carry.
///
/// Use [`fn@write`] when that might matter.
///
/// # 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 CII can
/// carry: [`en16931::InvoiceAmount`] cannot hold a third decimal, and
/// [`en16931::Date`] cannot hold something that is not a calendar day — which
/// is exactly what `udt:DateTimeString format="102"` accepts, and nothing more.
/// There is no state a writer could be handed that it would have to refuse, and
/// writing into a `String` does no I/O.
///
/// **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 CII **for a profile**, or refuse and say why.
///
/// The CII twin of [`crate::ubl::to_string_for`], and the one that matters for
/// ZUGFeRD: every ZUGFeRD payload is CII, and a hybrid PDF carrying an invalid
/// one is a document that looks right to a human and is rejected by a machine.
///
/// ```
/// use en16931::profiles::XRECHNUNG;
///
/// # fn demo(invoice: &en16931::Invoice) {
/// match en16931_formats::cii::to_string_for(invoice, &XRECHNUNG) {
/// Ok(xml) => embed_in_pdf(&xml),
/// Err(e) => eprintln!("{e}\n{}", e.report()),
/// }
/// # }
/// # fn embed_in_pdf(_: &str) {}
/// ```
///
/// # Errors
/// [`NotValid`](crate::NotValid), carrying the full report, when any fatal
/// finding was raised.
/// 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.
/// Write a **validated** invoice, stamping BT-24 from the profile it proved.
///
/// The same guarantee [`crate::ubl::write_validated`] gives, in the other
/// syntax: an unvalidated invoice cannot be serialised, and BT-24 cannot
/// disagree with the rules that were actually applied.
/// What reading a CII document produced.
/// Anything that stopped a document being read at all.
/// Read a CII `rsm:CrossIndustryInvoice`.
///
/// # Errors
///
/// [`Error::Xml`] if the input is not well-formed, [`Error::NotCii`] if the
/// document element is something else.