amazon_spapi/client_apis/
reports_api.rs1use std::time::Duration;
2
3use crate::{
4 client::{ApiEndpoint, ApiMethod, SpapiClient},
5 models::{
6 self,
7 reports_2021_06_30::{report::ProcessingStatus, CreateReportSpecification},
8 sellers::{GetAccountResponse, GetMarketplaceParticipationsResponse},
9 },
10};
11use anyhow::Result;
12use tokio::time::sleep;
13
14impl SpapiClient {
15 pub async fn cancel_report(&self, report_id: &str) -> Result<()> {
16 let configuration = self.create_configuration().await?;
17 let _ = self
18 .limiter()
19 .wait("/reports/v2021-06-30/reports/{reportId}/cancel", 0.016, 15)
20 .await?;
21 let res = crate::apis::reports_api::cancel_report(&configuration, report_id).await;
22 Ok(res?)
23 }
24
25 pub async fn cancel_report_schedule(&self, report_schedule_id: &str) -> Result<()> {
26 let configuration = self.create_configuration().await?;
27 let _ = self
28 .limiter()
29 .wait(
30 "/reports/v2021-06-30/schedules/{reportScheduleId}/cancel",
31 0.016,
32 15,
33 )
34 .await?;
35 let res =
36 crate::apis::reports_api::cancel_report_schedule(&configuration, report_schedule_id)
37 .await;
38 Ok(res?)
39 }
40
41 pub async fn create_report(
42 &self,
43 body: models::reports_2021_06_30::CreateReportSpecification,
44 ) -> Result<models::reports_2021_06_30::CreateReportResponse> {
45 let configuration = self.create_configuration().await?;
46 let _ = self
47 .limiter()
48 .wait("/reports/v2021-06-30/reports", 0.016, 15)
49 .await?;
50 let res = crate::apis::reports_api::create_report(&configuration, body).await;
51 Ok(res?)
52 }
53
54 pub async fn create_report_schedule(
55 &self,
56 body: models::reports_2021_06_30::CreateReportScheduleSpecification,
57 ) -> Result<models::reports_2021_06_30::CreateReportScheduleResponse> {
58 let configuration = self.create_configuration().await?;
59 let _ = self
60 .limiter()
61 .wait("/reports/v2021-06-30/schedules", 0.016, 15)
62 .await?;
63 let res = crate::apis::reports_api::create_report_schedule(&configuration, body).await;
64 Ok(res?)
65 }
66
67 pub async fn get_report(&self, report_id: &str) -> Result<models::reports_2021_06_30::Report> {
68 let configuration = self.create_configuration().await?;
69 let _ = self
70 .limiter()
71 .wait("/reports/v2021-06-30/reports/{reportId}", 0.016, 15)
72 .await?;
73 let res = crate::apis::reports_api::get_report(&configuration, report_id).await;
74 Ok(res?)
75 }
76
77 pub async fn get_report_document(
78 &self,
79 report_document_id: &str,
80 ) -> Result<models::reports_2021_06_30::ReportDocument> {
81 let configuration = self.create_configuration().await?;
82 let _ = self
83 .limiter()
84 .wait(
85 "/reports/v2021-06-30/reports/{reportId}/document",
86 0.016,
87 15,
88 )
89 .await?;
90 let res =
91 crate::apis::reports_api::get_report_document(&configuration, report_document_id).await;
92 Ok(res?)
93 }
94
95 pub async fn get_report_schedule(
96 &self,
97 report_schedule_id: &str,
98 ) -> Result<models::reports_2021_06_30::ReportSchedule> {
99 let configuration = self.create_configuration().await?;
100 let _ = self
101 .limiter()
102 .wait(
103 "/reports/v2021-06-30/schedules/{reportScheduleId}",
104 0.016,
105 15,
106 )
107 .await?;
108 let res =
109 crate::apis::reports_api::get_report_schedule(&configuration, report_schedule_id).await;
110 Ok(res?)
111 }
112
113 pub async fn get_report_schedules(
114 &self,
115 report_types: Vec<String>,
116 ) -> Result<models::reports_2021_06_30::ReportScheduleList> {
117 let configuration = self.create_configuration().await?;
118 let _ = self
119 .limiter()
120 .wait("/reports/v2021-06-30/schedules", 0.016, 15)
121 .await?;
122 let res =
123 crate::apis::reports_api::get_report_schedules(&configuration, report_types).await;
124 Ok(res?)
125 }
126
127 pub async fn get_reports(
128 &self,
129 report_types: Option<Vec<String>>,
130 processing_statuses: Option<Vec<String>>,
131 marketplace_ids: Option<Vec<String>>,
132 page_size: Option<i32>,
133 created_since: Option<String>,
134 created_until: Option<String>,
135 next_token: Option<&str>,
136 ) -> Result<models::reports_2021_06_30::GetReportsResponse> {
137 let configuration = self.create_configuration().await?;
138 let _ = self
139 .limiter()
140 .wait("/reports/v2021-06-30/reports", 0.016, 15)
141 .await?;
142 let res = crate::apis::reports_api::get_reports(
143 &configuration,
144 report_types,
145 processing_statuses,
146 marketplace_ids,
147 page_size,
148 created_since,
149 created_until,
150 next_token,
151 )
152 .await;
153 Ok(res?)
154 }
155
156 pub async fn fetch_report(
158 &self,
159 report_type: &str,
160 marketplace_ids: Vec<String>,
161 max_wait_minutes: Option<u32>,
162 progress_callback: Option<impl Fn(u32, ProcessingStatus) + Send + 'static>,
163 ) -> Result<String> {
164 let max_wait_minutes = max_wait_minutes.unwrap_or(30);
165 let check_interval_seconds = 10;
166 let max_attempts = (max_wait_minutes * 60 / check_interval_seconds) as u32;
167
168 let create_report_spec = CreateReportSpecification {
169 report_type: report_type.to_string(),
170 marketplace_ids,
171 report_options: None,
172 data_start_time: None,
173 data_end_time: None,
174 };
175
176 let create_response = self.create_report(create_report_spec).await?;
177 let report_id = &create_response.report_id;
178
179 for attempt_count in 1..=max_attempts {
180 let report = self.get_report(report_id).await?;
181
182 if let Some(callback) = &progress_callback {
183 callback(attempt_count, report.processing_status.clone());
184 }
185
186 match report.processing_status {
187 ProcessingStatus::Done => {
188 log::debug!("Report generation completed!");
189
190 if let Some(document_id) = report.report_document_id {
191 let document = self.get_report_document(&document_id).await?;
192 log::info!("Report document ID: {}", document.report_document_id);
193
194 let report_content =
195 if let Some(compression) = &document.compression_algorithm {
196 log::info!("Report uses compression algorithm: {:?}", compression);
197 self.download(&document.url).await?
199 } else {
200 self.download(&document.url).await?
201 };
202
203 log::debug!("Report content downloaded successfully.");
204 return Ok(report_content);
205 } else {
206 return Err(anyhow::anyhow!(
207 "Report generation completed but no document ID found"
208 ));
209 }
210 }
211 ProcessingStatus::Cancelled => {
212 return Err(anyhow::anyhow!("Report generation was cancelled"));
213 }
214 ProcessingStatus::Fatal => {
215 return Err(anyhow::anyhow!("Report generation failed"));
216 }
217 ProcessingStatus::InProgress => {
218 log::debug!("Report is being generated, waiting 30 seconds before retrying...");
219 }
220 ProcessingStatus::InQueue => {
221 log::debug!("Report is in queue waiting to be processed, waiting 30 seconds before retrying...");
222 }
223 }
224
225 if attempt_count < max_attempts {
226 log::debug!(
227 "Waiting {} seconds before next check...",
228 check_interval_seconds
229 );
230 sleep(Duration::from_secs(check_interval_seconds as u64)).await;
231 }
232 }
233
234 Err(anyhow::anyhow!(
235 "Report generation timed out after {} minutes ({} attempts)",
236 max_wait_minutes,
237 max_attempts
238 ))
239 }
240}