use serde::Serialize;
use super::enums::{JdChainType, JdEliteId, JdOrderQueryType, JdSortField};
use crate::common::types::SortDirection;
#[derive(Debug, Clone, Serialize)]
pub struct JdConvertRequest {
#[serde(rename = "materialId")]
pub material_id: String,
#[serde(rename = "unionId")]
pub union_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "positionId")]
pub position_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "couponUrl")]
pub coupon_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "subUnionId")]
pub sub_union_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "chainType")]
pub chain_type: Option<JdChainType>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "giftCouponKey")]
pub gift_coupon_key: Option<String>,
}
impl JdConvertRequest {
pub fn new(material_id: impl Into<String>, union_id: impl Into<String>) -> Self {
Self {
material_id: material_id.into(),
union_id: union_id.into(),
position_id: None,
pid: None,
coupon_url: None,
sub_union_id: None,
chain_type: None,
gift_coupon_key: None,
}
}
pub fn position_id(mut self, position_id: impl Into<String>) -> Self {
self.position_id = Some(position_id.into());
self
}
pub fn pid(mut self, pid: impl Into<String>) -> Self {
self.pid = Some(pid.into());
self
}
pub fn coupon_url(mut self, coupon_url: impl Into<String>) -> Self {
self.coupon_url = Some(coupon_url.into());
self
}
pub fn sub_union_id(mut self, sub_union_id: impl Into<String>) -> Self {
self.sub_union_id = Some(sub_union_id.into());
self
}
pub fn chain_type(mut self, chain_type: JdChainType) -> Self {
self.chain_type = Some(chain_type);
self
}
pub fn gift_coupon_key(mut self, gift_coupon_key: impl Into<String>) -> Self {
self.gift_coupon_key = Some(gift_coupon_key.into());
self
}
}
#[derive(Debug, Clone, Serialize)]
pub struct JingfenGoodsRequest {
#[serde(rename = "eliteId")]
pub elite_id: JdEliteId,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "pageIndex")]
pub page_index: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "pageSize")]
pub page_size: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "sortName")]
pub sort_name: Option<JdSortField>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sort: Option<SortDirection>,
#[serde(skip_serializing_if = "Option::is_none")]
pub pid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fields: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "forbidTypes")]
pub forbid_types: Option<String>,
}
impl JingfenGoodsRequest {
pub fn new(elite_id: JdEliteId) -> Self {
Self {
elite_id,
page_index: None,
page_size: None,
sort_name: None,
sort: None,
pid: None,
fields: None,
forbid_types: None,
}
}
pub fn page_index(mut self, page_index: u32) -> Self {
self.page_index = Some(page_index);
self
}
pub fn page_size(mut self, page_size: u32) -> Self {
self.page_size = Some(page_size);
self
}
pub fn sort_name(mut self, sort_name: JdSortField) -> Self {
self.sort_name = Some(sort_name);
self
}
pub fn sort(mut self, sort: SortDirection) -> Self {
self.sort = Some(sort);
self
}
pub fn pid(mut self, pid: impl Into<String>) -> Self {
self.pid = Some(pid.into());
self
}
pub fn fields(mut self, fields: impl Into<String>) -> Self {
self.fields = Some(fields.into());
self
}
pub fn forbid_types(mut self, forbid_types: impl Into<String>) -> Self {
self.forbid_types = Some(forbid_types.into());
self
}
}
#[derive(Debug, Clone, Serialize)]
pub struct JdOrderQueryRequest {
#[serde(rename = "startTime")]
pub start_time: String,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "endTime")]
pub end_time: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "type")]
pub query_type: Option<JdOrderQueryType>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "pageNo")]
pub page_no: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "pageSize")]
pub page_size: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "childUnionId")]
pub child_union_id: Option<String>,
}
impl JdOrderQueryRequest {
pub fn new(start_time: impl Into<String>) -> Self {
Self {
start_time: start_time.into(),
end_time: None,
query_type: None,
page_no: None,
page_size: None,
child_union_id: None,
}
}
pub fn end_time(mut self, end_time: impl Into<String>) -> Self {
self.end_time = Some(end_time.into());
self
}
pub fn query_type(mut self, query_type: JdOrderQueryType) -> Self {
self.query_type = Some(query_type);
self
}
pub fn page_no(mut self, page_no: u32) -> Self {
self.page_no = Some(page_no);
self
}
pub fn page_size(mut self, page_size: u32) -> Self {
self.page_size = Some(page_size);
self
}
pub fn child_union_id(mut self, child_union_id: impl Into<String>) -> Self {
self.child_union_id = Some(child_union_id.into());
self
}
}
#[derive(Debug, Clone, Serialize)]
pub struct JdGoodsDetailRequest {
#[serde(rename = "skuIds")]
pub sku_ids: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub pid: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub fields: Option<String>,
}
impl JdGoodsDetailRequest {
pub fn new(sku_ids: impl Into<String>) -> Self {
Self {
sku_ids: sku_ids.into(),
pid: None,
fields: None,
}
}
pub fn pid(mut self, pid: impl Into<String>) -> Self {
self.pid = Some(pid.into());
self
}
pub fn fields(mut self, fields: impl Into<String>) -> Self {
self.fields = Some(fields.into());
self
}
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct JdHotGoodsRequest {
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "pageIndex")]
pub page_index: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(rename = "pageSize")]
pub page_size: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub goods_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keyword: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub goods_type: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub commission_rate_start: Option<u32>,
}
impl JdHotGoodsRequest {
pub fn new() -> Self {
Self::default()
}
pub fn page_index(mut self, page_index: u32) -> Self {
self.page_index = Some(page_index);
self
}
pub fn page_size(mut self, page_size: u32) -> Self {
self.page_size = Some(page_size);
self
}
pub fn goods_id(mut self, goods_id: impl Into<String>) -> Self {
self.goods_id = Some(goods_id.into());
self
}
pub fn keyword(mut self, keyword: impl Into<String>) -> Self {
self.keyword = Some(keyword.into());
self
}
pub fn goods_type(mut self, goods_type: u32) -> Self {
self.goods_type = Some(goods_type);
self
}
pub fn commission_rate_start(mut self, commission_rate_start: u32) -> Self {
self.commission_rate_start = Some(commission_rate_start);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_jd_convert_request_serialize() {
let request = JdConvertRequest::new("https://item.jd.com/123456.html", "1000000001");
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json["materialId"], "https://item.jd.com/123456.html");
assert_eq!(json["unionId"], "1000000001");
assert!(json.get("positionId").is_none());
}
#[test]
fn test_jd_convert_request_with_options() {
let request = JdConvertRequest::new("https://item.jd.com/123456.html", "1000000001")
.position_id("12345")
.chain_type(JdChainType::Short);
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json["positionId"], "12345");
assert_eq!(json["chainType"], 2);
}
#[test]
fn test_jingfen_goods_request_serialize() {
let request = JingfenGoodsRequest::new(JdEliteId::HotSale)
.page_index(1)
.page_size(20);
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json["eliteId"], 22);
assert_eq!(json["pageIndex"], 1);
assert_eq!(json["pageSize"], 20);
}
#[test]
fn test_jingfen_goods_request_with_sort() {
let request = JingfenGoodsRequest::new(JdEliteId::HighCommission)
.sort_name(JdSortField::CommissionShare)
.sort(SortDirection::Desc);
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json["eliteId"], 129);
assert_eq!(json["sortName"], "commissionShare");
assert_eq!(json["sort"], "desc");
}
#[test]
fn test_jd_order_query_request_serialize() {
let request = JdOrderQueryRequest::new("2024-01-01 00:00:00")
.end_time("2024-01-31 23:59:59")
.query_type(JdOrderQueryType::OrderTime)
.page_no(1)
.page_size(100);
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json["startTime"], "2024-01-01 00:00:00");
assert_eq!(json["endTime"], "2024-01-31 23:59:59");
assert_eq!(json["type"], 1);
assert_eq!(json["pageNo"], 1);
assert_eq!(json["pageSize"], 100);
}
#[test]
fn test_jd_goods_detail_request_serialize() {
let request = JdGoodsDetailRequest::new("10025768652616,10025768652617");
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json["skuIds"], "10025768652616,10025768652617");
}
#[test]
fn test_jd_hot_goods_request_serialize() {
let request = JdHotGoodsRequest::new()
.page_index(1)
.page_size(20)
.keyword("手机")
.goods_type(7);
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json["pageIndex"], 1);
assert_eq!(json["pageSize"], 20);
assert_eq!(json["keyword"], "手机");
assert_eq!(json["goods_type"], 7);
}
#[test]
fn test_optional_fields_not_serialized() {
let request = JdConvertRequest::new("material", "union");
let json_str = serde_json::to_string(&request).unwrap();
assert!(!json_str.contains("positionId"));
assert!(!json_str.contains("couponUrl"));
assert!(!json_str.contains("chainType"));
}
}