Skip to main content

wave_api/inputs/
invoice.rs

1use chrono::NaiveDate;
2use rust_decimal::Decimal;
3use serde::Serialize;
4
5use crate::enums::{CurrencyCode, InvoiceCreateStatus, InvoiceDiscountType, InvoiceSendMethod};
6
7/// Input for creating an invoice.
8#[derive(Debug, Clone, Serialize)]
9#[serde(rename_all = "camelCase")]
10pub struct InvoiceCreateInput {
11    pub business_id: String,
12    pub customer_id: String,
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub status: Option<InvoiceCreateStatus>,
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub currency: Option<CurrencyCode>,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub title: Option<String>,
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub subhead: Option<String>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub invoice_number: Option<String>,
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub po_number: Option<String>,
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub invoice_date: Option<NaiveDate>,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub due_date: Option<NaiveDate>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub exchange_rate: Option<Decimal>,
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub items: Option<Vec<InvoiceCreateItemInput>>,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub discounts: Option<Vec<InvoiceDiscountInput>>,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub memo: Option<String>,
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub footer: Option<String>,
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub disable_credit_card_payments: Option<bool>,
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub disable_bank_payments: Option<bool>,
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub disable_amex_payments: Option<bool>,
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub item_title: Option<String>,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub unit_title: Option<String>,
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub price_title: Option<String>,
51    #[serde(skip_serializing_if = "Option::is_none")]
52    pub amount_title: Option<String>,
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub hide_name: Option<bool>,
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub hide_description: Option<bool>,
57    #[serde(skip_serializing_if = "Option::is_none")]
58    pub hide_unit: Option<bool>,
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub hide_price: Option<bool>,
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub hide_amount: Option<bool>,
63}
64
65impl InvoiceCreateInput {
66    pub fn new(
67        business_id: impl Into<String>,
68        customer_id: impl Into<String>,
69    ) -> Self {
70        Self {
71            business_id: business_id.into(),
72            customer_id: customer_id.into(),
73            status: None,
74            currency: None,
75            title: None,
76            subhead: None,
77            invoice_number: None,
78            po_number: None,
79            invoice_date: None,
80            due_date: None,
81            exchange_rate: None,
82            items: None,
83            discounts: None,
84            memo: None,
85            footer: None,
86            disable_credit_card_payments: None,
87            disable_bank_payments: None,
88            disable_amex_payments: None,
89            item_title: None,
90            unit_title: None,
91            price_title: None,
92            amount_title: None,
93            hide_name: None,
94            hide_description: None,
95            hide_unit: None,
96            hide_price: None,
97            hide_amount: None,
98        }
99    }
100
101    pub fn status(mut self, v: InvoiceCreateStatus) -> Self {
102        self.status = Some(v);
103        self
104    }
105    pub fn items(mut self, v: Vec<InvoiceCreateItemInput>) -> Self {
106        self.items = Some(v);
107        self
108    }
109    pub fn invoice_date(mut self, v: NaiveDate) -> Self {
110        self.invoice_date = Some(v);
111        self
112    }
113    pub fn due_date(mut self, v: NaiveDate) -> Self {
114        self.due_date = Some(v);
115        self
116    }
117    pub fn memo(mut self, v: impl Into<String>) -> Self {
118        self.memo = Some(v.into());
119        self
120    }
121    pub fn footer(mut self, v: impl Into<String>) -> Self {
122        self.footer = Some(v.into());
123        self
124    }
125    pub fn discounts(mut self, v: Vec<InvoiceDiscountInput>) -> Self {
126        self.discounts = Some(v);
127        self
128    }
129}
130
131/// A line item on an invoice create/patch.
132#[derive(Debug, Clone, Serialize)]
133#[serde(rename_all = "camelCase")]
134pub struct InvoiceCreateItemInput {
135    pub product_id: String,
136    #[serde(skip_serializing_if = "Option::is_none")]
137    pub description: Option<String>,
138    #[serde(skip_serializing_if = "Option::is_none")]
139    pub quantity: Option<Decimal>,
140    #[serde(skip_serializing_if = "Option::is_none")]
141    pub unit_price: Option<Decimal>,
142    #[serde(skip_serializing_if = "Option::is_none")]
143    pub taxes: Option<Vec<InvoiceCreateItemTaxInput>>,
144}
145
146impl InvoiceCreateItemInput {
147    pub fn new(product_id: impl Into<String>) -> Self {
148        Self {
149            product_id: product_id.into(),
150            description: None,
151            quantity: None,
152            unit_price: None,
153            taxes: None,
154        }
155    }
156
157    pub fn quantity(mut self, v: Decimal) -> Self {
158        self.quantity = Some(v);
159        self
160    }
161    pub fn unit_price(mut self, v: Decimal) -> Self {
162        self.unit_price = Some(v);
163        self
164    }
165    pub fn description(mut self, v: impl Into<String>) -> Self {
166        self.description = Some(v.into());
167        self
168    }
169}
170
171/// Tax input for an invoice line item.
172#[derive(Debug, Clone, Serialize)]
173#[serde(rename_all = "camelCase")]
174pub struct InvoiceCreateItemTaxInput {
175    pub sales_tax_id: String,
176}
177
178impl InvoiceCreateItemTaxInput {
179    pub fn new(sales_tax_id: impl Into<String>) -> Self {
180        Self {
181            sales_tax_id: sales_tax_id.into(),
182        }
183    }
184}
185
186/// Discount input for an invoice.
187#[derive(Debug, Clone, Serialize)]
188#[serde(rename_all = "camelCase")]
189pub struct InvoiceDiscountInput {
190    pub discount_type: InvoiceDiscountType,
191    #[serde(skip_serializing_if = "Option::is_none")]
192    pub name: Option<String>,
193    #[serde(skip_serializing_if = "Option::is_none")]
194    pub amount: Option<Decimal>,
195    #[serde(skip_serializing_if = "Option::is_none")]
196    pub percentage: Option<Decimal>,
197}
198
199impl InvoiceDiscountInput {
200    pub fn fixed(amount: Decimal) -> Self {
201        Self {
202            discount_type: InvoiceDiscountType::Fixed,
203            name: None,
204            amount: Some(amount),
205            percentage: None,
206        }
207    }
208
209    pub fn percentage(pct: Decimal) -> Self {
210        Self {
211            discount_type: InvoiceDiscountType::Percentage,
212            name: None,
213            amount: None,
214            percentage: Some(pct),
215        }
216    }
217
218    pub fn name(mut self, v: impl Into<String>) -> Self {
219        self.name = Some(v.into());
220        self
221    }
222}
223
224/// Input for patching an invoice.
225#[derive(Debug, Clone, Serialize)]
226#[serde(rename_all = "camelCase")]
227pub struct InvoicePatchInput {
228    pub id: String,
229    #[serde(skip_serializing_if = "Option::is_none")]
230    pub customer_id: Option<String>,
231    #[serde(skip_serializing_if = "Option::is_none")]
232    pub status: Option<InvoiceCreateStatus>,
233    #[serde(skip_serializing_if = "Option::is_none")]
234    pub title: Option<String>,
235    #[serde(skip_serializing_if = "Option::is_none")]
236    pub invoice_date: Option<NaiveDate>,
237    #[serde(skip_serializing_if = "Option::is_none")]
238    pub due_date: Option<NaiveDate>,
239    #[serde(skip_serializing_if = "Option::is_none")]
240    pub items: Option<Vec<InvoiceCreateItemInput>>,
241    #[serde(skip_serializing_if = "Option::is_none")]
242    pub memo: Option<String>,
243    #[serde(skip_serializing_if = "Option::is_none")]
244    pub footer: Option<String>,
245    #[serde(skip_serializing_if = "Option::is_none")]
246    pub po_number: Option<String>,
247    #[serde(skip_serializing_if = "Option::is_none")]
248    pub invoice_number: Option<String>,
249    #[serde(skip_serializing_if = "Option::is_none")]
250    pub discounts: Option<Vec<InvoiceDiscountInput>>,
251}
252
253impl InvoicePatchInput {
254    pub fn new(id: impl Into<String>) -> Self {
255        Self {
256            id: id.into(),
257            customer_id: None,
258            status: None,
259            title: None,
260            invoice_date: None,
261            due_date: None,
262            items: None,
263            memo: None,
264            footer: None,
265            po_number: None,
266            invoice_number: None,
267            discounts: None,
268        }
269    }
270
271    pub fn memo(mut self, v: impl Into<String>) -> Self {
272        self.memo = Some(v.into());
273        self
274    }
275    pub fn items(mut self, v: Vec<InvoiceCreateItemInput>) -> Self {
276        self.items = Some(v);
277        self
278    }
279}
280
281/// Input for deleting an invoice.
282#[derive(Debug, Clone, Serialize)]
283#[serde(rename_all = "camelCase")]
284pub struct InvoiceDeleteInput {
285    pub invoice_id: String,
286}
287
288/// Input for cloning an invoice.
289#[derive(Debug, Clone, Serialize)]
290#[serde(rename_all = "camelCase")]
291pub struct InvoiceCloneInput {
292    pub invoice_id: String,
293}
294
295/// Input for approving an invoice.
296#[derive(Debug, Clone, Serialize)]
297#[serde(rename_all = "camelCase")]
298pub struct InvoiceApproveInput {
299    pub invoice_id: String,
300}
301
302/// Input for marking an invoice as sent.
303#[derive(Debug, Clone, Serialize)]
304#[serde(rename_all = "camelCase")]
305pub struct InvoiceMarkSentInput {
306    pub invoice_id: String,
307    pub send_method: InvoiceSendMethod,
308    #[serde(skip_serializing_if = "Option::is_none")]
309    pub sent_at: Option<chrono::DateTime<chrono::Utc>>,
310}
311
312/// Input for sending an invoice via email.
313#[derive(Debug, Clone, Serialize)]
314#[serde(rename_all = "camelCase")]
315pub struct InvoiceSendInput {
316    pub invoice_id: String,
317    pub to: Vec<String>,
318    #[serde(skip_serializing_if = "Option::is_none")]
319    pub subject: Option<String>,
320    #[serde(skip_serializing_if = "Option::is_none")]
321    pub message: Option<String>,
322    pub attach_pdf: bool,
323    #[serde(skip_serializing_if = "Option::is_none")]
324    pub from_address: Option<String>,
325    #[serde(skip_serializing_if = "Option::is_none")]
326    pub cc_myself: Option<bool>,
327}
328
329impl InvoiceSendInput {
330    pub fn new(invoice_id: impl Into<String>, to: Vec<String>) -> Self {
331        Self {
332            invoice_id: invoice_id.into(),
333            to,
334            subject: None,
335            message: None,
336            attach_pdf: true,
337            from_address: None,
338            cc_myself: None,
339        }
340    }
341
342    pub fn subject(mut self, v: impl Into<String>) -> Self {
343        self.subject = Some(v.into());
344        self
345    }
346    pub fn message(mut self, v: impl Into<String>) -> Self {
347        self.message = Some(v.into());
348        self
349    }
350}