use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct JdConvertResponse {
#[serde(default)]
pub status: i32,
#[serde(default)]
pub content: Option<Vec<JdConvertResult>>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdConvertResult {
#[serde(default)]
pub code: Option<String>,
#[serde(default)]
pub type_one_id: Option<String>,
#[serde(default)]
pub tao_id: Option<String>,
#[serde(default)]
pub title: Option<String>,
#[serde(default)]
pub jianjie: Option<String>,
#[serde(default)]
pub pict_url: Option<String>,
#[serde(default)]
pub user_type: Option<String>,
#[serde(default)]
pub seller_id: Option<String>,
#[serde(default)]
pub shop_dsr: Option<String>,
#[serde(default)]
pub volume: Option<String>,
#[serde(default)]
pub size: Option<String>,
#[serde(default)]
pub quanhou_jiage: Option<String>,
#[serde(default)]
pub tkrate3: Option<String>,
#[serde(default)]
pub yongjin_type: Option<String>,
#[serde(default)]
pub coupon_id: Option<String>,
#[serde(default)]
pub coupon_start_time: Option<String>,
#[serde(default)]
pub coupon_end_time: Option<String>,
#[serde(default)]
pub coupon_info_money: Option<String>,
#[serde(default)]
pub coupon_total_count: Option<String>,
#[serde(default)]
pub coupon_remain_count: Option<String>,
#[serde(default)]
pub coupon_info: Option<String>,
#[serde(default)]
pub juhuasuan: Option<String>,
#[serde(default)]
pub taoqianggou: Option<String>,
#[serde(default)]
pub haitao: Option<String>,
#[serde(default)]
pub jiyoujia: Option<String>,
#[serde(default)]
pub jinpaimaijia: Option<String>,
#[serde(default)]
pub pinpai: Option<String>,
#[serde(default)]
pub pinpai_name: Option<String>,
#[serde(default)]
pub yunfeixian: Option<String>,
#[serde(default)]
pub nick: Option<String>,
#[serde(default)]
pub small_images: Option<String>,
#[serde(default)]
pub white_image: Option<String>,
#[serde(default)]
pub tao_title: Option<String>,
#[serde(default)]
pub provcity: Option<String>,
#[serde(default)]
pub shop_title: Option<String>,
#[serde(default)]
pub zhibo_url: Option<String>,
#[serde(default, rename = "sellCount")]
pub sell_count: Option<String>,
#[serde(default, rename = "commentCount")]
pub comment_count: Option<String>,
#[serde(default)]
pub favcount: Option<String>,
#[serde(default)]
pub score1: Option<String>,
#[serde(default)]
pub score2: Option<String>,
#[serde(default)]
pub score3: Option<String>,
#[serde(default, rename = "creditLevel")]
pub credit_level: Option<String>,
#[serde(default, rename = "shopIcon")]
pub shop_icon: Option<String>,
#[serde(default, rename = "pcDescContent")]
pub pc_desc_content: Option<String>,
#[serde(default)]
pub item_url: Option<String>,
#[serde(default)]
pub category_id: Option<String>,
#[serde(default)]
pub category_name: Option<String>,
#[serde(default)]
pub level_one_category_id: Option<String>,
#[serde(default)]
pub level_one_category_name: Option<String>,
#[serde(default)]
pub tkfee3: Option<String>,
#[serde(default)]
pub tag: Option<String>,
#[serde(default)]
pub date_time: Option<String>,
#[serde(default)]
pub coupon_click_url: Option<String>,
#[serde(default)]
pub shorturl: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JingfenGoodsResponse {
#[serde(default, rename = "jd_union_open_goods_jingfen_query_response")]
pub response: Option<JingfenQueryResponse>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JingfenQueryResponse {
#[serde(default, rename = "queryResult")]
pub query_result: Option<JingfenQueryResult>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JingfenQueryResult {
#[serde(default)]
pub code: Option<String>,
#[serde(default)]
pub message: Option<String>,
#[serde(default)]
pub data: Option<Vec<JingfenGoodsItem>>,
#[serde(default, rename = "totalCount")]
pub total_count: Option<i64>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JingfenGoodsItem {
#[serde(default, rename = "skuId")]
pub sku_id: Option<i64>,
#[serde(default, rename = "skuName")]
pub sku_name: Option<String>,
#[serde(default, rename = "materialUrl")]
pub material_url: Option<String>,
#[serde(default, rename = "imageInfo")]
pub image_info: Option<JdImageInfo>,
#[serde(default, rename = "priceInfo")]
pub price_info: Option<JdPriceInfo>,
#[serde(default, rename = "commissionInfo")]
pub commission_info: Option<JdCommissionInfo>,
#[serde(default, rename = "couponInfo")]
pub coupon_info: Option<JdCouponInfo>,
#[serde(default, rename = "shopInfo")]
pub shop_info: Option<JdShopInfo>,
#[serde(default, rename = "categoryInfo")]
pub category_info: Option<JdCategoryInfo>,
#[serde(default, rename = "pinGouInfo")]
pub pingou_info: Option<JdPingouInfo>,
#[serde(default, rename = "inOrderCount30Days")]
pub in_order_count_30_days: Option<i64>,
#[serde(default, rename = "inOrderComm30Days")]
pub in_order_comm_30_days: Option<f64>,
#[serde(default)]
pub comments: Option<i64>,
#[serde(default, rename = "goodCommentsShare")]
pub good_comments_share: Option<f64>,
#[serde(default, rename = "brandCode")]
pub brand_code: Option<String>,
#[serde(default, rename = "brandName")]
pub brand_name: Option<String>,
#[serde(default)]
pub owner: Option<String>,
#[serde(default, rename = "isJdSale")]
pub is_jd_sale: Option<i32>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdImageInfo {
#[serde(default, rename = "imageList")]
pub image_list: Option<Vec<JdImage>>,
#[serde(default, rename = "whiteImage")]
pub white_image: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdImage {
#[serde(default)]
pub url: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdPriceInfo {
#[serde(default)]
pub price: Option<f64>,
#[serde(default, rename = "lowestPrice")]
pub lowest_price: Option<f64>,
#[serde(default, rename = "lowestCouponPrice")]
pub lowest_coupon_price: Option<f64>,
#[serde(default, rename = "historyPriceDay")]
pub history_price_day: Option<i32>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdCommissionInfo {
#[serde(default)]
pub commission: Option<f64>,
#[serde(default, rename = "commissionShare")]
pub commission_share: Option<f64>,
#[serde(default, rename = "couponCommission")]
pub coupon_commission: Option<f64>,
#[serde(default, rename = "plusCommissionShare")]
pub plus_commission_share: Option<f64>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdCouponInfo {
#[serde(default, rename = "couponList")]
pub coupon_list: Option<Vec<JdCoupon>>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdCoupon {
#[serde(default, rename = "bindType")]
pub bind_type: Option<i32>,
#[serde(default)]
pub discount: Option<f64>,
#[serde(default)]
pub link: Option<String>,
#[serde(default, rename = "platformType")]
pub platform_type: Option<i32>,
#[serde(default)]
pub quota: Option<f64>,
#[serde(default, rename = "getStartTime")]
pub get_start_time: Option<i64>,
#[serde(default, rename = "getEndTime")]
pub get_end_time: Option<i64>,
#[serde(default, rename = "isBest")]
pub is_best: Option<i32>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdShopInfo {
#[serde(default, rename = "shopId")]
pub shop_id: Option<i64>,
#[serde(default, rename = "shopName")]
pub shop_name: Option<String>,
#[serde(default, rename = "shopLevel")]
pub shop_level: Option<f64>,
#[serde(default, rename = "shopLabel")]
pub shop_label: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdCategoryInfo {
#[serde(default)]
pub cid1: Option<i64>,
#[serde(default, rename = "cid1Name")]
pub cid1_name: Option<String>,
#[serde(default)]
pub cid2: Option<i64>,
#[serde(default, rename = "cid2Name")]
pub cid2_name: Option<String>,
#[serde(default)]
pub cid3: Option<i64>,
#[serde(default, rename = "cid3Name")]
pub cid3_name: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdPingouInfo {
#[serde(default, rename = "pingouPrice")]
pub pingou_price: Option<f64>,
#[serde(default, rename = "pingouTmCount")]
pub pingou_tm_count: Option<i64>,
#[serde(default, rename = "pingouUrl")]
pub pingou_url: Option<String>,
#[serde(default, rename = "pingouStartTime")]
pub pingou_start_time: Option<i64>,
#[serde(default, rename = "pingouEndTime")]
pub pingou_end_time: Option<i64>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdOrderResponse {
#[serde(default)]
pub status: i32,
#[serde(default)]
pub data: Option<JdOrderData>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdOrderData {
#[serde(default)]
pub has_more: Option<bool>,
#[serde(default)]
pub data: Option<Vec<JdOrderInfo>>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdOrderInfo {
#[serde(default, rename = "orderId")]
pub order_id: Option<i64>,
#[serde(default, rename = "parentId")]
pub parent_id: Option<i64>,
#[serde(default, rename = "orderTime")]
pub order_time: Option<String>,
#[serde(default, rename = "finishTime")]
pub finish_time: Option<String>,
#[serde(default, rename = "modifyTime")]
pub modify_time: Option<String>,
#[serde(default, rename = "validCode")]
pub valid_code: Option<i32>,
#[serde(default, rename = "skuId")]
pub sku_id: Option<i64>,
#[serde(default, rename = "skuName")]
pub sku_name: Option<String>,
#[serde(default, rename = "skuNum")]
pub sku_num: Option<i32>,
#[serde(default)]
pub price: Option<f64>,
#[serde(default, rename = "actualCosPrice")]
pub actual_cos_price: Option<f64>,
#[serde(default, rename = "actualFee")]
pub actual_fee: Option<f64>,
#[serde(default, rename = "estimateCosPrice")]
pub estimate_cos_price: Option<f64>,
#[serde(default, rename = "estimateFee")]
pub estimate_fee: Option<f64>,
#[serde(default, rename = "commissionRate")]
pub commission_rate: Option<f64>,
#[serde(default, rename = "subUnionId")]
pub sub_union_id: Option<String>,
#[serde(default, rename = "positionId")]
pub position_id: Option<i64>,
#[serde(default, rename = "siteId")]
pub site_id: Option<i64>,
#[serde(default, rename = "unionId")]
pub union_id: Option<i64>,
#[serde(default)]
pub cid1: Option<i64>,
#[serde(default)]
pub cid2: Option<i64>,
#[serde(default)]
pub cid3: Option<i64>,
#[serde(default)]
pub plus: Option<i32>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdGoodsDetailResponse {
#[serde(default)]
pub status: i32,
#[serde(default)]
pub data: Option<Vec<JingfenGoodsItem>>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdHotGoodsResponse {
#[serde(default)]
pub status: i32,
#[serde(default)]
pub content: Option<Vec<JdHotGoodsItem>>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct JdHotGoodsItem {
#[serde(default)]
pub goods_id: Option<i64>,
#[serde(default)]
pub state: Option<i32>,
#[serde(default, rename = "J_state")]
pub j_state: Option<i32>,
#[serde(default)]
pub short_name: Option<String>,
#[serde(default)]
pub goods_type: Option<i32>,
#[serde(default)]
pub goods_img: Option<String>,
#[serde(default)]
pub goods_price: Option<f64>,
#[serde(default)]
pub discount_price_after: Option<f64>,
#[serde(default)]
pub goods_recommend: Option<String>,
#[serde(default)]
pub commissionshare: Option<f64>,
#[serde(default)]
pub goods_link: Option<String>,
#[serde(default)]
pub discount_price: Option<f64>,
#[serde(default)]
pub discount_link: Option<String>,
#[serde(default)]
pub today_num: Option<i32>,
#[serde(default)]
pub quota: Option<f64>,
#[serde(default)]
pub discount_start: Option<String>,
#[serde(default)]
pub discount_end: Option<String>,
#[serde(default)]
pub shop_id: Option<i64>,
#[serde(default)]
pub shop_name: Option<String>,
#[serde(default, rename = "inOrderCount30Days")]
pub in_order_count_30_days: Option<i64>,
#[serde(default, rename = "imageList")]
pub image_list: Option<String>,
#[serde(default)]
pub img_info: Option<String>,
#[serde(default)]
pub update_time: Option<String>,
#[serde(default)]
pub brand_id: Option<String>,
#[serde(default, rename = "brandCode")]
pub brand_code: Option<String>,
#[serde(default, rename = "brandName")]
pub brand_name: Option<String>,
#[serde(default)]
pub owner: Option<String>,
#[serde(default)]
pub cid1: Option<i64>,
#[serde(default, rename = "cid1Name")]
pub cid1_name: Option<String>,
#[serde(default)]
pub cid2: Option<i64>,
#[serde(default, rename = "cid2Name")]
pub cid2_name: Option<String>,
#[serde(default)]
pub cid3: Option<i64>,
#[serde(default, rename = "cid3Name")]
pub cid3_name: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_jd_convert_response_deserialize() {
let json = r#"{
"status": 200,
"content": [{
"tao_id": "10025768652616",
"title": "测试商品",
"quanhou_jiage": "99.00",
"coupon_click_url": "https://union-click.jd.com/xxx",
"shorturl": "https://u.jd.com/xxx"
}]
}"#;
let response: JdConvertResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.status, 200);
assert!(response.content.is_some());
let content = response.content.unwrap();
assert_eq!(content.len(), 1);
assert_eq!(content[0].tao_id, Some("10025768652616".to_string()));
assert_eq!(content[0].title, Some("测试商品".to_string()));
}
#[test]
fn test_jingfen_goods_response_deserialize() {
let json = r#"{
"jd_union_open_goods_jingfen_query_response": {
"queryResult": {
"code": "200",
"message": "success",
"data": [{
"skuId": 10025768652616,
"skuName": "测试商品",
"inOrderCount30Days": 100
}],
"totalCount": 1
}
}
}"#;
let response: JingfenGoodsResponse = serde_json::from_str(json).unwrap();
assert!(response.response.is_some());
let query_response = response.response.unwrap();
assert!(query_response.query_result.is_some());
let result = query_response.query_result.unwrap();
assert_eq!(result.code, Some("200".to_string()));
assert!(result.data.is_some());
let data = result.data.unwrap();
assert_eq!(data.len(), 1);
assert_eq!(data[0].sku_id, Some(10025768652616));
}
#[test]
fn test_jd_order_response_deserialize() {
let json = r#"{
"status": 200,
"data": {
"has_more": true,
"data": [{
"orderId": 123456789,
"skuId": 10025768652616,
"skuName": "测试商品",
"validCode": 2,
"price": 99.00,
"actualFee": 9.90
}]
}
}"#;
let response: JdOrderResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.status, 200);
assert!(response.data.is_some());
let data = response.data.unwrap();
assert_eq!(data.has_more, Some(true));
assert!(data.data.is_some());
let orders = data.data.unwrap();
assert_eq!(orders.len(), 1);
assert_eq!(orders[0].order_id, Some(123456789));
}
#[test]
fn test_jd_hot_goods_response_deserialize() {
let json = r#"{
"status": 200,
"content": [{
"goods_id": 10025768652616,
"short_name": "测试商品",
"goods_price": 99.00,
"discount_price_after": 79.00,
"commissionshare": 20.0,
"shop_name": "测试店铺"
}]
}"#;
let response: JdHotGoodsResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.status, 200);
assert!(response.content.is_some());
let content = response.content.unwrap();
assert_eq!(content.len(), 1);
assert_eq!(content[0].goods_id, Some(10025768652616));
assert_eq!(content[0].short_name, Some("测试商品".to_string()));
}
#[test]
fn test_response_with_missing_fields() {
let json = r#"{"status": 200}"#;
let response: JdConvertResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.status, 200);
assert!(response.content.is_none());
}
#[test]
fn test_jd_price_info_deserialize() {
let json = r#"{
"price": 99.00,
"lowestPrice": 89.00,
"lowestCouponPrice": 79.00
}"#;
let price_info: JdPriceInfo = serde_json::from_str(json).unwrap();
assert_eq!(price_info.price, Some(99.00));
assert_eq!(price_info.lowest_price, Some(89.00));
assert_eq!(price_info.lowest_coupon_price, Some(79.00));
}
#[test]
fn test_jd_commission_info_deserialize() {
let json = r#"{
"commission": 9.90,
"commissionShare": 10.0
}"#;
let commission_info: JdCommissionInfo = serde_json::from_str(json).unwrap();
assert_eq!(commission_info.commission, Some(9.90));
assert_eq!(commission_info.commission_share, Some(10.0));
}
}