iop_client/
product_category.rs

1use crate::constants::{methods, urls};
2
3use serde::{Deserialize, Deserializer, Serialize};
4use std::collections::HashMap;
5
6use log::info;
7
8use crate::IopClient;
9
10#[derive(Serialize, Deserialize, Debug)]
11pub struct NewCategoryResponse {
12    pub alibaba_icbu_category_get_new_response: NewCategoryGroup,
13    pub request_id: Option<String>,
14    pub _trace_id_: Option<String>,
15}
16
17#[derive(Serialize, Deserialize, Debug)]
18pub struct NewCategoryGroup {
19    pub category: NewCategory,
20}
21
22#[derive(Serialize, Deserialize, Debug)]
23pub struct NewCategory {
24    pub leaf_category: bool,
25    pub cn_name: Option<String>,
26    pub category_id: i32,
27    pub level: i32,
28    pub name: String,
29
30    #[serde(default, deserialize_with = "empty_object_as_none")]
31    pub child_ids: Option<NewCategoryChildId>,
32
33    #[serde(default, deserialize_with = "empty_object_as_none")]
34    pub parent_ids: Option<NewCategoryChildId>,
35}
36
37#[derive(Serialize, Deserialize, Debug)]
38pub struct NewCategoryChildId {
39    pub number: Vec<String>,
40}
41
42#[derive(Serialize, Deserialize, Debug)]
43struct CategoryAttributeGetResponse {
44    alibaba_icbu_category_attribute_get_response: CategoryAttributeGroup,
45}
46
47#[derive(Serialize, Deserialize, Debug)]
48pub struct CategoryAttributeGroup {
49    pub attributes: CategoryAttributes,
50    request_id: Option<String>,
51    _trace_id_: Option<String>,
52}
53
54#[derive(Serialize, Deserialize, Debug)]
55pub struct CategoryAttributes {
56    pub attribute: Vec<CategoryAttribute>,
57}
58
59#[derive(Serialize, Deserialize, Debug)]
60pub struct CategoryAttribute {
61    pub sku_attribute: bool,
62    pub show_type: String,
63    pub customize_image: bool,
64    pub car_model: bool,
65    pub value_type: String,
66    pub customize_value: bool,
67
68    #[serde(deserialize_with = "empty_object_as_none")]
69    pub attribute_values: Option<AttributeValues>,
70    pub input_type: String,
71    pub en_name: String,
72    pub required: bool,
73    pub attr_id: i32,
74}
75
76#[derive(Serialize, Deserialize, Debug)]
77pub struct AttributeValues {
78    pub attribute_value: Vec<AttributeValue>,
79}
80
81#[derive(Serialize, Deserialize, Debug)]
82pub struct AttributeValue {
83    pub sku_value: bool,
84    pub attr_value_id: i32,
85    pub en_name: String,
86}
87
88// [skip deserialize empty json object {}](https://github.com/serde-rs/serde/issues/2362)
89fn empty_object_as_none<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
90where
91    D: Deserializer<'de>,
92    T: Deserialize<'de>,
93{
94    #[derive(Deserialize)]
95    #[serde(
96        untagged,
97        deny_unknown_fields,
98        expecting = "object, empty object or null"
99    )]
100    enum Helper<T> {
101        Empty {},
102        Data(T),
103        Null,
104    }
105    match Helper::deserialize(deserializer) {
106        Ok(Helper::Data(data)) => Ok(Some(data)),
107        Ok(_) => Ok(None),
108        Err(e) => Err(e),
109    }
110}
111
112impl IopClient {
113    /// (新)ICBU类目树获取接口
114    ///
115    /// [官方文档](https://open.alibaba.com/doc/api.htm#/api?cid=20966&path=alibaba.icbu.category.get.new&methodType=GET/POST)
116    ///
117    ///  Get the specified category by cat_id.
118    ///
119    /// # Arguments
120    ///
121    /// * `cat_id` - The category ID.
122    ///
123    /// # Returns
124    ///
125    /// A `Result` containing the `NewCategory` model if successful, or an error if the process fails.
126    ///
127    /// The function first retrieves an access token, constructs a map of parameters required
128    /// for the API call, and includes the category ID and language. A signature is then generated
129    /// for the request, and the request is sent to the API endpoint. Upon successful completion,
130    /// the category information is returned.
131    pub async fn list_product_categories(
132        &self,
133        cat_id: i32,
134    ) -> Result<NewCategory, Box<dyn std::error::Error>> {
135        let mut map = HashMap::new();
136        map.insert("cat_id".to_string(), format!("{}", cat_id));
137        map.insert(
138            "method".to_string(),
139            methods::ALIBABA_ICBU_CATEGORY_GET_NEW.to_string(),
140        );
141
142        let params = self.build_request_params(map).await;
143
144        let hash = self.generate_sign(None, params.clone());
145        let url = self.generate_url(urls::BASE_SYNC_URL.to_string(), params.clone(), hash);
146        info!("--------list_product_categories-------- url: {:#?}", url);
147
148        let response = self.client.get(&url).send().await?;
149        let result = response.json::<NewCategoryResponse>().await?;
150
151        Ok(result.alibaba_icbu_category_get_new_response.category)
152    }
153
154    /// 类目属性获取
155    ///
156    /// [官方文档](https://open.alibaba.com/doc/api.htm?spm=a2o9m.11193494.0.0.22023a3a2ZhCGD#/api?cid=20966&path=alibaba.icbu.category.attribute.get&methodType=GET/POST)
157    ///
158    /// Retrieve the category attributes for the specified category by cat_id.
159    ///
160    /// # Arguments
161    ///
162    /// * `cat_id` - The category ID.
163    ///
164    /// # Returns
165    ///
166    /// A `Result` containing the `CategoryAttributeGroup` model if successful, or an error if the process fails.
167    ///
168    /// The function first retrieves an access token, constructs a map of parameters required
169    /// for the API call, and includes the category ID and language. A signature is then generated
170    /// for the request, and the request is sent to the API endpoint. Upon successful completion,
171    /// the category attributes are returned.
172    pub async fn get_category_attributes(
173        self,
174        cat_id: i32,
175    ) -> Result<CategoryAttributeGroup, Box<dyn std::error::Error>> {
176        let mut map = HashMap::new();
177        map.insert("cat_id".to_string(), format!("{}", cat_id));
178        map.insert(
179            "method".to_string(),
180            methods::ALIBABA_ICBU_CATEGORY_ATTRIBUTE_GET.to_string(),
181        );
182
183        let params = self.build_request_params(map).await;
184
185        let hash = self.generate_sign(None, params.clone());
186        let url = self.generate_url(urls::BASE_SYNC_URL.to_string(), params.clone(), hash);
187        info!("--------get_category_attributes-------- url: {:#?}", url);
188
189        let response = self.client.get(&url).send().await?;
190        let result = response.json::<CategoryAttributeGetResponse>().await?;
191
192        Ok(result.alibaba_icbu_category_attribute_get_response)
193    }
194}