1use crate::error::Result;
4use crate::message::invoice::{Invoice, LineItem, TaxCategory, TaxSubtotal, TaxTotal};
5use crate::message::tap_message_trait::TapMessageBody;
6use crate::message::types::Participant;
7use crate::message::PaymentRequest;
8use didcomm::Message;
9use std::collections::HashMap;
10
11pub fn create_basic_invoice_example() -> Result<Invoice> {
13 let line_items = vec![
15 LineItem {
16 id: "1".to_string(),
17 description: "Widget A".to_string(),
18 quantity: 5.0,
19 unit_code: Some("EA".to_string()),
20 unit_price: 10.0,
21 line_total: 50.0,
22 tax_category: None,
23 },
24 LineItem {
25 id: "2".to_string(),
26 description: "Widget B".to_string(),
27 quantity: 10.0,
28 unit_code: Some("EA".to_string()),
29 unit_price: 5.0,
30 line_total: 50.0,
31 tax_category: None,
32 },
33 ];
34
35 let total = line_items.iter().map(|item| item.line_total).sum();
37
38 let invoice = Invoice::new(
40 "INV001".to_string(),
41 "2023-09-01".to_string(),
42 "USD".to_string(),
43 line_items,
44 total,
45 );
46
47 invoice.validate()?;
49
50 Ok(invoice)
51}
52
53pub fn create_invoice_with_tax_example() -> Result<Invoice> {
55 let line_items = vec![
57 LineItem {
58 id: "1".to_string(),
59 description: "Widget A".to_string(),
60 quantity: 5.0,
61 unit_code: Some("EA".to_string()),
62 unit_price: 10.0,
63 line_total: 50.0,
64 tax_category: None,
65 },
66 LineItem {
67 id: "2".to_string(),
68 description: "Widget B".to_string(),
69 quantity: 10.0,
70 unit_code: Some("EA".to_string()),
71 unit_price: 5.0,
72 line_total: 50.0,
73 tax_category: None,
74 },
75 ];
76
77 let sub_total = line_items.iter().map(|item| item.line_total).sum();
79
80 let tax_category = TaxCategory {
82 id: "S".to_string(),
83 percent: 15.0,
84 tax_scheme: "VAT".to_string(),
85 };
86
87 let tax_amount = sub_total * (tax_category.percent / 100.0);
88 let total = sub_total + tax_amount;
89
90 let tax_subtotal = TaxSubtotal {
91 taxable_amount: sub_total,
92 tax_amount,
93 tax_category,
94 };
95
96 let tax_total = TaxTotal {
97 tax_amount,
98 tax_subtotal: Some(vec![tax_subtotal]),
99 };
100
101 let invoice = Invoice {
103 id: "INV001".to_string(),
104 issue_date: "2023-09-01".to_string(),
105 currency_code: "USD".to_string(),
106 line_items,
107 tax_total: Some(tax_total),
108 total,
109 sub_total: Some(sub_total),
110 due_date: Some("2023-10-01".to_string()),
111 note: None,
112 payment_terms: Some("NET30".to_string()),
113 accounting_cost: None,
114 order_reference: None,
115 additional_document_reference: None,
116 metadata: HashMap::new(),
117 };
118
119 invoice.validate()?;
121
122 Ok(invoice)
123}
124
125pub fn create_payment_request_with_invoice_example(
127 merchant_did: &str,
128 customer_did: Option<&str>,
129) -> Result<Message> {
130 let merchant = Participant {
132 id: merchant_did.to_string(),
133 role: Some("merchant".to_string()),
134 policies: None,
135 leiCode: None,
136 };
137
138 let agent = Participant {
140 id: "did:example:payment_processor".to_string(),
141 role: Some("agent".to_string()),
142 policies: None,
143 leiCode: None,
144 };
145
146 let invoice = create_invoice_with_tax_example()?;
148
149 let mut payment_request = PaymentRequest::with_currency(
151 invoice.currency_code.clone(),
152 format!("{:.2}", invoice.total),
153 merchant.clone(),
154 vec![agent],
155 );
156
157 payment_request.invoice = Some(invoice);
159
160 if let Some(cust_did) = customer_did {
162 payment_request.customer = Some(Participant {
163 id: cust_did.to_string(),
164 role: Some("customer".to_string()),
165 policies: None,
166 leiCode: None,
167 });
168 }
169
170 payment_request.expiry = Some("2023-10-01T00:00:00Z".to_string());
172
173 let recipients = if let Some(cust_did) = customer_did {
175 vec![cust_did]
176 } else {
177 vec![]
178 };
179
180 let message =
181 payment_request.to_didcomm_with_route(Some(merchant_did), recipients.iter().copied())?;
182
183 Ok(message)
184}
185
186pub fn process_payment_request_with_invoice_example(message: &Message) -> Result<()> {
188 let payment_request = PaymentRequest::from_didcomm(message)?;
190
191 payment_request.validate()?;
193
194 if let Some(invoice) = &payment_request.invoice {
196 println!("Invoice ID: {}", invoice.id);
197 println!("Currency: {}", invoice.currency_code);
198 println!("Total amount: {:.2}", invoice.total);
199
200 println!("Line items:");
202 for (i, item) in invoice.line_items.iter().enumerate() {
203 println!(
204 " {}: {} x {} @ {:.2} = {:.2}",
205 i + 1,
206 item.quantity,
207 item.description,
208 item.unit_price,
209 item.line_total
210 );
211 }
212
213 if let Some(tax_total) = &invoice.tax_total {
215 println!("Tax amount: {:.2}", tax_total.tax_amount);
216
217 if let Some(tax_subtotals) = &tax_total.tax_subtotal {
218 for (i, subtotal) in tax_subtotals.iter().enumerate() {
219 println!(
220 " Tax {}: {:.2}% {} on {:.2} = {:.2}",
221 i + 1,
222 subtotal.tax_category.percent,
223 subtotal.tax_category.tax_scheme,
224 subtotal.taxable_amount,
225 subtotal.tax_amount
226 );
227 }
228 }
229 }
230
231 println!(
232 "Due date: {}",
233 invoice.due_date.as_deref().unwrap_or("Not specified")
234 );
235 } else {
236 println!("Payment request does not contain an invoice");
237 }
238
239 Ok(())
240}