1use serde::Deserialize;
6
7#[derive(Debug, Clone, Deserialize)]
11pub struct JdConvertResponse {
12 #[serde(default)]
14 pub status: i32,
15 #[serde(default)]
17 pub content: Option<Vec<JdConvertResult>>,
18}
19
20#[derive(Debug, Clone, Deserialize)]
22pub struct JdConvertResult {
23 #[serde(default)]
25 pub code: Option<String>,
26 #[serde(default)]
28 pub type_one_id: Option<String>,
29 #[serde(default)]
31 pub tao_id: Option<String>,
32 #[serde(default)]
34 pub title: Option<String>,
35 #[serde(default)]
37 pub jianjie: Option<String>,
38 #[serde(default)]
40 pub pict_url: Option<String>,
41 #[serde(default)]
43 pub user_type: Option<String>,
44 #[serde(default)]
46 pub seller_id: Option<String>,
47 #[serde(default)]
49 pub shop_dsr: Option<String>,
50 #[serde(default)]
52 pub volume: Option<String>,
53 #[serde(default)]
55 pub size: Option<String>,
56 #[serde(default)]
58 pub quanhou_jiage: Option<String>,
59 #[serde(default)]
61 pub tkrate3: Option<String>,
62 #[serde(default)]
64 pub yongjin_type: Option<String>,
65 #[serde(default)]
67 pub coupon_id: Option<String>,
68 #[serde(default)]
70 pub coupon_start_time: Option<String>,
71 #[serde(default)]
73 pub coupon_end_time: Option<String>,
74 #[serde(default)]
76 pub coupon_info_money: Option<String>,
77 #[serde(default)]
79 pub coupon_total_count: Option<String>,
80 #[serde(default)]
82 pub coupon_remain_count: Option<String>,
83 #[serde(default)]
85 pub coupon_info: Option<String>,
86 #[serde(default)]
88 pub juhuasuan: Option<String>,
89 #[serde(default)]
91 pub taoqianggou: Option<String>,
92 #[serde(default)]
94 pub haitao: Option<String>,
95 #[serde(default)]
97 pub jiyoujia: Option<String>,
98 #[serde(default)]
100 pub jinpaimaijia: Option<String>,
101 #[serde(default)]
103 pub pinpai: Option<String>,
104 #[serde(default)]
106 pub pinpai_name: Option<String>,
107 #[serde(default)]
109 pub yunfeixian: Option<String>,
110 #[serde(default)]
112 pub nick: Option<String>,
113 #[serde(default)]
115 pub small_images: Option<String>,
116 #[serde(default)]
118 pub white_image: Option<String>,
119 #[serde(default)]
121 pub tao_title: Option<String>,
122 #[serde(default)]
124 pub provcity: Option<String>,
125 #[serde(default)]
127 pub shop_title: Option<String>,
128 #[serde(default)]
130 pub zhibo_url: Option<String>,
131 #[serde(default, rename = "sellCount")]
133 pub sell_count: Option<String>,
134 #[serde(default, rename = "commentCount")]
136 pub comment_count: Option<String>,
137 #[serde(default)]
139 pub favcount: Option<String>,
140 #[serde(default)]
142 pub score1: Option<String>,
143 #[serde(default)]
145 pub score2: Option<String>,
146 #[serde(default)]
148 pub score3: Option<String>,
149 #[serde(default, rename = "creditLevel")]
151 pub credit_level: Option<String>,
152 #[serde(default, rename = "shopIcon")]
154 pub shop_icon: Option<String>,
155 #[serde(default, rename = "pcDescContent")]
157 pub pc_desc_content: Option<String>,
158 #[serde(default)]
160 pub item_url: Option<String>,
161 #[serde(default)]
163 pub category_id: Option<String>,
164 #[serde(default)]
166 pub category_name: Option<String>,
167 #[serde(default)]
169 pub level_one_category_id: Option<String>,
170 #[serde(default)]
172 pub level_one_category_name: Option<String>,
173 #[serde(default)]
175 pub tkfee3: Option<String>,
176 #[serde(default)]
178 pub tag: Option<String>,
179 #[serde(default)]
181 pub date_time: Option<String>,
182 #[serde(default)]
184 pub coupon_click_url: Option<String>,
185 #[serde(default)]
187 pub shorturl: Option<String>,
188}
189
190#[derive(Debug, Clone, Deserialize)]
194pub struct JingfenGoodsResponse {
195 #[serde(default, rename = "jd_union_open_goods_jingfen_query_response")]
197 pub response: Option<JingfenQueryResponse>,
198}
199
200#[derive(Debug, Clone, Deserialize)]
202pub struct JingfenQueryResponse {
203 #[serde(default, rename = "queryResult")]
205 pub query_result: Option<JingfenQueryResult>,
206}
207
208#[derive(Debug, Clone, Deserialize)]
210pub struct JingfenQueryResult {
211 #[serde(default)]
213 pub code: Option<String>,
214 #[serde(default)]
216 pub message: Option<String>,
217 #[serde(default)]
219 pub data: Option<Vec<JingfenGoodsItem>>,
220 #[serde(default, rename = "totalCount")]
222 pub total_count: Option<i64>,
223}
224
225#[derive(Debug, Clone, Deserialize)]
227pub struct JingfenGoodsItem {
228 #[serde(default, rename = "skuId")]
230 pub sku_id: Option<i64>,
231 #[serde(default, rename = "skuName")]
233 pub sku_name: Option<String>,
234 #[serde(default, rename = "materialUrl")]
236 pub material_url: Option<String>,
237 #[serde(default, rename = "imageInfo")]
239 pub image_info: Option<JdImageInfo>,
240 #[serde(default, rename = "priceInfo")]
242 pub price_info: Option<JdPriceInfo>,
243 #[serde(default, rename = "commissionInfo")]
245 pub commission_info: Option<JdCommissionInfo>,
246 #[serde(default, rename = "couponInfo")]
248 pub coupon_info: Option<JdCouponInfo>,
249 #[serde(default, rename = "shopInfo")]
251 pub shop_info: Option<JdShopInfo>,
252 #[serde(default, rename = "categoryInfo")]
254 pub category_info: Option<JdCategoryInfo>,
255 #[serde(default, rename = "pinGouInfo")]
257 pub pingou_info: Option<JdPingouInfo>,
258 #[serde(default, rename = "inOrderCount30Days")]
260 pub in_order_count_30_days: Option<i64>,
261 #[serde(default, rename = "inOrderComm30Days")]
263 pub in_order_comm_30_days: Option<f64>,
264 #[serde(default)]
266 pub comments: Option<i64>,
267 #[serde(default, rename = "goodCommentsShare")]
269 pub good_comments_share: Option<f64>,
270 #[serde(default, rename = "brandCode")]
272 pub brand_code: Option<String>,
273 #[serde(default, rename = "brandName")]
275 pub brand_name: Option<String>,
276 #[serde(default)]
278 pub owner: Option<String>,
279 #[serde(default, rename = "isJdSale")]
281 pub is_jd_sale: Option<i32>,
282}
283
284#[derive(Debug, Clone, Deserialize)]
286pub struct JdImageInfo {
287 #[serde(default, rename = "imageList")]
289 pub image_list: Option<Vec<JdImage>>,
290 #[serde(default, rename = "whiteImage")]
292 pub white_image: Option<String>,
293}
294
295#[derive(Debug, Clone, Deserialize)]
297pub struct JdImage {
298 #[serde(default)]
300 pub url: Option<String>,
301}
302
303#[derive(Debug, Clone, Deserialize)]
305pub struct JdPriceInfo {
306 #[serde(default)]
308 pub price: Option<f64>,
309 #[serde(default, rename = "lowestPrice")]
311 pub lowest_price: Option<f64>,
312 #[serde(default, rename = "lowestCouponPrice")]
314 pub lowest_coupon_price: Option<f64>,
315 #[serde(default, rename = "historyPriceDay")]
317 pub history_price_day: Option<i32>,
318}
319
320#[derive(Debug, Clone, Deserialize)]
322pub struct JdCommissionInfo {
323 #[serde(default)]
325 pub commission: Option<f64>,
326 #[serde(default, rename = "commissionShare")]
328 pub commission_share: Option<f64>,
329 #[serde(default, rename = "couponCommission")]
331 pub coupon_commission: Option<f64>,
332 #[serde(default, rename = "plusCommissionShare")]
334 pub plus_commission_share: Option<f64>,
335}
336
337#[derive(Debug, Clone, Deserialize)]
339pub struct JdCouponInfo {
340 #[serde(default, rename = "couponList")]
342 pub coupon_list: Option<Vec<JdCoupon>>,
343}
344
345#[derive(Debug, Clone, Deserialize)]
347pub struct JdCoupon {
348 #[serde(default, rename = "bindType")]
350 pub bind_type: Option<i32>,
351 #[serde(default)]
353 pub discount: Option<f64>,
354 #[serde(default)]
356 pub link: Option<String>,
357 #[serde(default, rename = "platformType")]
359 pub platform_type: Option<i32>,
360 #[serde(default)]
362 pub quota: Option<f64>,
363 #[serde(default, rename = "getStartTime")]
365 pub get_start_time: Option<i64>,
366 #[serde(default, rename = "getEndTime")]
368 pub get_end_time: Option<i64>,
369 #[serde(default, rename = "isBest")]
371 pub is_best: Option<i32>,
372}
373
374#[derive(Debug, Clone, Deserialize)]
376pub struct JdShopInfo {
377 #[serde(default, rename = "shopId")]
379 pub shop_id: Option<i64>,
380 #[serde(default, rename = "shopName")]
382 pub shop_name: Option<String>,
383 #[serde(default, rename = "shopLevel")]
385 pub shop_level: Option<f64>,
386 #[serde(default, rename = "shopLabel")]
388 pub shop_label: Option<String>,
389}
390
391#[derive(Debug, Clone, Deserialize)]
393pub struct JdCategoryInfo {
394 #[serde(default)]
396 pub cid1: Option<i64>,
397 #[serde(default, rename = "cid1Name")]
399 pub cid1_name: Option<String>,
400 #[serde(default)]
402 pub cid2: Option<i64>,
403 #[serde(default, rename = "cid2Name")]
405 pub cid2_name: Option<String>,
406 #[serde(default)]
408 pub cid3: Option<i64>,
409 #[serde(default, rename = "cid3Name")]
411 pub cid3_name: Option<String>,
412}
413
414#[derive(Debug, Clone, Deserialize)]
416pub struct JdPingouInfo {
417 #[serde(default, rename = "pingouPrice")]
419 pub pingou_price: Option<f64>,
420 #[serde(default, rename = "pingouTmCount")]
422 pub pingou_tm_count: Option<i64>,
423 #[serde(default, rename = "pingouUrl")]
425 pub pingou_url: Option<String>,
426 #[serde(default, rename = "pingouStartTime")]
428 pub pingou_start_time: Option<i64>,
429 #[serde(default, rename = "pingouEndTime")]
431 pub pingou_end_time: Option<i64>,
432}
433
434#[derive(Debug, Clone, Deserialize)]
438pub struct JdOrderResponse {
439 #[serde(default)]
441 pub status: i32,
442 #[serde(default)]
444 pub data: Option<JdOrderData>,
445}
446
447#[derive(Debug, Clone, Deserialize)]
449pub struct JdOrderData {
450 #[serde(default)]
452 pub has_more: Option<bool>,
453 #[serde(default)]
455 pub data: Option<Vec<JdOrderInfo>>,
456}
457
458#[derive(Debug, Clone, Deserialize)]
460pub struct JdOrderInfo {
461 #[serde(default, rename = "orderId")]
463 pub order_id: Option<i64>,
464 #[serde(default, rename = "parentId")]
466 pub parent_id: Option<i64>,
467 #[serde(default, rename = "orderTime")]
469 pub order_time: Option<String>,
470 #[serde(default, rename = "finishTime")]
472 pub finish_time: Option<String>,
473 #[serde(default, rename = "modifyTime")]
475 pub modify_time: Option<String>,
476 #[serde(default, rename = "validCode")]
478 pub valid_code: Option<i32>,
479 #[serde(default, rename = "skuId")]
481 pub sku_id: Option<i64>,
482 #[serde(default, rename = "skuName")]
484 pub sku_name: Option<String>,
485 #[serde(default, rename = "skuNum")]
487 pub sku_num: Option<i32>,
488 #[serde(default)]
490 pub price: Option<f64>,
491 #[serde(default, rename = "actualCosPrice")]
493 pub actual_cos_price: Option<f64>,
494 #[serde(default, rename = "actualFee")]
496 pub actual_fee: Option<f64>,
497 #[serde(default, rename = "estimateCosPrice")]
499 pub estimate_cos_price: Option<f64>,
500 #[serde(default, rename = "estimateFee")]
502 pub estimate_fee: Option<f64>,
503 #[serde(default, rename = "commissionRate")]
505 pub commission_rate: Option<f64>,
506 #[serde(default, rename = "subUnionId")]
508 pub sub_union_id: Option<String>,
509 #[serde(default, rename = "positionId")]
511 pub position_id: Option<i64>,
512 #[serde(default, rename = "siteId")]
514 pub site_id: Option<i64>,
515 #[serde(default, rename = "unionId")]
517 pub union_id: Option<i64>,
518 #[serde(default)]
520 pub cid1: Option<i64>,
521 #[serde(default)]
523 pub cid2: Option<i64>,
524 #[serde(default)]
526 pub cid3: Option<i64>,
527 #[serde(default)]
529 pub plus: Option<i32>,
530}
531
532#[derive(Debug, Clone, Deserialize)]
536pub struct JdGoodsDetailResponse {
537 #[serde(default)]
539 pub status: i32,
540 #[serde(default)]
542 pub data: Option<Vec<JingfenGoodsItem>>,
543}
544
545#[derive(Debug, Clone, Deserialize)]
549pub struct JdHotGoodsResponse {
550 #[serde(default)]
552 pub status: i32,
553 #[serde(default)]
555 pub content: Option<Vec<JdHotGoodsItem>>,
556}
557
558#[derive(Debug, Clone, Deserialize)]
560pub struct JdHotGoodsItem {
561 #[serde(default)]
563 pub goods_id: Option<i64>,
564 #[serde(default)]
566 pub state: Option<i32>,
567 #[serde(default, rename = "J_state")]
569 pub j_state: Option<i32>,
570 #[serde(default)]
572 pub short_name: Option<String>,
573 #[serde(default)]
575 pub goods_type: Option<i32>,
576 #[serde(default)]
578 pub goods_img: Option<String>,
579 #[serde(default)]
581 pub goods_price: Option<f64>,
582 #[serde(default)]
584 pub discount_price_after: Option<f64>,
585 #[serde(default)]
587 pub goods_recommend: Option<String>,
588 #[serde(default)]
590 pub commissionshare: Option<f64>,
591 #[serde(default)]
593 pub goods_link: Option<String>,
594 #[serde(default)]
596 pub discount_price: Option<f64>,
597 #[serde(default)]
599 pub discount_link: Option<String>,
600 #[serde(default)]
602 pub today_num: Option<i32>,
603 #[serde(default)]
605 pub quota: Option<f64>,
606 #[serde(default)]
608 pub discount_start: Option<String>,
609 #[serde(default)]
611 pub discount_end: Option<String>,
612 #[serde(default)]
614 pub shop_id: Option<i64>,
615 #[serde(default)]
617 pub shop_name: Option<String>,
618 #[serde(default, rename = "inOrderCount30Days")]
620 pub in_order_count_30_days: Option<i64>,
621 #[serde(default, rename = "imageList")]
623 pub image_list: Option<String>,
624 #[serde(default)]
626 pub img_info: Option<String>,
627 #[serde(default)]
629 pub update_time: Option<String>,
630 #[serde(default)]
632 pub brand_id: Option<String>,
633 #[serde(default, rename = "brandCode")]
635 pub brand_code: Option<String>,
636 #[serde(default, rename = "brandName")]
638 pub brand_name: Option<String>,
639 #[serde(default)]
641 pub owner: Option<String>,
642 #[serde(default)]
644 pub cid1: Option<i64>,
645 #[serde(default, rename = "cid1Name")]
647 pub cid1_name: Option<String>,
648 #[serde(default)]
650 pub cid2: Option<i64>,
651 #[serde(default, rename = "cid2Name")]
653 pub cid2_name: Option<String>,
654 #[serde(default)]
656 pub cid3: Option<i64>,
657 #[serde(default, rename = "cid3Name")]
659 pub cid3_name: Option<String>,
660}
661
662#[cfg(test)]
663mod tests {
664 use super::*;
665
666 #[test]
667 fn test_jd_convert_response_deserialize() {
668 let json = r#"{
669 "status": 200,
670 "content": [{
671 "tao_id": "10025768652616",
672 "title": "测试商品",
673 "quanhou_jiage": "99.00",
674 "coupon_click_url": "https://union-click.jd.com/xxx",
675 "shorturl": "https://u.jd.com/xxx"
676 }]
677 }"#;
678
679 let response: JdConvertResponse = serde_json::from_str(json).unwrap();
680 assert_eq!(response.status, 200);
681 assert!(response.content.is_some());
682 let content = response.content.unwrap();
683 assert_eq!(content.len(), 1);
684 assert_eq!(content[0].tao_id, Some("10025768652616".to_string()));
685 assert_eq!(content[0].title, Some("测试商品".to_string()));
686 }
687
688 #[test]
689 fn test_jingfen_goods_response_deserialize() {
690 let json = r#"{
691 "jd_union_open_goods_jingfen_query_response": {
692 "queryResult": {
693 "code": "200",
694 "message": "success",
695 "data": [{
696 "skuId": 10025768652616,
697 "skuName": "测试商品",
698 "inOrderCount30Days": 100
699 }],
700 "totalCount": 1
701 }
702 }
703 }"#;
704
705 let response: JingfenGoodsResponse = serde_json::from_str(json).unwrap();
706 assert!(response.response.is_some());
707 let query_response = response.response.unwrap();
708 assert!(query_response.query_result.is_some());
709 let result = query_response.query_result.unwrap();
710 assert_eq!(result.code, Some("200".to_string()));
711 assert!(result.data.is_some());
712 let data = result.data.unwrap();
713 assert_eq!(data.len(), 1);
714 assert_eq!(data[0].sku_id, Some(10025768652616));
715 }
716
717 #[test]
718 fn test_jd_order_response_deserialize() {
719 let json = r#"{
720 "status": 200,
721 "data": {
722 "has_more": true,
723 "data": [{
724 "orderId": 123456789,
725 "skuId": 10025768652616,
726 "skuName": "测试商品",
727 "validCode": 2,
728 "price": 99.00,
729 "actualFee": 9.90
730 }]
731 }
732 }"#;
733
734 let response: JdOrderResponse = serde_json::from_str(json).unwrap();
735 assert_eq!(response.status, 200);
736 assert!(response.data.is_some());
737 let data = response.data.unwrap();
738 assert_eq!(data.has_more, Some(true));
739 assert!(data.data.is_some());
740 let orders = data.data.unwrap();
741 assert_eq!(orders.len(), 1);
742 assert_eq!(orders[0].order_id, Some(123456789));
743 }
744
745 #[test]
746 fn test_jd_hot_goods_response_deserialize() {
747 let json = r#"{
748 "status": 200,
749 "content": [{
750 "goods_id": 10025768652616,
751 "short_name": "测试商品",
752 "goods_price": 99.00,
753 "discount_price_after": 79.00,
754 "commissionshare": 20.0,
755 "shop_name": "测试店铺"
756 }]
757 }"#;
758
759 let response: JdHotGoodsResponse = serde_json::from_str(json).unwrap();
760 assert_eq!(response.status, 200);
761 assert!(response.content.is_some());
762 let content = response.content.unwrap();
763 assert_eq!(content.len(), 1);
764 assert_eq!(content[0].goods_id, Some(10025768652616));
765 assert_eq!(content[0].short_name, Some("测试商品".to_string()));
766 }
767
768 #[test]
769 fn test_response_with_missing_fields() {
770 let json = r#"{"status": 200}"#;
771
772 let response: JdConvertResponse = serde_json::from_str(json).unwrap();
773 assert_eq!(response.status, 200);
774 assert!(response.content.is_none());
775 }
776
777 #[test]
778 fn test_jd_price_info_deserialize() {
779 let json = r#"{
780 "price": 99.00,
781 "lowestPrice": 89.00,
782 "lowestCouponPrice": 79.00
783 }"#;
784
785 let price_info: JdPriceInfo = serde_json::from_str(json).unwrap();
786 assert_eq!(price_info.price, Some(99.00));
787 assert_eq!(price_info.lowest_price, Some(89.00));
788 assert_eq!(price_info.lowest_coupon_price, Some(79.00));
789 }
790
791 #[test]
792 fn test_jd_commission_info_deserialize() {
793 let json = r#"{
794 "commission": 9.90,
795 "commissionShare": 10.0
796 }"#;
797
798 let commission_info: JdCommissionInfo = serde_json::from_str(json).unwrap();
799 assert_eq!(commission_info.commission, Some(9.90));
800 assert_eq!(commission_info.commission_share, Some(10.0));
801 }
802}