amazon_spapi/client_apis/
fees_api.rs

1use crate::{
2    client::SpapiClient,
3    models::{
4        self,
5        product_fees_v0::{
6            FeesEstimateByIdRequest, FeesEstimateRequest, GetMyFeesEstimateRequest, IdType,
7            MoneyType, OptionalFulfillmentProgram, PriceToEstimateFees,
8        },
9        sellers::{GetAccountResponse, GetMarketplaceParticipationsResponse},
10    },
11};
12use anyhow::Result;
13
14impl SpapiClient {
15    pub async fn get_my_fees_estimate_for_asin(
16        &self,
17        asin: &str,
18        body: models::product_fees_v0::GetMyFeesEstimateRequest,
19    ) -> Result<models::product_fees_v0::GetMyFeesEstimateResponse> {
20        let configuration = self.create_configuration().await?;
21        let guard = self
22            .limiter()
23            .wait("/products/fees/v0/items/feesEstimate", 1.0, 2)
24            .await?;
25        let res = crate::apis::fees_api::get_my_fees_estimate_for_asin(&configuration, asin, body)
26            .await?;
27        guard.mark_response().await;
28        Ok(res)
29    }
30
31    pub async fn get_my_fees_estimate_for_sku(
32        &self,
33        seller_sku: &str,
34        body: models::product_fees_v0::GetMyFeesEstimateRequest,
35    ) -> Result<models::product_fees_v0::GetMyFeesEstimateResponse> {
36        let configuration = self.create_configuration().await?;
37        let guard = self
38            .limiter()
39            .wait("/products/fees/v0/listings/feesEstimate", 1.0, 2)
40            .await?;
41        let res =
42            crate::apis::fees_api::get_my_fees_estimate_for_sku(&configuration, seller_sku, body)
43                .await?;
44        guard.mark_response().await;
45        Ok(res)
46    }
47
48    pub async fn get_my_fees_estimates(
49        &self,
50        body: Vec<models::product_fees_v0::FeesEstimateByIdRequest>,
51    ) -> Result<Vec<models::product_fees_v0::FeesEstimateResult>> {
52        let configuration = self.create_configuration().await?;
53        let guard = self
54            .limiter()
55            .wait("/products/fees/v0/feesEstimate", 0.5, 1)
56            .await?;
57        let res = crate::apis::fees_api::get_my_fees_estimates(&configuration, body).await?;
58        guard.mark_response().await;
59        Ok(res)
60    }
61
62    /// Convenience method to get fees estimate for a single ASIN with price
63    pub async fn get_fee_for_asin(
64        &self,
65        asin: &str,
66        price: f64,
67        is_amazon_fulfilled: bool,
68    ) -> Result<f64> {
69        let request = GetMyFeesEstimateRequest {
70            fees_estimate_request: Some(Box::new(FeesEstimateRequest {
71                marketplace_id: self.get_marketplace_id().to_string(),
72                is_amazon_fulfilled: Some(is_amazon_fulfilled),
73                price_to_estimate_fees: Box::new(PriceToEstimateFees {
74                    listing_price: Box::new(MoneyType {
75                        currency_code: Some("USD".to_string()),
76                        amount: Some(price),
77                    }),
78                    shipping: None,
79                    points: None,
80                }),
81                identifier: asin.to_string(),
82                optional_fulfillment_program: Some(OptionalFulfillmentProgram::FbaCore),
83            })),
84        };
85
86        let response = self.get_my_fees_estimate_for_asin(asin, request).await?;
87
88        if let Some(payload) = response.payload {
89            if let Some(result) = payload.fees_estimate_result {
90                if result.status == Some("Success".to_string()) {
91                    if let Some(estimate) = result.fees_estimate {
92                        if let Some(total_fees) = estimate.total_fees_estimate {
93                            return Ok(total_fees.amount.unwrap_or(0.0));
94                        }
95                    }
96                }
97            }
98        }
99
100        Err(anyhow::anyhow!(
101            "Failed to get fee estimate for ASIN: {}",
102            asin
103        ))
104    }
105
106    /// Get fees estimates for multiple ASINs (batch operation)
107    pub async fn get_fees_for_asins(
108        &self,
109        asins_with_prices: Vec<(String, f64)>,
110        is_amazon_fulfilled: bool,
111    ) -> Result<Vec<(String, f64)>> {
112        let requests: Vec<FeesEstimateByIdRequest> = asins_with_prices
113            .iter()
114            .map(|(asin, price)| FeesEstimateByIdRequest {
115                fees_estimate_request: Some(Box::new(FeesEstimateRequest {
116                    marketplace_id: self.get_marketplace_id().to_string(),
117                    is_amazon_fulfilled: Some(is_amazon_fulfilled),
118                    price_to_estimate_fees: Box::new(PriceToEstimateFees {
119                        listing_price: Box::new(MoneyType {
120                            currency_code: Some("USD".to_string()),
121                            amount: Some(*price),
122                        }),
123                        shipping: None,
124                        points: None,
125                    }),
126                    identifier: asin.clone(),
127                    optional_fulfillment_program: None,
128                })),
129                id_type: IdType::Asin,
130                id_value: asin.clone(),
131            })
132            .collect();
133
134        let results = self.get_my_fees_estimates(requests).await?;
135
136        let mut fees: Vec<(String, f64)> = Vec::new();
137        for result in results {
138            if let Some(identifier) = result.fees_estimate_identifier {
139                let asin = identifier.id_value.unwrap_or_default();
140                let fee = if result.status == Some("Success".to_string()) {
141                    if let Some(estimate) = result.fees_estimate {
142                        if let Some(total_fees) = estimate.total_fees_estimate {
143                            total_fees.amount.unwrap_or(0.0)
144                        } else {
145                            0.0
146                        }
147                    } else {
148                        0.0
149                    }
150                } else {
151                    0.0
152                };
153                fees.push((asin, fee));
154            }
155        }
156
157        Ok(fees)
158    }
159
160    /// Convenience method to get fees estimate for a single SKU with price
161    pub async fn get_fee_for_sku(
162        &self,
163        sku: &str,
164        price: f64,
165        is_amazon_fulfilled: bool,
166    ) -> Result<f64> {
167        let request = GetMyFeesEstimateRequest {
168            fees_estimate_request: Some(Box::new(FeesEstimateRequest {
169                marketplace_id: self.get_marketplace_id().to_string(),
170                is_amazon_fulfilled: Some(is_amazon_fulfilled),
171                price_to_estimate_fees: Box::new(PriceToEstimateFees {
172                    listing_price: Box::new(MoneyType {
173                        currency_code: Some("USD".to_string()),
174                        amount: Some(price),
175                    }),
176                    shipping: None,
177                    points: None,
178                }),
179                identifier: sku.to_string(),
180                optional_fulfillment_program: Some(OptionalFulfillmentProgram::FbaCore),
181            })),
182        };
183
184        let response = self.get_my_fees_estimate_for_sku(sku, request).await?;
185
186        if let Some(payload) = response.payload {
187            if let Some(result) = payload.fees_estimate_result {
188                if result.status == Some("Success".to_string()) {
189                    if let Some(estimate) = result.fees_estimate {
190                        if let Some(total_fees) = estimate.total_fees_estimate {
191                            return Ok(total_fees.amount.unwrap_or(0.0));
192                        }
193                    }
194                }
195            }
196        }
197
198        Err(anyhow::anyhow!(
199            "Failed to get fee estimate for SKU: {}",
200            sku
201        ))
202    }
203
204    /// Get fees estimates for multiple SKUs (batch operation)
205    pub async fn get_fees_for_skus(
206        &self,
207        skus_with_prices: Vec<(String, f64)>,
208        is_amazon_fulfilled: bool,
209    ) -> Result<Vec<(String, f64)>> {
210        let requests: Vec<FeesEstimateByIdRequest> = skus_with_prices
211            .iter()
212            .map(|(sku, price)| FeesEstimateByIdRequest {
213                fees_estimate_request: Some(Box::new(FeesEstimateRequest {
214                    marketplace_id: self.get_marketplace_id().to_string(),
215                    is_amazon_fulfilled: Some(is_amazon_fulfilled),
216                    price_to_estimate_fees: Box::new(PriceToEstimateFees {
217                        listing_price: Box::new(MoneyType {
218                            currency_code: Some("USD".to_string()),
219                            amount: Some(*price),
220                        }),
221                        shipping: None,
222                        points: None,
223                    }),
224                    identifier: sku.clone(),
225                    optional_fulfillment_program: None,
226                })),
227                id_type: IdType::SellerSku,
228                id_value: sku.clone(),
229            })
230            .collect();
231        let results = self.get_my_fees_estimates(requests).await?;
232        let mut fees: Vec<(String, f64)> = Vec::new();
233        for result in results {
234            if let Some(identifier) = result.fees_estimate_identifier {
235                let sku = identifier.id_value.unwrap_or_default();
236                let fee = if result.status == Some("Success".to_string()) {
237                    if let Some(estimate) = result.fees_estimate {
238                        if let Some(total_fees) = estimate.total_fees_estimate {
239                            total_fees.amount.unwrap_or(0.0)
240                        } else {
241                            0.0
242                        }
243                    } else {
244                        0.0
245                    }
246                } else {
247                    0.0
248                };
249                fees.push((sku, fee));
250            }
251        }
252        Ok(fees)
253    }
254}