1use serde::Serialize;
6
7use super::enums::{TaobaoOrderQueryType, TaobaoOrderStatus, TaobaoSignUrlType};
8
9#[derive(Debug, Clone, Serialize)]
26pub struct ConvertByItemIdRequest {
27 pub sid: String,
29 pub pid: String,
31 pub num_iid: String,
33 #[serde(skip_serializing_if = "Option::is_none")]
35 pub relation_id: Option<String>,
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub special_id: Option<String>,
39 #[serde(skip_serializing_if = "Option::is_none")]
45 pub signurl: Option<TaobaoSignUrlType>,
46}
47
48impl ConvertByItemIdRequest {
49 pub fn new(sid: impl Into<String>, pid: impl Into<String>, num_iid: impl Into<String>) -> Self {
57 Self {
58 sid: sid.into(),
59 pid: pid.into(),
60 num_iid: num_iid.into(),
61 relation_id: None,
62 special_id: None,
63 signurl: None,
64 }
65 }
66
67 pub fn relation_id(mut self, relation_id: impl Into<String>) -> Self {
69 self.relation_id = Some(relation_id.into());
70 self
71 }
72
73 pub fn special_id(mut self, special_id: impl Into<String>) -> Self {
75 self.special_id = Some(special_id.into());
76 self
77 }
78
79 pub fn signurl(mut self, signurl: TaobaoSignUrlType) -> Self {
81 self.signurl = Some(signurl);
82 self
83 }
84}
85
86#[derive(Debug, Clone, Serialize)]
106pub struct ConvertByTklRequest {
107 pub sid: String,
109 pub pid: String,
111 pub tkl: String,
113 #[serde(skip_serializing_if = "Option::is_none")]
115 pub relation_id: Option<String>,
116 #[serde(skip_serializing_if = "Option::is_none")]
118 pub union_id: Option<String>,
119 #[serde(skip_serializing_if = "Option::is_none")]
121 pub position_id: Option<String>,
122 #[serde(skip_serializing_if = "Option::is_none")]
124 pub custom_parameters: Option<String>,
125 #[serde(skip_serializing_if = "Option::is_none")]
127 pub chan_tag: Option<String>,
128 #[serde(skip_serializing_if = "Option::is_none")]
130 pub customer_id: Option<String>,
131}
132
133impl ConvertByTklRequest {
134 pub fn new(sid: impl Into<String>, pid: impl Into<String>, tkl: impl Into<String>) -> Self {
142 Self {
143 sid: sid.into(),
144 pid: pid.into(),
145 tkl: tkl.into(),
146 relation_id: None,
147 union_id: None,
148 position_id: None,
149 custom_parameters: None,
150 chan_tag: None,
151 customer_id: None,
152 }
153 }
154
155 pub fn relation_id(mut self, relation_id: impl Into<String>) -> Self {
157 self.relation_id = Some(relation_id.into());
158 self
159 }
160
161 pub fn union_id(mut self, union_id: impl Into<String>) -> Self {
163 self.union_id = Some(union_id.into());
164 self
165 }
166
167 pub fn position_id(mut self, position_id: impl Into<String>) -> Self {
169 self.position_id = Some(position_id.into());
170 self
171 }
172
173 pub fn custom_parameters(mut self, custom_parameters: impl Into<String>) -> Self {
175 self.custom_parameters = Some(custom_parameters.into());
176 self
177 }
178
179 pub fn chan_tag(mut self, chan_tag: impl Into<String>) -> Self {
181 self.chan_tag = Some(chan_tag.into());
182 self
183 }
184
185 pub fn customer_id(mut self, customer_id: impl Into<String>) -> Self {
187 self.customer_id = Some(customer_id.into());
188 self
189 }
190}
191
192#[derive(Debug, Clone, Serialize)]
196pub struct BatchConvertRequest {
197 pub sid: String,
199 pub pid: String,
201 pub num_iid: String,
203 #[serde(skip_serializing_if = "Option::is_none")]
205 pub relation_ids: Option<String>,
206 #[serde(skip_serializing_if = "Option::is_none")]
208 pub signurl: Option<TaobaoSignUrlType>,
209}
210
211impl BatchConvertRequest {
212 pub fn new(sid: impl Into<String>, pid: impl Into<String>, num_iid: impl Into<String>) -> Self {
220 Self {
221 sid: sid.into(),
222 pid: pid.into(),
223 num_iid: num_iid.into(),
224 relation_ids: None,
225 signurl: None,
226 }
227 }
228
229 pub fn relation_ids(mut self, relation_ids: impl Into<String>) -> Self {
231 self.relation_ids = Some(relation_ids.into());
232 self
233 }
234
235 pub fn signurl(mut self, signurl: TaobaoSignUrlType) -> Self {
237 self.signurl = Some(signurl);
238 self
239 }
240}
241
242#[derive(Debug, Clone, Serialize)]
246pub struct QueryOrdersRequest {
247 pub sid: String,
249 pub start_time: String,
251 #[serde(skip_serializing_if = "Option::is_none")]
253 pub end_time: Option<String>,
254 #[serde(skip_serializing_if = "Option::is_none")]
256 pub query_type: Option<TaobaoOrderQueryType>,
257 #[serde(skip_serializing_if = "Option::is_none")]
259 pub tk_status: Option<TaobaoOrderStatus>,
260 #[serde(skip_serializing_if = "Option::is_none")]
262 pub page_no: Option<u32>,
263 #[serde(skip_serializing_if = "Option::is_none")]
265 pub page_size: Option<u32>,
266 #[serde(skip_serializing_if = "Option::is_none")]
268 pub relation_id: Option<String>,
269 #[serde(skip_serializing_if = "Option::is_none")]
271 pub special_id: Option<String>,
272}
273
274impl QueryOrdersRequest {
275 pub fn new(sid: impl Into<String>, start_time: impl Into<String>) -> Self {
282 Self {
283 sid: sid.into(),
284 start_time: start_time.into(),
285 end_time: None,
286 query_type: None,
287 tk_status: None,
288 page_no: None,
289 page_size: None,
290 relation_id: None,
291 special_id: None,
292 }
293 }
294
295 pub fn end_time(mut self, end_time: impl Into<String>) -> Self {
297 self.end_time = Some(end_time.into());
298 self
299 }
300
301 pub fn query_type(mut self, query_type: TaobaoOrderQueryType) -> Self {
303 self.query_type = Some(query_type);
304 self
305 }
306
307 pub fn tk_status(mut self, tk_status: TaobaoOrderStatus) -> Self {
309 self.tk_status = Some(tk_status);
310 self
311 }
312
313 pub fn page_no(mut self, page_no: u32) -> Self {
315 self.page_no = Some(page_no);
316 self
317 }
318
319 pub fn page_size(mut self, page_size: u32) -> Self {
321 self.page_size = Some(page_size);
322 self
323 }
324
325 pub fn relation_id(mut self, relation_id: impl Into<String>) -> Self {
327 self.relation_id = Some(relation_id.into());
328 self
329 }
330
331 pub fn special_id(mut self, special_id: impl Into<String>) -> Self {
333 self.special_id = Some(special_id.into());
334 self
335 }
336}
337
338#[derive(Debug, Clone, Serialize)]
342pub struct CreateTklRequest {
343 pub sid: String,
345 pub pid: String,
347 #[serde(skip_serializing_if = "Option::is_none")]
349 pub num_iid: Option<String>,
350 #[serde(skip_serializing_if = "Option::is_none")]
352 pub url: Option<String>,
353 #[serde(skip_serializing_if = "Option::is_none")]
355 pub text: Option<String>,
356 #[serde(skip_serializing_if = "Option::is_none")]
358 pub logo: Option<String>,
359 #[serde(skip_serializing_if = "Option::is_none")]
361 pub relation_id: Option<String>,
362}
363
364impl CreateTklRequest {
365 pub fn new(sid: impl Into<String>, pid: impl Into<String>) -> Self {
372 Self {
373 sid: sid.into(),
374 pid: pid.into(),
375 num_iid: None,
376 url: None,
377 text: None,
378 logo: None,
379 relation_id: None,
380 }
381 }
382
383 pub fn num_iid(mut self, num_iid: impl Into<String>) -> Self {
385 self.num_iid = Some(num_iid.into());
386 self
387 }
388
389 pub fn url(mut self, url: impl Into<String>) -> Self {
391 self.url = Some(url.into());
392 self
393 }
394
395 pub fn text(mut self, text: impl Into<String>) -> Self {
397 self.text = Some(text.into());
398 self
399 }
400
401 pub fn logo(mut self, logo: impl Into<String>) -> Self {
403 self.logo = Some(logo.into());
404 self
405 }
406
407 pub fn relation_id(mut self, relation_id: impl Into<String>) -> Self {
409 self.relation_id = Some(relation_id.into());
410 self
411 }
412}
413
414#[derive(Debug, Clone, Serialize)]
418pub struct ParseItemIdRequest {
419 pub content: String,
421}
422
423impl ParseItemIdRequest {
424 pub fn new(content: impl Into<String>) -> Self {
430 Self {
431 content: content.into(),
432 }
433 }
434}
435
436#[derive(Debug, Clone, Serialize)]
450pub struct SearchGoodsRequest {
451 pub sid: String,
453 pub pid: String,
455 #[serde(skip_serializing_if = "Option::is_none")]
457 pub q: Option<String>,
458 #[serde(skip_serializing_if = "Option::is_none")]
460 pub page: Option<u32>,
461 #[serde(skip_serializing_if = "Option::is_none")]
463 pub page_size: Option<u32>,
464 #[serde(skip_serializing_if = "Option::is_none")]
472 pub sort: Option<String>,
473 #[serde(skip_serializing_if = "Option::is_none")]
475 pub youquan: Option<String>,
476 #[serde(skip_serializing_if = "Option::is_none")]
478 pub tj: Option<String>,
479 #[serde(skip_serializing_if = "Option::is_none")]
481 pub haiwai: Option<String>,
482 #[serde(skip_serializing_if = "Option::is_none")]
484 pub itemloc: Option<String>,
485 #[serde(skip_serializing_if = "Option::is_none")]
487 pub start_tk_rate: Option<String>,
488 #[serde(skip_serializing_if = "Option::is_none")]
490 pub end_tk_rate: Option<String>,
491 #[serde(skip_serializing_if = "Option::is_none")]
493 pub start_price: Option<String>,
494 #[serde(skip_serializing_if = "Option::is_none")]
496 pub end_price: Option<String>,
497 #[serde(skip_serializing_if = "Option::is_none")]
499 #[serde(rename = "type")]
500 pub filter_type: Option<String>,
501 #[serde(skip_serializing_if = "Option::is_none")]
503 pub cat: Option<String>,
504}
505
506impl SearchGoodsRequest {
507 pub fn new(sid: impl Into<String>, pid: impl Into<String>) -> Self {
514 Self {
515 sid: sid.into(),
516 pid: pid.into(),
517 q: None,
518 page: None,
519 page_size: None,
520 sort: None,
521 youquan: None,
522 tj: None,
523 haiwai: None,
524 itemloc: None,
525 start_tk_rate: None,
526 end_tk_rate: None,
527 start_price: None,
528 end_price: None,
529 filter_type: None,
530 cat: None,
531 }
532 }
533
534 pub fn keyword(mut self, keyword: impl Into<String>) -> Self {
536 self.q = Some(keyword.into());
537 self
538 }
539
540 pub fn page(mut self, page: u32) -> Self {
542 self.page = Some(page);
543 self
544 }
545
546 pub fn page_size(mut self, page_size: u32) -> Self {
548 self.page_size = Some(page_size);
549 self
550 }
551
552 pub fn sort(mut self, sort: impl Into<String>) -> Self {
554 self.sort = Some(sort.into());
555 self
556 }
557
558 pub fn with_coupon(mut self) -> Self {
560 self.youquan = Some("1".to_string());
561 self
562 }
563
564 pub fn tmall_only(mut self) -> Self {
566 self.tj = Some("tmall".to_string());
567 self
568 }
569
570 pub fn overseas_only(mut self) -> Self {
572 self.haiwai = Some("1".to_string());
573 self
574 }
575
576 pub fn location(mut self, location: impl Into<String>) -> Self {
578 self.itemloc = Some(location.into());
579 self
580 }
581
582 pub fn commission_rate_range(mut self, start: u32, end: u32) -> Self {
584 self.start_tk_rate = Some(start.to_string());
585 self.end_tk_rate = Some(end.to_string());
586 self
587 }
588
589 pub fn price_range(mut self, start: f64, end: f64) -> Self {
591 self.start_price = Some(start.to_string());
592 self.end_price = Some(end.to_string());
593 self
594 }
595
596 pub fn filter(mut self, level: u32) -> Self {
598 self.filter_type = Some(level.to_string());
599 self
600 }
601
602 pub fn category(mut self, cat: impl Into<String>) -> Self {
604 self.cat = Some(cat.into());
605 self
606 }
607}
608
609#[cfg(test)]
610mod tests {
611 use super::*;
612
613 #[test]
614 fn test_convert_by_item_id_request_serialize() {
615 let request = ConvertByItemIdRequest::new("sid123", "mm_123_456_789", "987654321");
616 let json = serde_json::to_value(&request).unwrap();
617
618 assert_eq!(json["sid"], "sid123");
619 assert_eq!(json["pid"], "mm_123_456_789");
620 assert_eq!(json["num_iid"], "987654321");
621 assert!(json.get("relation_id").is_none());
622 }
623
624 #[test]
625 fn test_convert_by_item_id_request_with_options() {
626 let request = ConvertByItemIdRequest::new("sid123", "mm_123_456_789", "987654321")
627 .relation_id("rel123")
628 .signurl(TaobaoSignUrlType::WithFullDetail);
629
630 let json = serde_json::to_value(&request).unwrap();
631
632 assert_eq!(json["relation_id"], "rel123");
633 assert_eq!(json["signurl"], 5);
634 }
635
636 #[test]
637 fn test_convert_by_tkl_request_serialize() {
638 let request = ConvertByTklRequest::new("sid123", "mm_123_456_789", "淘口令内容");
639 let json = serde_json::to_value(&request).unwrap();
640
641 assert_eq!(json["sid"], "sid123");
642 assert_eq!(json["pid"], "mm_123_456_789");
643 assert_eq!(json["tkl"], "淘口令内容");
644 }
645
646 #[test]
647 fn test_batch_convert_request_serialize() {
648 let request = BatchConvertRequest::new("sid123", "mm_123_456_789", "987654321")
649 .relation_ids("rel1,rel2,rel3");
650
651 let json = serde_json::to_value(&request).unwrap();
652
653 assert_eq!(json["relation_ids"], "rel1,rel2,rel3");
654 }
655
656 #[test]
657 fn test_query_orders_request_serialize() {
658 let request = QueryOrdersRequest::new("sid123", "2024-01-01 00:00:00")
659 .end_time("2024-01-31 23:59:59")
660 .query_type(TaobaoOrderQueryType::CreateTime)
661 .page_no(1)
662 .page_size(20);
663
664 let json = serde_json::to_value(&request).unwrap();
665
666 assert_eq!(json["start_time"], "2024-01-01 00:00:00");
667 assert_eq!(json["end_time"], "2024-01-31 23:59:59");
668 assert_eq!(json["query_type"], 1);
669 assert_eq!(json["page_no"], 1);
670 assert_eq!(json["page_size"], 20);
671 }
672
673 #[test]
674 fn test_create_tkl_request_serialize() {
675 let request = CreateTklRequest::new("sid123", "mm_123_456_789")
676 .num_iid("987654321")
677 .text("推荐好物");
678
679 let json = serde_json::to_value(&request).unwrap();
680
681 assert_eq!(json["num_iid"], "987654321");
682 assert_eq!(json["text"], "推荐好物");
683 }
684
685 #[test]
686 fn test_parse_item_id_request_serialize() {
687 let request = ParseItemIdRequest::new("https://item.taobao.com/item.htm?id=123456");
688 let json = serde_json::to_value(&request).unwrap();
689
690 assert_eq!(
691 json["content"],
692 "https://item.taobao.com/item.htm?id=123456"
693 );
694 }
695
696 #[test]
697 fn test_optional_fields_not_serialized() {
698 let request = ConvertByItemIdRequest::new("sid", "pid", "num_iid");
699 let json_str = serde_json::to_string(&request).unwrap();
700
701 assert!(!json_str.contains("relation_id"));
702 assert!(!json_str.contains("special_id"));
703 assert!(!json_str.contains("signurl"));
704 }
705}