Skip to main content

sure_client_rs/client/
valuations.rs

1use crate::error::ApiResult;
2use crate::models::valuation::{
3    CreateValuationData, CreateValuationRequest, UpdateValuationData, UpdateValuationRequest,
4    Valuation,
5};
6use crate::types::{AccountId, ValuationId};
7use bon::bon;
8use chrono::NaiveDate;
9use reqwest::Method;
10use rust_decimal::Decimal;
11
12use super::SureClient;
13
14#[bon]
15impl SureClient {
16    /// Create a new valuation entry for an account.
17    ///
18    /// Valuations are most commonly used to record point-in-time balances for
19    /// asset accounts whose value drifts over time, such as properties, vehicles,
20    /// or investment portfolios that are not synced from a brokerage. Each
21    /// valuation appears as a `reconciliation` entry on the account's timeline.
22    ///
23    /// # Arguments
24    /// * `account_id` - The account the valuation applies to (required).
25    /// * `amount` - The valuation amount (required).
26    /// * `date` - The valuation date (required).
27    /// * `notes` - Optional notes attached to the entry.
28    ///
29    /// # Returns
30    /// The created valuation entry.
31    ///
32    /// # Errors
33    /// Returns `ApiError::ValidationError` if required fields are missing or invalid.
34    /// Returns `ApiError::Unauthorized` if the credentials are missing/invalid.
35    /// Returns `ApiError::Network` if the request fails due to network issues.
36    ///
37    /// # Example
38    /// ```no_run
39    /// use sure_client_rs::{SureClient, AccountId};
40    /// use chrono::NaiveDate;
41    /// use rust_decimal::Decimal;
42    /// use uuid::Uuid;
43    ///
44    /// # async fn example(client: SureClient) -> Result<(), Box<dyn std::error::Error>> {
45    /// let account_id = AccountId::new(Uuid::new_v4());
46    /// let valuation = client.create_valuation()
47    ///     .account_id(account_id)
48    ///     .amount(Decimal::new(77000000, 2)) // $770,000.00
49    ///     .date(NaiveDate::from_ymd_opt(2025, 12, 12).unwrap())
50    ///     .call()
51    ///     .await?;
52    /// println!("Created valuation: {} on {}", valuation.amount, valuation.date);
53    /// # Ok(())
54    /// # }
55    /// ```
56    #[builder]
57    pub async fn create_valuation(
58        &self,
59        account_id: AccountId,
60        amount: Decimal,
61        date: NaiveDate,
62        notes: Option<String>,
63    ) -> ApiResult<Valuation> {
64        let request = CreateValuationRequest {
65            valuation: CreateValuationData {
66                account_id,
67                amount,
68                date,
69                notes,
70            },
71        };
72
73        self.execute_request(
74            Method::POST,
75            "/api/v1/valuations",
76            None,
77            Some(serde_json::to_string(&request)?),
78        )
79        .await
80    }
81
82    /// Get a specific valuation by ID.
83    ///
84    /// # Arguments
85    /// * `id` - The valuation ID to retrieve.
86    pub async fn get_valuation(&self, id: &ValuationId) -> ApiResult<Valuation> {
87        self.execute_request(
88            Method::GET,
89            &format!("/api/v1/valuations/{}", id),
90            None,
91            None,
92        )
93        .await
94    }
95
96    /// Update an existing valuation entry.
97    ///
98    /// The Sure API requires both `amount` and `date` to be supplied together
99    /// when changing the underlying reconciliation; `notes` may be updated
100    /// independently.
101    ///
102    /// # Arguments
103    /// * `id` - The valuation ID to update.
104    /// * `amount` - New amount (must accompany `date` if either is set).
105    /// * `date` - New date (must accompany `amount` if either is set).
106    /// * `notes` - New notes.
107    #[builder]
108    pub async fn update_valuation(
109        &self,
110        id: &ValuationId,
111        amount: Option<Decimal>,
112        date: Option<NaiveDate>,
113        notes: Option<String>,
114    ) -> ApiResult<Valuation> {
115        let request = UpdateValuationRequest {
116            valuation: UpdateValuationData {
117                amount,
118                date,
119                notes,
120            },
121        };
122
123        self.execute_request(
124            Method::PATCH,
125            &format!("/api/v1/valuations/{}", id),
126            None,
127            Some(serde_json::to_string(&request)?),
128        )
129        .await
130    }
131}