amazon_sp_api/models/
listings.rs

1use reqwest::{Method, Response};
2use serde_json::{json, Value};
3use crate::general::{Client, CountryMarketplace};
4use strum_macros;
5use crate::error_handling::Errors;
6
7pub struct Listings;
8#[allow(non_camel_case_types)]
9#[derive(strum_macros::Display)]
10pub enum IncludedData {
11    summaries,
12    issues,
13    attributes,
14    offers,
15    fulfillmentAvailability,
16    procurement,
17    relationships,
18    productTypes,
19}
20impl Listings {
21    pub async fn get_listings_item(
22        client: &mut Client,
23        seller_id: &str,
24        sku: &str,
25        country_marketplace: CountryMarketplace,
26        included_data: Vec<IncludedData>,
27
28    ) -> Result<Response, Errors> {
29        let url = format!("/listings/2021-08-01/items/{}/{}", seller_id, sku);
30        let parameters = vec![("marketplaceIds", country_marketplace.details().0.to_string()), ("includedData", included_data.iter().map(|b| b.to_string()).collect::<Vec<String>>().join(","))];
31
32        client.make_request(&url, Method::GET, Some(parameters)).await
33    }
34    pub async fn put_listings_item() {}
35
36    pub async fn patch_listings_item(
37        client: &mut Client,
38        seller_id: &str,
39        sku: &str,
40        country_marketplace: CountryMarketplace,
41        validation_preview: bool,
42        body: &str
43    ) -> Result<Response, Errors> {
44        let url = format!("/listings/2021-08-01/items/{}/{}", seller_id, sku);
45        let mut parameters = vec![("marketplaceIds", country_marketplace.details().0)];
46        if validation_preview {
47            parameters.push(("mode", "VALIDATION_PREVIEW"))
48        }
49
50        client.make_request_w_body(&url, Method::PATCH, Some(parameters), body.parse().unwrap()).await
51
52    }
53    ///This is a simple way to change prices
54    pub async fn wrapped_patch_listings_item(
55        client: &mut Client,
56        seller_id: &str,
57        sku: &str,
58        country_marketplace: CountryMarketplace,
59        validation_preview: bool,
60        new_price: f64
61
62    ) -> Result<Response, Errors> {
63        let item_data: Value = Self::get_listings_item(client, seller_id, sku ,CountryMarketplace::SaudiArabia, vec![IncludedData::productTypes, IncludedData::attributes]).await?.json().await?;
64        let item_type = &item_data["productTypes"][0]["productType"];
65        let mut offers = item_data["attributes"]["purchasable_offer"].clone();
66
67        offers[0]["our_price"][0]["schedule"][0]["value_with_tax"] = Value::from(new_price);
68        let final_body = json!({
69            "productType": item_type,
70            "patches": [{
71                    "op":"replace",
72                  "path":"/attributes/purchasable_offer",
73                  "value":offers
74            }]
75        });
76        Self::patch_listings_item(client, seller_id, sku, country_marketplace, validation_preview, &*final_body.to_string()).await
77
78    }
79        /// Search for and return a list of selling partner listings items
80        ///
81        /// Rate (requests per second): 5
82        /// Burst: 5
83        ///
84        /// # Parameters
85        /// - client: Reference to the HTTP client
86        /// - seller_id: Required selling partner identifier
87        /// - marketplace: The marketplace to search in (max count: 1)
88        /// - issue_locale: Optional locale for issue localization (e.g., "en_US", "fr_CA")
89        /// - included_data: Optional data sets to include (default: summaries)
90        /// - identifiers: Optional list of product identifiers (max: 20)
91        /// - identifiers_type: Required when identifiers are provided
92        /// - variation_parent_sku: Optional SKU to filter variation children
93        /// - package_hierarchy_sku: Optional SKU to filter package hierarchy
94        /// - created_after: Optional filter for items created after date
95        /// - created_before: Optional filter for items created before date
96        /// - last_updated_after: Optional filter for items updated after date
97        /// - last_updated_before: Optional filter for items updated before date
98        /// - with_issue_severity: Optional filter by issue severity levels
99        /// - with_status: Optional filter by status
100        /// - without_status: Optional filter to exclude status
101        /// - sort_by: Optional attribute to sort by (default: lastUpdatedDate)
102        /// - sort_order: Optional sort direction (default: DESC)
103        /// - page_size: Optional results per page (max: 20, default: 10)
104        /// - page_token: Optional pagination token
105        pub async fn search_listings_items(
106            client: &mut Client,
107            seller_id: String,
108            marketplace: CountryMarketplace,
109            issue_locale: Option<String>,
110            included_data: Option<Vec<String>>,
111            identifiers: Option<Vec<String>>,
112            identifiers_type: Option<String>,
113            variation_parent_sku: Option<String>,
114            package_hierarchy_sku: Option<String>,
115            created_after: Option<String>,
116            created_before: Option<String>,
117            last_updated_after: Option<String>,
118            last_updated_before: Option<String>,
119            with_issue_severity: Option<Vec<String>>,
120            with_status: Option<Vec<String>>,
121            without_status: Option<Vec<String>>,
122            sort_by: Option<String>,
123            sort_order: Option<String>,
124            page_size: Option<u32>,
125            page_token: Option<String>,
126        ) -> Result<Response, Errors> {
127            let uri = format!("/listings/2021-08-01/items/{}", seller_id);
128
129            // Validate mutually exclusive parameters
130            if identifiers.is_some() && (variation_parent_sku.is_some() || package_hierarchy_sku.is_some()) {
131                return Err(Errors::CustomError(
132                    "Cannot use identifiers with variationParentSku or packageHierarchySku".to_string()
133                ));
134            }
135
136            if variation_parent_sku.is_some() && package_hierarchy_sku.is_some() {
137                return Err(Errors::CustomError(
138                    "Cannot use both variationParentSku and packageHierarchySku".to_string()
139                ));
140            }
141
142            // Validate array sizes
143            if let Some(ids) = &identifiers {
144                if ids.len() > 20 {
145                    return Err(Errors::CustomError("Maximum 20 identifiers allowed".to_string()));
146                }
147            }
148
149            // Validate page size
150            if let Some(size) = page_size {
151                if size > 20 {
152                    return Err(Errors::CustomError("Maximum page size is 20".to_string()));
153                }
154            }
155
156            let mut params: Vec<(String, String)> = Vec::new();
157
158            // Add required marketplace ID
159            params.push(("marketplaceIds".to_string(), marketplace.details().0.to_string()));
160            params.push(("sellerId".to_string(), seller_id));
161
162            // Add optional parameters
163            if let Some(locale) = issue_locale {
164                params.push(("issueLocale".to_string(), locale));
165            }
166            if let Some(data) = included_data {
167                params.push(("includedData".to_string(), data.join(",")));
168            }
169            if let Some(ids) = identifiers {
170                params.push(("identifiers".to_string(), ids.join(",")));
171            }
172            if let Some(id_type) = identifiers_type {
173                params.push(("identifiersType".to_string(), format!("{:?}", id_type)));
174            }
175            if let Some(sku) = variation_parent_sku {
176                params.push(("variationParentSku".to_string(), sku));
177            }
178            if let Some(sku) = package_hierarchy_sku {
179                params.push(("packageHierarchySku".to_string(), sku));
180            }
181            if let Some(date) = created_after {
182                params.push(("createdAfter".to_string(), date));
183            }
184            if let Some(date) = created_before {
185                params.push(("createdBefore".to_string(), date));
186            }
187            if let Some(date) = last_updated_after {
188                params.push(("lastUpdatedAfter".to_string(), date));
189            }
190            if let Some(date) = last_updated_before {
191                params.push(("lastUpdatedBefore".to_string(), date));
192            }
193            if let Some(severities) = with_issue_severity {
194                params.push(("withIssueSeverity".to_string(),
195                             severities.iter().map(|s| format!("{:?}", s)).collect::<Vec<_>>().join(",")));
196            }
197            if let Some(statuses) = with_status {
198                params.push(("withStatus".to_string(),
199                             statuses.iter().map(|s| format!("{:?}", s)).collect::<Vec<_>>().join(",")));
200            }
201            if let Some(statuses) = without_status {
202                params.push(("withoutStatus".to_string(),
203                             statuses.iter().map(|s| format!("{:?}", s)).collect::<Vec<_>>().join(",")));
204            }
205            if let Some(sort) = sort_by {
206                params.push(("sortBy".to_string(), format!("{:?}", sort)));
207            }
208            if let Some(order) = sort_order {
209                params.push(("sortOrder".to_string(), format!("{:?}", order)));
210            }
211            if let Some(size) = page_size {
212                params.push(("pageSize".to_string(), size.to_string()));
213            }
214            if let Some(token) = page_token {
215                params.push(("pageToken".to_string(), token));
216            }
217            client.make_request(&uri, Method::GET, Some(params)).await
218        }
219}