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