lago_types/requests/
invoice.rs

1use serde::{Deserialize, Serialize};
2
3use crate::models::PaginationParams;
4
5use crate::filters::{common::ListFilters, invoice::InvoiceFilters};
6
7/// Request parameters for listing invoices.
8///
9/// This struct combines pagination parameters and invoice-specific filters
10/// to build a comprehensive request for retrieving invoice lists.
11#[derive(Debug, Clone)]
12pub struct ListInvoicesRequest {
13    pub pagination: PaginationParams,
14    pub filters: InvoiceFilters,
15}
16
17impl ListInvoicesRequest {
18    /// Creates a new empty list invoices request.
19    ///
20    /// # Returns
21    /// A new `ListInvoicesRequest` instance with default pagination and no filters.
22    pub fn new() -> Self {
23        Self {
24            pagination: PaginationParams::default(),
25            filters: InvoiceFilters::default(),
26        }
27    }
28
29    /// Sets the pagination parameters for the request.
30    ///
31    /// # Arguments
32    /// * `pagination` - The pagination parameters to use
33    ///
34    /// # Returns
35    /// The modified request instance for method chaining.
36    pub fn with_pagination(mut self, pagination: PaginationParams) -> Self {
37        self.pagination = pagination;
38        self
39    }
40
41    /// Sets the invoice filters for the request.
42    ///
43    /// # Arguments
44    /// * `filters` - The invoice filters to apply
45    ///
46    /// # Returns
47    /// The modified request instance for method chaining.
48    pub fn with_filters(mut self, filters: InvoiceFilters) -> Self {
49        self.filters = filters;
50        self
51    }
52
53    /// Converts the request parameters into HTTP query parameters.
54    ///
55    /// # Returns
56    /// A vector of query parameter tuples containing both pagination and filter criteria.
57    pub fn to_query_params(&self) -> Vec<(&str, String)> {
58        let mut params = self.pagination.to_query_params();
59        params.extend(self.filters.to_query_params());
60        params
61    }
62}
63
64impl Default for ListInvoicesRequest {
65    fn default() -> Self {
66        Self::new()
67    }
68}
69
70/// Request parameters for retrieving a specific invoice.
71///
72/// This struct contains the identifier needed to fetch a single invoice
73/// from the API.
74#[derive(Debug, Clone)]
75pub struct GetInvoiceRequest {
76    pub invoice_id: String,
77}
78
79impl GetInvoiceRequest {
80    /// Creates a new get invoice request.
81    ///
82    /// # Arguments
83    /// * `invoice_id` - The unique identifier of the invoice to retrieve
84    ///
85    /// # Returns
86    /// A new `GetInvoiceRequest` instance with the specified invoice ID.
87    pub fn new(invoice_id: String) -> Self {
88        Self { invoice_id }
89    }
90}
91
92/// Billing time determines when recurring billing cycles occur.
93#[derive(Debug, Clone, Serialize, Deserialize)]
94#[serde(rename_all = "snake_case")]
95pub enum BillingTime {
96    /// Billing cycle based on the specific date the subscription started (billed fully).
97    Anniversary,
98    /// Billing cycle at the first day of the week/month/year (billed with proration).
99    Calendar,
100}
101
102/// Customer information for invoice preview.
103///
104/// This struct contains customer data used when generating an invoice preview.
105/// It can reference an existing customer via external_id or provide inline customer details.
106#[derive(Debug, Clone, Default, Serialize, Deserialize)]
107pub struct InvoicePreviewCustomer {
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub external_id: Option<String>,
110    #[serde(skip_serializing_if = "Option::is_none")]
111    pub name: Option<String>,
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub address_line1: Option<String>,
114    #[serde(skip_serializing_if = "Option::is_none")]
115    pub address_line2: Option<String>,
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub city: Option<String>,
118    #[serde(skip_serializing_if = "Option::is_none")]
119    pub state: Option<String>,
120    #[serde(skip_serializing_if = "Option::is_none")]
121    pub country: Option<String>,
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub currency: Option<String>,
124    #[serde(skip_serializing_if = "Option::is_none")]
125    pub timezone: Option<String>,
126    #[serde(skip_serializing_if = "Option::is_none")]
127    pub tax_identification_number: Option<String>,
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub shipping_address: Option<InvoicePreviewAddress>,
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub integration_customers: Option<Vec<InvoicePreviewIntegrationCustomer>>,
132}
133
134impl InvoicePreviewCustomer {
135    /// Creates a new invoice preview customer with an external ID.
136    ///
137    /// # Arguments
138    /// * `external_id` - The unique external identifier for the customer
139    ///
140    /// # Returns
141    /// A new `InvoicePreviewCustomer` instance
142    pub fn with_external_id(external_id: String) -> Self {
143        Self {
144            external_id: Some(external_id),
145            ..Default::default()
146        }
147    }
148
149    /// Creates a new empty invoice preview customer for inline definition.
150    ///
151    /// # Returns
152    /// A new empty `InvoicePreviewCustomer` instance
153    pub fn new() -> Self {
154        Self::default()
155    }
156
157    pub fn with_name(mut self, name: String) -> Self {
158        self.name = Some(name);
159        self
160    }
161
162    pub fn with_address(
163        mut self,
164        address_line1: String,
165        address_line2: Option<String>,
166        city: Option<String>,
167        state: Option<String>,
168        country: Option<String>,
169    ) -> Self {
170        self.address_line1 = Some(address_line1);
171        self.address_line2 = address_line2;
172        self.city = city;
173        self.state = state;
174        self.country = country;
175        self
176    }
177
178    pub fn with_currency(mut self, currency: String) -> Self {
179        self.currency = Some(currency);
180        self
181    }
182
183    pub fn with_timezone(mut self, timezone: String) -> Self {
184        self.timezone = Some(timezone);
185        self
186    }
187
188    pub fn with_tax_identification_number(mut self, tax_id: String) -> Self {
189        self.tax_identification_number = Some(tax_id);
190        self
191    }
192
193    pub fn with_shipping_address(mut self, address: InvoicePreviewAddress) -> Self {
194        self.shipping_address = Some(address);
195        self
196    }
197
198    pub fn with_integration_customers(
199        mut self,
200        integrations: Vec<InvoicePreviewIntegrationCustomer>,
201    ) -> Self {
202        self.integration_customers = Some(integrations);
203        self
204    }
205}
206
207/// Address information for invoice preview.
208#[derive(Debug, Clone, Default, Serialize, Deserialize)]
209pub struct InvoicePreviewAddress {
210    #[serde(skip_serializing_if = "Option::is_none")]
211    pub address_line1: Option<String>,
212    #[serde(skip_serializing_if = "Option::is_none")]
213    pub address_line2: Option<String>,
214    #[serde(skip_serializing_if = "Option::is_none")]
215    pub city: Option<String>,
216    #[serde(skip_serializing_if = "Option::is_none")]
217    pub state: Option<String>,
218    #[serde(skip_serializing_if = "Option::is_none")]
219    pub country: Option<String>,
220    #[serde(skip_serializing_if = "Option::is_none")]
221    pub zipcode: Option<String>,
222}
223
224/// Integration customer for tax providers like Anrok.
225#[derive(Debug, Clone, Serialize, Deserialize)]
226pub struct InvoicePreviewIntegrationCustomer {
227    pub integration_type: String,
228    pub integration_code: String,
229}
230
231/// Coupon information for invoice preview.
232#[derive(Debug, Clone, Serialize, Deserialize)]
233pub struct InvoicePreviewCoupon {
234    pub code: String,
235    #[serde(skip_serializing_if = "Option::is_none")]
236    pub name: Option<String>,
237    #[serde(skip_serializing_if = "Option::is_none")]
238    pub coupon_type: Option<InvoicePreviewCouponType>,
239    #[serde(skip_serializing_if = "Option::is_none")]
240    pub amount_cents: Option<i64>,
241    #[serde(skip_serializing_if = "Option::is_none")]
242    pub amount_currency: Option<String>,
243    #[serde(skip_serializing_if = "Option::is_none")]
244    pub percentage_rate: Option<String>,
245    #[serde(skip_serializing_if = "Option::is_none")]
246    pub frequency_duration: Option<i32>,
247}
248
249impl InvoicePreviewCoupon {
250    /// Creates a new coupon with the required code.
251    ///
252    /// # Arguments
253    /// * `code` - The unique code for the coupon
254    ///
255    /// # Returns
256    /// A new `InvoicePreviewCoupon` instance
257    pub fn new(code: String) -> Self {
258        Self {
259            code,
260            name: None,
261            coupon_type: None,
262            amount_cents: None,
263            amount_currency: None,
264            percentage_rate: None,
265            frequency_duration: None,
266        }
267    }
268
269    pub fn with_name(mut self, name: String) -> Self {
270        self.name = Some(name);
271        self
272    }
273
274    pub fn with_fixed_amount(mut self, amount_cents: i64, currency: String) -> Self {
275        self.coupon_type = Some(InvoicePreviewCouponType::FixedAmount);
276        self.amount_cents = Some(amount_cents);
277        self.amount_currency = Some(currency);
278        self
279    }
280
281    pub fn with_percentage(mut self, percentage_rate: String) -> Self {
282        self.coupon_type = Some(InvoicePreviewCouponType::Percentage);
283        self.percentage_rate = Some(percentage_rate);
284        self
285    }
286
287    pub fn with_frequency_duration(mut self, duration: i32) -> Self {
288        self.frequency_duration = Some(duration);
289        self
290    }
291}
292
293/// Type of coupon discount.
294#[derive(Debug, Clone, Serialize, Deserialize)]
295#[serde(rename_all = "snake_case")]
296pub enum InvoicePreviewCouponType {
297    FixedAmount,
298    Percentage,
299}
300
301/// Subscription information for invoice preview.
302///
303/// Used to specify existing subscriptions to include in the preview,
304/// with optional plan changes or termination.
305#[derive(Debug, Clone, Serialize, Deserialize)]
306pub struct InvoicePreviewSubscriptions {
307    pub external_ids: Vec<String>,
308    #[serde(skip_serializing_if = "Option::is_none")]
309    pub plan_code: Option<String>,
310    #[serde(skip_serializing_if = "Option::is_none")]
311    pub terminated_at: Option<String>,
312}
313
314impl InvoicePreviewSubscriptions {
315    /// Creates a new subscriptions object with the required external IDs.
316    ///
317    /// # Arguments
318    /// * `external_ids` - The external identifiers of the subscriptions
319    ///
320    /// # Returns
321    /// A new `InvoicePreviewSubscriptions` instance
322    pub fn new(external_ids: Vec<String>) -> Self {
323        Self {
324            external_ids,
325            plan_code: None,
326            terminated_at: None,
327        }
328    }
329
330    pub fn with_plan_code(mut self, plan_code: String) -> Self {
331        self.plan_code = Some(plan_code);
332        self
333    }
334
335    pub fn with_terminated_at(mut self, terminated_at: String) -> Self {
336        self.terminated_at = Some(terminated_at);
337        self
338    }
339}
340
341/// Input parameters for previewing an invoice.
342///
343/// This struct contains all the information needed to generate an invoice preview
344/// without actually creating the invoice.
345#[derive(Debug, Clone, Default, Serialize, Deserialize)]
346pub struct InvoicePreviewInput {
347    pub customer: InvoicePreviewCustomer,
348    #[serde(skip_serializing_if = "Option::is_none")]
349    pub plan_code: Option<String>,
350    #[serde(skip_serializing_if = "Option::is_none")]
351    pub subscription_at: Option<String>,
352    #[serde(skip_serializing_if = "Option::is_none")]
353    pub billing_time: Option<BillingTime>,
354    #[serde(skip_serializing_if = "Option::is_none")]
355    pub coupons: Option<Vec<InvoicePreviewCoupon>>,
356    #[serde(skip_serializing_if = "Option::is_none")]
357    pub subscriptions: Option<InvoicePreviewSubscriptions>,
358    #[serde(skip_serializing_if = "Option::is_none")]
359    pub billing_entity_code: Option<String>,
360}
361
362impl InvoicePreviewInput {
363    /// Creates a new invoice preview input with a customer reference.
364    ///
365    /// # Arguments
366    /// * `customer` - The customer information for the preview
367    ///
368    /// # Returns
369    /// A new `InvoicePreviewInput` instance
370    pub fn new(customer: InvoicePreviewCustomer) -> Self {
371        Self {
372            customer,
373            ..Default::default()
374        }
375    }
376
377    /// Creates an invoice preview for an existing customer.
378    ///
379    /// # Arguments
380    /// * `external_id` - The external ID of the existing customer
381    ///
382    /// # Returns
383    /// A new `InvoicePreviewInput` instance
384    pub fn for_customer(external_id: String) -> Self {
385        Self::new(InvoicePreviewCustomer::with_external_id(external_id))
386    }
387
388    pub fn with_plan_code(mut self, plan_code: String) -> Self {
389        self.plan_code = Some(plan_code);
390        self
391    }
392
393    pub fn with_subscription_at(mut self, subscription_at: String) -> Self {
394        self.subscription_at = Some(subscription_at);
395        self
396    }
397
398    pub fn with_billing_time(mut self, billing_time: BillingTime) -> Self {
399        self.billing_time = Some(billing_time);
400        self
401    }
402
403    pub fn with_coupons(mut self, coupons: Vec<InvoicePreviewCoupon>) -> Self {
404        self.coupons = Some(coupons);
405        self
406    }
407
408    pub fn with_subscriptions(mut self, subscriptions: InvoicePreviewSubscriptions) -> Self {
409        self.subscriptions = Some(subscriptions);
410        self
411    }
412
413    pub fn with_billing_entity_code(mut self, code: String) -> Self {
414        self.billing_entity_code = Some(code);
415        self
416    }
417}
418
419/// Request parameters for previewing an invoice.
420///
421/// This struct wraps the invoice preview input in the expected API format.
422#[derive(Debug, Clone, Serialize, Deserialize)]
423pub struct InvoicePreviewRequest {
424    #[serde(flatten)]
425    pub input: InvoicePreviewInput,
426}
427
428impl InvoicePreviewRequest {
429    /// Creates a new preview invoice request.
430    ///
431    /// # Arguments
432    /// * `input` - The invoice preview input data
433    ///
434    /// # Returns
435    /// A new `InvoicePreviewRequest` instance
436    pub fn new(input: InvoicePreviewInput) -> Self {
437        Self { input }
438    }
439}