1use serde::Serialize;
6
7use super::enums::{JdChainType, JdEliteId, JdOrderQueryType, JdSortField};
8use crate::common::types::SortDirection;
9
10#[derive(Debug, Clone, Serialize)]
22pub struct JdConvertRequest {
23 #[serde(rename = "materialId")]
25 pub material_id: String,
26 #[serde(rename = "unionId")]
28 pub union_id: String,
29 #[serde(skip_serializing_if = "Option::is_none")]
32 #[serde(rename = "positionId")]
33 pub position_id: Option<String>,
34 #[serde(skip_serializing_if = "Option::is_none")]
37 pub pid: Option<String>,
38 #[serde(skip_serializing_if = "Option::is_none")]
40 #[serde(rename = "couponUrl")]
41 pub coupon_url: Option<String>,
42 #[serde(skip_serializing_if = "Option::is_none")]
44 #[serde(rename = "subUnionId")]
45 pub sub_union_id: Option<String>,
46 #[serde(skip_serializing_if = "Option::is_none")]
48 #[serde(rename = "chainType")]
49 pub chain_type: Option<JdChainType>,
50 #[serde(skip_serializing_if = "Option::is_none")]
52 #[serde(rename = "giftCouponKey")]
53 pub gift_coupon_key: Option<String>,
54}
55
56impl JdConvertRequest {
57 pub fn new(material_id: impl Into<String>, union_id: impl Into<String>) -> Self {
64 Self {
65 material_id: material_id.into(),
66 union_id: union_id.into(),
67 position_id: None,
68 pid: None,
69 coupon_url: None,
70 sub_union_id: None,
71 chain_type: None,
72 gift_coupon_key: None,
73 }
74 }
75
76 pub fn position_id(mut self, position_id: impl Into<String>) -> Self {
78 self.position_id = Some(position_id.into());
79 self
80 }
81
82 pub fn pid(mut self, pid: impl Into<String>) -> Self {
84 self.pid = Some(pid.into());
85 self
86 }
87
88 pub fn coupon_url(mut self, coupon_url: impl Into<String>) -> Self {
90 self.coupon_url = Some(coupon_url.into());
91 self
92 }
93
94 pub fn sub_union_id(mut self, sub_union_id: impl Into<String>) -> Self {
96 self.sub_union_id = Some(sub_union_id.into());
97 self
98 }
99
100 pub fn chain_type(mut self, chain_type: JdChainType) -> Self {
102 self.chain_type = Some(chain_type);
103 self
104 }
105
106 pub fn gift_coupon_key(mut self, gift_coupon_key: impl Into<String>) -> Self {
108 self.gift_coupon_key = Some(gift_coupon_key.into());
109 self
110 }
111}
112
113#[derive(Debug, Clone, Serialize)]
125pub struct JingfenGoodsRequest {
126 #[serde(rename = "eliteId")]
128 pub elite_id: JdEliteId,
129 #[serde(skip_serializing_if = "Option::is_none")]
131 #[serde(rename = "pageIndex")]
132 pub page_index: Option<u32>,
133 #[serde(skip_serializing_if = "Option::is_none")]
135 #[serde(rename = "pageSize")]
136 pub page_size: Option<u32>,
137 #[serde(skip_serializing_if = "Option::is_none")]
139 #[serde(rename = "sortName")]
140 pub sort_name: Option<JdSortField>,
141 #[serde(skip_serializing_if = "Option::is_none")]
143 pub sort: Option<SortDirection>,
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub pid: Option<String>,
147 #[serde(skip_serializing_if = "Option::is_none")]
150 pub fields: Option<String>,
151 #[serde(skip_serializing_if = "Option::is_none")]
154 #[serde(rename = "forbidTypes")]
155 pub forbid_types: Option<String>,
156}
157
158impl JingfenGoodsRequest {
159 pub fn new(elite_id: JdEliteId) -> Self {
165 Self {
166 elite_id,
167 page_index: None,
168 page_size: None,
169 sort_name: None,
170 sort: None,
171 pid: None,
172 fields: None,
173 forbid_types: None,
174 }
175 }
176
177 pub fn page_index(mut self, page_index: u32) -> Self {
179 self.page_index = Some(page_index);
180 self
181 }
182
183 pub fn page_size(mut self, page_size: u32) -> Self {
185 self.page_size = Some(page_size);
186 self
187 }
188
189 pub fn sort_name(mut self, sort_name: JdSortField) -> Self {
191 self.sort_name = Some(sort_name);
192 self
193 }
194
195 pub fn sort(mut self, sort: SortDirection) -> Self {
197 self.sort = Some(sort);
198 self
199 }
200
201 pub fn pid(mut self, pid: impl Into<String>) -> Self {
203 self.pid = Some(pid.into());
204 self
205 }
206
207 pub fn fields(mut self, fields: impl Into<String>) -> Self {
209 self.fields = Some(fields.into());
210 self
211 }
212
213 pub fn forbid_types(mut self, forbid_types: impl Into<String>) -> Self {
215 self.forbid_types = Some(forbid_types.into());
216 self
217 }
218}
219
220#[derive(Debug, Clone, Serialize)]
233pub struct JdOrderQueryRequest {
234 #[serde(rename = "startTime")]
236 pub start_time: String,
237 #[serde(skip_serializing_if = "Option::is_none")]
239 #[serde(rename = "endTime")]
240 pub end_time: Option<String>,
241 #[serde(skip_serializing_if = "Option::is_none")]
243 #[serde(rename = "type")]
244 pub query_type: Option<JdOrderQueryType>,
245 #[serde(skip_serializing_if = "Option::is_none")]
247 #[serde(rename = "pageNo")]
248 pub page_no: Option<u32>,
249 #[serde(skip_serializing_if = "Option::is_none")]
251 #[serde(rename = "pageSize")]
252 pub page_size: Option<u32>,
253 #[serde(skip_serializing_if = "Option::is_none")]
255 #[serde(rename = "childUnionId")]
256 pub child_union_id: Option<String>,
257}
258
259impl JdOrderQueryRequest {
260 pub fn new(start_time: impl Into<String>) -> Self {
266 Self {
267 start_time: start_time.into(),
268 end_time: None,
269 query_type: None,
270 page_no: None,
271 page_size: None,
272 child_union_id: None,
273 }
274 }
275
276 pub fn end_time(mut self, end_time: impl Into<String>) -> Self {
278 self.end_time = Some(end_time.into());
279 self
280 }
281
282 pub fn query_type(mut self, query_type: JdOrderQueryType) -> Self {
284 self.query_type = Some(query_type);
285 self
286 }
287
288 pub fn page_no(mut self, page_no: u32) -> Self {
290 self.page_no = Some(page_no);
291 self
292 }
293
294 pub fn page_size(mut self, page_size: u32) -> Self {
296 self.page_size = Some(page_size);
297 self
298 }
299
300 pub fn child_union_id(mut self, child_union_id: impl Into<String>) -> Self {
302 self.child_union_id = Some(child_union_id.into());
303 self
304 }
305}
306
307#[derive(Debug, Clone, Serialize)]
317pub struct JdGoodsDetailRequest {
318 #[serde(rename = "skuIds")]
320 pub sku_ids: String,
321 #[serde(skip_serializing_if = "Option::is_none")]
323 pub pid: Option<String>,
324 #[serde(skip_serializing_if = "Option::is_none")]
326 pub fields: Option<String>,
327}
328
329impl JdGoodsDetailRequest {
330 pub fn new(sku_ids: impl Into<String>) -> Self {
336 Self {
337 sku_ids: sku_ids.into(),
338 pid: None,
339 fields: None,
340 }
341 }
342
343 pub fn pid(mut self, pid: impl Into<String>) -> Self {
345 self.pid = Some(pid.into());
346 self
347 }
348
349 pub fn fields(mut self, fields: impl Into<String>) -> Self {
351 self.fields = Some(fields.into());
352 self
353 }
354}
355
356#[derive(Debug, Clone, Serialize, Default)]
369pub struct JdHotGoodsRequest {
370 #[serde(skip_serializing_if = "Option::is_none")]
372 #[serde(rename = "pageIndex")]
373 pub page_index: Option<u32>,
374 #[serde(skip_serializing_if = "Option::is_none")]
376 #[serde(rename = "pageSize")]
377 pub page_size: Option<u32>,
378 #[serde(skip_serializing_if = "Option::is_none")]
380 pub goods_id: Option<String>,
381 #[serde(skip_serializing_if = "Option::is_none")]
383 pub keyword: Option<String>,
384 #[serde(skip_serializing_if = "Option::is_none")]
389 pub goods_type: Option<u32>,
390 #[serde(skip_serializing_if = "Option::is_none")]
393 pub commission_rate_start: Option<u32>,
394}
395
396impl JdHotGoodsRequest {
397 pub fn new() -> Self {
399 Self::default()
400 }
401
402 pub fn page_index(mut self, page_index: u32) -> Self {
404 self.page_index = Some(page_index);
405 self
406 }
407
408 pub fn page_size(mut self, page_size: u32) -> Self {
410 self.page_size = Some(page_size);
411 self
412 }
413
414 pub fn goods_id(mut self, goods_id: impl Into<String>) -> Self {
416 self.goods_id = Some(goods_id.into());
417 self
418 }
419
420 pub fn keyword(mut self, keyword: impl Into<String>) -> Self {
422 self.keyword = Some(keyword.into());
423 self
424 }
425
426 pub fn goods_type(mut self, goods_type: u32) -> Self {
428 self.goods_type = Some(goods_type);
429 self
430 }
431
432 pub fn commission_rate_start(mut self, commission_rate_start: u32) -> Self {
434 self.commission_rate_start = Some(commission_rate_start);
435 self
436 }
437}
438
439#[cfg(test)]
440mod tests {
441 use super::*;
442
443 #[test]
444 fn test_jd_convert_request_serialize() {
445 let request = JdConvertRequest::new("https://item.jd.com/123456.html", "1000000001");
446 let json = serde_json::to_value(&request).unwrap();
447
448 assert_eq!(json["materialId"], "https://item.jd.com/123456.html");
449 assert_eq!(json["unionId"], "1000000001");
450 assert!(json.get("positionId").is_none());
451 }
452
453 #[test]
454 fn test_jd_convert_request_with_options() {
455 let request = JdConvertRequest::new("https://item.jd.com/123456.html", "1000000001")
456 .position_id("12345")
457 .chain_type(JdChainType::Short);
458
459 let json = serde_json::to_value(&request).unwrap();
460
461 assert_eq!(json["positionId"], "12345");
462 assert_eq!(json["chainType"], 2);
463 }
464
465 #[test]
466 fn test_jingfen_goods_request_serialize() {
467 let request = JingfenGoodsRequest::new(JdEliteId::HotSale)
468 .page_index(1)
469 .page_size(20);
470
471 let json = serde_json::to_value(&request).unwrap();
472
473 assert_eq!(json["eliteId"], 22);
474 assert_eq!(json["pageIndex"], 1);
475 assert_eq!(json["pageSize"], 20);
476 }
477
478 #[test]
479 fn test_jingfen_goods_request_with_sort() {
480 let request = JingfenGoodsRequest::new(JdEliteId::HighCommission)
481 .sort_name(JdSortField::CommissionShare)
482 .sort(SortDirection::Desc);
483
484 let json = serde_json::to_value(&request).unwrap();
485
486 assert_eq!(json["eliteId"], 129);
487 assert_eq!(json["sortName"], "commissionShare");
488 assert_eq!(json["sort"], "desc");
489 }
490
491 #[test]
492 fn test_jd_order_query_request_serialize() {
493 let request = JdOrderQueryRequest::new("2024-01-01 00:00:00")
494 .end_time("2024-01-31 23:59:59")
495 .query_type(JdOrderQueryType::OrderTime)
496 .page_no(1)
497 .page_size(100);
498
499 let json = serde_json::to_value(&request).unwrap();
500
501 assert_eq!(json["startTime"], "2024-01-01 00:00:00");
502 assert_eq!(json["endTime"], "2024-01-31 23:59:59");
503 assert_eq!(json["type"], 1);
504 assert_eq!(json["pageNo"], 1);
505 assert_eq!(json["pageSize"], 100);
506 }
507
508 #[test]
509 fn test_jd_goods_detail_request_serialize() {
510 let request = JdGoodsDetailRequest::new("10025768652616,10025768652617");
511 let json = serde_json::to_value(&request).unwrap();
512
513 assert_eq!(json["skuIds"], "10025768652616,10025768652617");
514 }
515
516 #[test]
517 fn test_jd_hot_goods_request_serialize() {
518 let request = JdHotGoodsRequest::new()
519 .page_index(1)
520 .page_size(20)
521 .keyword("手机")
522 .goods_type(7);
523
524 let json = serde_json::to_value(&request).unwrap();
525
526 assert_eq!(json["pageIndex"], 1);
527 assert_eq!(json["pageSize"], 20);
528 assert_eq!(json["keyword"], "手机");
529 assert_eq!(json["goods_type"], 7);
530 }
531
532 #[test]
533 fn test_optional_fields_not_serialized() {
534 let request = JdConvertRequest::new("material", "union");
535 let json_str = serde_json::to_string(&request).unwrap();
536
537 assert!(!json_str.contains("positionId"));
538 assert!(!json_str.contains("couponUrl"));
539 assert!(!json_str.contains("chainType"));
540 }
541}