flowglad 0.1.0

Rust SDK for FlowGlad - Open source billing infrastructure
Documentation
//! Customer resource endpoints
//!
//! This module provides methods for interacting with the FlowGlad Customer API.
//!
//! # Example
//!
//! ```no_run
//! use flowglad::{Client, Config};
//! use flowglad::types::customer::CreateCustomer;
//!
//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
//! let client = Client::new(Config::new("sk_test_..."))?;
//!
//! // Create a customer
//! let customer = client.customers().create(
//!     CreateCustomer::new("user_123", "Jane Doe")
//!         .email("customer@example.com")
//! ).await?;
//!
//! // Retrieve the customer by external_id
//! let retrieved = client.customers().get("user_123").await?;
//!
//! // List all customers
//! let customers = client.customers().list().await?;
//! # Ok(())
//! # }
//! ```

use crate::client::Client;
use crate::error::Result;
use crate::types::customer::{
    BillingDetails, CreateCustomer, CreateCustomerRequest, Customer, CustomerResponse,
    SingleCustomerResponse, UpdateCustomer, UpdateCustomerRequest,
};
use crate::types::ListResponse;

impl Client {
    /// Access the Customers resource
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use flowglad::{Client, Config};
    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// # let client = Client::new(Config::new("sk_test_..."))?;
    /// let customers = client.customers().list().await?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn customers(&self) -> Customers<'_> {
        Customers { client: self }
    }
}

/// Customer resource methods
///
/// Provides methods for creating, retrieving, updating, and listing customers.
pub struct Customers<'a> {
    client: &'a Client,
}

impl<'a> Customers<'a> {
    /// Create a new customer
    ///
    /// # Arguments
    ///
    /// * `params` - Customer creation parameters
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use flowglad::{Client, Config};
    /// # use flowglad::types::customer::CreateCustomer;
    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// # let client = Client::new(Config::new("sk_test_..."))?;
    /// let customer = client.customers().create(
    ///     CreateCustomer::new("user_123", "Jane Doe")
    ///         .email("customer@example.com")
    ///         .metadata("plan", serde_json::json!("premium"))
    /// ).await?;
    ///
    /// println!("Created customer: {}", customer.id);
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// # Errors
    ///
    /// Returns an error if:
    /// - The API request fails
    /// - The response cannot be parsed
    ///
    /// # See Also
    ///
    /// - [FlowGlad API: Create Customer](https://docs.flowglad.com/api-reference/customer/create-customer)
    pub async fn create(&self, params: CreateCustomer) -> Result<Customer> {
        let request = CreateCustomerRequest { customer: params };
        let response: CustomerResponse = self.client.post("/customers", &request).await?;
        Ok(response.data.customer)
    }

    /// Retrieve a customer by external ID
    ///
    /// # Arguments
    ///
    /// * `external_id` - The customer's external identifier (from your system)
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use flowglad::{Client, Config};
    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// # let client = Client::new(Config::new("sk_test_..."))?;
    /// let customer = client.customers().get("user_123").await?;
    ///
    /// println!("Customer: {} ({})", customer.name.unwrap_or_default(), customer.email.unwrap_or_default());
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// # Errors
    ///
    /// Returns an error if:
    /// - The customer does not exist (404)
    /// - The API request fails
    ///
    /// # See Also
    ///
    /// - [FlowGlad API: Get Customer](https://docs.flowglad.com/api-reference/customer/get-customer)
    pub async fn get(&self, external_id: &str) -> Result<Customer> {
        let response: SingleCustomerResponse = self
            .client
            .get(&format!("/customers/{}", external_id))
            .await?;
        Ok(response.customer)
    }

    /// List all customers
    ///
    /// Returns a paginated list of all customers.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use flowglad::{Client, Config};
    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// # let client = Client::new(Config::new("sk_test_..."))?;
    /// let response = client.customers().list().await?;
    ///
    /// for customer in response.data {
    ///     println!("Customer: {} - {}", customer.id, customer.email.unwrap_or_default());
    /// }
    ///
    /// if response.has_more == Some(true) {
    ///     println!("More customers available...");
    /// }
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// # Errors
    ///
    /// Returns an error if the API request fails.
    ///
    /// # See Also
    ///
    /// - [FlowGlad API: List Customers](https://docs.flowglad.com/api-reference/customer/list-customers)
    pub async fn list(&self) -> Result<ListResponse<Customer>> {
        self.client.get("/customers").await
    }

    /// Update a customer
    ///
    /// # Arguments
    ///
    /// * `external_id` - The customer's external identifier
    /// * `params` - Customer update parameters
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use flowglad::{Client, Config};
    /// # use flowglad::types::customer::UpdateCustomer;
    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// # let client = Client::new(Config::new("sk_test_..."))?;
    /// let updated = client.customers().update(
    ///     "user_123",
    ///     UpdateCustomer::new()
    ///         .email("newemail@example.com")
    ///         .name("Jane Smith")
    /// ).await?;
    ///
    /// println!("Updated customer: {}", updated.id);
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// # Errors
    ///
    /// Returns an error if:
    /// - The customer does not exist (404)
    /// - The API request fails
    ///
    /// # See Also
    ///
    /// - [FlowGlad API: Update Customer](https://docs.flowglad.com/api-reference/customer/update-customer)
    pub async fn update(&self, external_id: &str, params: UpdateCustomer) -> Result<Customer> {
        let request = UpdateCustomerRequest { customer: params };
        let response: SingleCustomerResponse = self
            .client
            .put(&format!("/customers/{}", external_id), &request)
            .await?;
        Ok(response.customer)
    }

    /// Get billing details for a customer
    ///
    /// Returns comprehensive billing information including subscriptions,
    /// features, and usage for the specified customer.
    ///
    /// # Arguments
    ///
    /// * `external_id` - The customer's external identifier
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use flowglad::{Client, Config};
    /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
    /// # let client = Client::new(Config::new("sk_test_..."))?;
    /// let billing = client.customers().get_billing("user_123").await?;
    ///
    /// println!("Billing details: {:?}", billing);
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// # Errors
    ///
    /// Returns an error if:
    /// - The customer does not exist (404)
    /// - The API request fails
    ///
    /// # See Also
    ///
    /// - [FlowGlad API: Get Billing Details](https://docs.flowglad.com/api-reference/customer/get-billing-details)
    pub async fn get_billing(&self, external_id: &str) -> Result<BillingDetails> {
        self.client
            .get(&format!("/customers/{}/billing", external_id))
            .await
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_customers_accessor() {
        let config = crate::Config::new("sk_test_123");
        let client = Client::new(config).unwrap();
        let _customers = client.customers();
        // Just verify it compiles and we can access the resource
    }
}