use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinGoodsConvertResponse {
#[serde(default)]
pub code: i32,
#[serde(default)]
pub msg: Option<String>,
#[serde(default)]
pub sub_code: Option<String>,
#[serde(default)]
pub sub_msg: Option<String>,
#[serde(default)]
pub data: Option<DouyinGoodsConvertData>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinGoodsConvertData {
#[serde(default)]
pub data: Option<DouyinConvertResult>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinConvertResult {
#[serde(default)]
pub dy_deeplink: Option<String>,
#[serde(default)]
pub dy_password: Option<String>,
#[serde(default)]
pub dy_zlink: Option<String>,
#[serde(default)]
pub qr_code: Option<DouyinQrCode>,
#[serde(default)]
pub share_link: Option<String>,
#[serde(default)]
pub use_ins_activity: Option<String>,
#[serde(default)]
pub coupon_link: Option<DouyinCouponLink>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinQrCode {
#[serde(default)]
pub height: Option<String>,
#[serde(default)]
pub url: Option<String>,
#[serde(default)]
pub width: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinCouponLink {
#[serde(default)]
pub coupon_status: Option<String>,
#[serde(default)]
pub deeplink: Option<String>,
#[serde(default)]
pub qrcode: Option<DouyinQrCode>,
#[serde(default)]
pub share_command: Option<String>,
#[serde(default)]
pub share_link: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinLiveConvertResponse {
#[serde(default)]
pub code: i32,
#[serde(default)]
pub msg: Option<String>,
#[serde(default)]
pub sub_code: Option<String>,
#[serde(default)]
pub sub_msg: Option<String>,
#[serde(default)]
pub data: Option<DouyinLiveConvertData>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinLiveConvertData {
#[serde(default)]
pub data: Option<DouyinLiveConvertResult>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinLiveConvertResult {
#[serde(default)]
pub dy_deeplink: Option<String>,
#[serde(default)]
pub dy_password: Option<String>,
#[serde(default)]
pub dy_zlink: Option<String>,
#[serde(default)]
pub qr_code: Option<DouyinQrCode>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinActivityConvertResponse {
#[serde(default)]
pub code: i32,
#[serde(default)]
pub msg: Option<String>,
#[serde(default)]
pub sub_code: Option<String>,
#[serde(default)]
pub sub_msg: Option<String>,
#[serde(default)]
pub data: Option<DouyinActivityConvertData>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinActivityConvertData {
#[serde(default)]
pub data: Option<DouyinLiveConvertResult>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinGoodsDetailResponse {
#[serde(default)]
pub code: i32,
#[serde(default)]
pub msg: Option<String>,
#[serde(default)]
pub sub_code: Option<String>,
#[serde(default)]
pub sub_msg: Option<String>,
#[serde(default)]
pub data: Option<DouyinGoodsDetailData>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinGoodsDetailData {
#[serde(default)]
pub products: Option<Vec<DouyinProductDetail>>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinProductDetail {
#[serde(default)]
pub base_info: Option<DouyinProductBaseInfo>,
#[serde(default)]
pub promotion_info: Option<DouyinPromotionInfo>,
#[serde(default)]
pub shop_info: Option<DouyinShopInfo>,
#[serde(default)]
pub coupon_info: Option<DouyinCouponInfo>,
#[serde(default)]
pub comment_info: Option<DouyinCommentInfo>,
#[serde(default)]
pub brand_info: Option<DouyinBrandInfo>,
#[serde(default)]
pub logistics_info: Option<DouyinLogisticsInfo>,
#[serde(default)]
pub tags: Option<DouyinProductTags>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinProductBaseInfo {
#[serde(default)]
pub product_id: Option<String>,
#[serde(default)]
pub title: Option<String>,
#[serde(default)]
pub cover: Option<String>,
#[serde(default)]
pub price: Option<String>,
#[serde(default)]
pub sales: Option<String>,
#[serde(default)]
pub in_stock: Option<String>,
#[serde(default)]
pub detail_url: Option<String>,
#[serde(default)]
pub first_cid: Option<String>,
#[serde(default)]
pub second_cid: Option<String>,
#[serde(default)]
pub third_cid: Option<String>,
#[serde(default)]
pub category_id: Option<String>,
#[serde(default)]
pub category_name: Option<String>,
#[serde(default)]
pub imgs: Option<String>,
#[serde(default)]
pub success: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinPromotionInfo {
#[serde(default)]
pub cos_fee: Option<String>,
#[serde(default)]
pub cos_ratio: Option<String>,
#[serde(default)]
pub success: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinShopInfo {
#[serde(default)]
pub shop_id: Option<String>,
#[serde(default)]
pub shop_name: Option<String>,
#[serde(default)]
pub shop_total_score: Option<DouyinShopScore>,
#[serde(default)]
pub success: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinShopScore {
#[serde(default)]
pub logistics_score: Option<DouyinScoreItem>,
#[serde(default)]
pub product_score: Option<DouyinScoreItem>,
#[serde(default)]
pub service_score: Option<DouyinScoreItem>,
#[serde(default)]
pub shop_score: Option<DouyinScoreItem>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinScoreItem {
#[serde(default)]
pub level: Option<String>,
#[serde(default)]
pub score: Option<String>,
#[serde(default)]
pub text: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinCouponInfo {
#[serde(default)]
pub coupon_price: Option<String>,
#[serde(default)]
pub available_coupons: Option<Vec<DouyinCoupon>>,
#[serde(default)]
pub success: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinCoupon {
#[serde(default)]
pub coupon_type: Option<String>,
#[serde(default)]
pub discount_desc: Option<String>,
#[serde(default)]
pub type_desc: Option<String>,
#[serde(default)]
pub apply_start_time: Option<String>,
#[serde(default)]
pub apply_end_time: Option<String>,
#[serde(default)]
pub use_start_time: Option<String>,
#[serde(default)]
pub use_end_time: Option<String>,
#[serde(default)]
pub valid_period: Option<String>,
#[serde(default)]
pub validity_type: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinCommentInfo {
#[serde(default)]
pub comment_num: Option<String>,
#[serde(default)]
pub comment_score: Option<String>,
#[serde(default)]
pub success: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinBrandInfo {
#[serde(default)]
pub brand_id: Option<String>,
#[serde(default)]
pub brand_name_cn: Option<String>,
#[serde(default)]
pub brand_name_en: Option<String>,
#[serde(default)]
pub success: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinLogisticsInfo {
#[serde(default)]
pub post_free: Option<String>,
#[serde(default)]
pub text: Option<String>,
#[serde(default)]
pub success: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinProductTags {
#[serde(default)]
pub has_douin_goods_tag: Option<String>,
#[serde(default)]
pub has_shop_brand_tag: Option<String>,
#[serde(default)]
pub has_subsidy_tag: Option<String>,
#[serde(default)]
pub has_supermarket_tag: Option<String>,
#[serde(default)]
pub success: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinSearchGoodsResponse {
#[serde(default)]
pub code: i32,
#[serde(default)]
pub msg: Option<String>,
#[serde(default)]
pub sub_code: Option<String>,
#[serde(default)]
pub sub_msg: Option<String>,
#[serde(default)]
pub data: Option<DouyinSearchGoodsData>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinSearchGoodsData {
#[serde(default)]
pub products: Option<Vec<DouyinSearchProduct>>,
#[serde(default)]
pub total: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinSearchProduct {
#[serde(default)]
pub product_id: Option<String>,
#[serde(default)]
pub title: Option<String>,
#[serde(default)]
pub cover: Option<String>,
#[serde(default)]
pub price: Option<String>,
#[serde(default)]
pub coupon_price: Option<String>,
#[serde(default)]
pub sales: Option<String>,
#[serde(default)]
pub cos_fee: Option<String>,
#[serde(default)]
pub cos_ratio: Option<String>,
#[serde(default)]
pub detail_url: Option<String>,
#[serde(default)]
pub first_cid: Option<String>,
#[serde(default)]
pub second_cid: Option<String>,
#[serde(default)]
pub third_cid: Option<String>,
#[serde(default)]
pub in_stock: Option<String>,
#[serde(default)]
pub sharable: Option<String>,
#[serde(default)]
pub post_free: Option<String>,
#[serde(default)]
pub shop_id: Option<String>,
#[serde(default)]
pub shop_name: Option<String>,
#[serde(default)]
pub activity_id: Option<String>,
#[serde(default)]
pub available_coupons: Option<Vec<DouyinCoupon>>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinParseCommandResponse {
#[serde(default)]
pub code: i32,
#[serde(default)]
pub msg: Option<String>,
#[serde(default)]
pub sub_code: Option<String>,
#[serde(default)]
pub sub_msg: Option<String>,
#[serde(default)]
pub data: Option<DouyinParseCommandData>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinParseCommandData {
#[serde(default)]
pub command_info: Option<DouyinCommandInfo>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinCommandInfo {
#[serde(default)]
pub command_type: Option<String>,
#[serde(default)]
pub product_info: Option<DouyinCommandProductInfo>,
#[serde(default)]
pub live_info: Option<DouyinCommandLiveInfo>,
#[serde(default)]
pub activity_info: Option<DouyinCommandActivityInfo>,
#[serde(default)]
pub redpack_info: Option<DouyinCommandRedpackInfo>,
#[serde(default)]
pub live_appoint_info: Option<DouyinCommandLiveAppointInfo>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinCommandProductInfo {
#[serde(default)]
pub product_id: Option<String>,
#[serde(default)]
pub ins_activity_param: Option<String>,
#[serde(default)]
pub share_info: Option<DouyinShareInfo>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinCommandLiveInfo {
#[serde(default)]
pub author_buyin_id: Option<String>,
#[serde(default)]
pub product_id: Option<String>,
#[serde(default)]
pub share_info: Option<DouyinShareInfo>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinCommandActivityInfo {
#[serde(default)]
pub material_id: Option<String>,
#[serde(default)]
pub extra_params: Option<String>,
#[serde(default)]
pub share_info: Option<DouyinShareInfo>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinCommandRedpackInfo {
#[serde(default)]
pub redpack_id: Option<String>,
#[serde(default)]
pub share_info: Option<DouyinShareInfo>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinCommandLiveAppointInfo {
#[serde(default)]
pub author_buyin_id: Option<String>,
#[serde(default)]
pub live_appointment_id: Option<String>,
#[serde(default)]
pub share_info: Option<DouyinShareInfo>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinShareInfo {
#[serde(default)]
pub deeplink: Option<String>,
#[serde(default)]
pub zlink: Option<String>,
#[serde(default)]
pub share_command: Option<String>,
#[serde(default)]
pub share_link: Option<String>,
#[serde(default)]
pub qrcode: Option<DouyinQrCode>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinOrderQueryResponse {
#[serde(default)]
pub status: i32,
#[serde(default)]
pub content: Option<Vec<DouyinOrderInfo>>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinOrderInfo {
#[serde(default)]
pub code: Option<String>,
#[serde(default)]
pub account: Option<String>,
#[serde(default)]
pub appkey_ztk: Option<String>,
#[serde(default)]
pub sid: Option<String>,
#[serde(default)]
pub is_jiesuan: Option<String>,
#[serde(default)]
pub jiesuan_time: Option<String>,
#[serde(default)]
pub jiesuan_profit: Option<String>,
#[serde(default)]
pub orderid: Option<String>,
#[serde(default)]
pub paytime: Option<String>,
#[serde(default)]
pub payprice: Option<String>,
#[serde(default)]
pub profit: Option<f64>,
#[serde(default)]
pub smstitle: Option<String>,
#[serde(default)]
pub smstitle2: Option<String>,
#[serde(default)]
pub item_id: Option<String>,
#[serde(default)]
pub item_pic: Option<String>,
#[serde(default)]
pub refundprice: Option<f64>,
#[serde(default)]
pub refundtime: Option<String>,
#[serde(default)]
pub status: Option<String>,
#[serde(default)]
pub update_time: Option<String>,
#[serde(default, rename = "type")]
pub order_type: Option<String>,
#[serde(default)]
pub sid_ztk: Option<String>,
#[serde(default)]
pub customer_id_ztk: Option<String>,
#[serde(default)]
pub platform_ztk: Option<String>,
#[serde(default, rename = "actId")]
pub act_id: Option<String>,
#[serde(default)]
pub san_pingtai: Option<String>,
#[serde(default)]
pub san_pingtai_id: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinActivityListResponse {
#[serde(default)]
pub code: i32,
#[serde(default)]
pub msg: Option<String>,
#[serde(default)]
pub sub_code: Option<String>,
#[serde(default)]
pub sub_msg: Option<String>,
#[serde(default)]
pub data: Option<DouyinActivityListData>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinActivityListData {
#[serde(default)]
pub activity_material_list: Option<Vec<DouyinActivityMaterial>>,
#[serde(default)]
pub total: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DouyinActivityMaterial {
#[serde(default)]
pub activity_id: Option<String>,
#[serde(default)]
pub activity_name: Option<String>,
#[serde(default)]
pub activity_main_cover: Option<String>,
#[serde(default)]
pub activity_preview_cover: Option<String>,
#[serde(default)]
pub activity_promotion_asset: Option<String>,
#[serde(default)]
pub activity_promotion_cover: Option<String>,
#[serde(default)]
pub activity_rule: Option<String>,
#[serde(default)]
pub activity_rule_link: Option<String>,
#[serde(default)]
pub activity_status: Option<String>,
#[serde(default)]
pub activity_type: Option<String>,
#[serde(default)]
pub activity_validity_type: Option<String>,
#[serde(default)]
pub material_id: Option<String>,
#[serde(default)]
pub start_time: Option<String>,
#[serde(default)]
pub end_time: Option<String>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_goods_convert_response_deserialize() {
let json = r#"{
"code": 10000,
"msg": "success",
"data": {
"data": {
"dy_deeplink": "snssdk1128://xxx",
"dy_password": "口令内容",
"dy_zlink": "https://z.douyin.com/xxx"
}
}
}"#;
let response: DouyinGoodsConvertResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.code, 10000);
assert!(response.data.is_some());
let data = response.data.unwrap().data.unwrap();
assert_eq!(data.dy_deeplink, Some("snssdk1128://xxx".to_string()));
assert_eq!(data.dy_password, Some("口令内容".to_string()));
}
#[test]
fn test_goods_detail_response_deserialize() {
let json = r#"{
"code": 10000,
"msg": "success",
"data": {
"products": [
{
"base_info": {
"product_id": "123456",
"title": "测试商品",
"price": "1000"
},
"promotion_info": {
"cos_fee": "100",
"cos_ratio": "10"
}
}
]
}
}"#;
let response: DouyinGoodsDetailResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.code, 10000);
let products = response.data.unwrap().products.unwrap();
assert_eq!(products.len(), 1);
let base_info = products[0].base_info.as_ref().unwrap();
assert_eq!(base_info.product_id, Some("123456".to_string()));
assert_eq!(base_info.title, Some("测试商品".to_string()));
}
#[test]
fn test_search_goods_response_deserialize() {
let json = r#"{
"code": 10000,
"msg": "success",
"data": {
"products": [
{
"product_id": "123456",
"title": "测试商品",
"price": "1000",
"cos_fee": "100"
}
],
"total": "100"
}
}"#;
let response: DouyinSearchGoodsResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.code, 10000);
let data = response.data.unwrap();
assert_eq!(data.total, Some("100".to_string()));
let products = data.products.unwrap();
assert_eq!(products.len(), 1);
assert_eq!(products[0].product_id, Some("123456".to_string()));
}
#[test]
fn test_order_query_response_deserialize() {
let json = r#"{
"status": 200,
"content": [
{
"orderid": "123456789",
"paytime": "2024/01/01 12:00:00",
"payprice": "100.00",
"profit": 10.5,
"status": "8",
"san_pingtai": "抖音",
"san_pingtai_id": "9"
}
]
}"#;
let response: DouyinOrderQueryResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.status, 200);
let orders = response.content.unwrap();
assert_eq!(orders.len(), 1);
assert_eq!(orders[0].orderid, Some("123456789".to_string()));
assert_eq!(orders[0].san_pingtai_id, Some("9".to_string()));
}
#[test]
fn test_parse_command_response_deserialize() {
let json = r#"{
"code": 10000,
"msg": "success",
"data": {
"command_info": {
"command_type": "1",
"product_info": {
"product_id": "123456",
"share_info": {
"deeplink": "snssdk1128://xxx",
"share_command": "口令内容"
}
}
}
}
}"#;
let response: DouyinParseCommandResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.code, 10000);
let command_info = response.data.unwrap().command_info.unwrap();
assert_eq!(command_info.command_type, Some("1".to_string()));
let product_info = command_info.product_info.unwrap();
assert_eq!(product_info.product_id, Some("123456".to_string()));
}
#[test]
fn test_response_with_missing_fields() {
let json = r#"{"code": 10000}"#;
let response: DouyinGoodsConvertResponse = serde_json::from_str(json).unwrap();
assert_eq!(response.code, 10000);
assert!(response.data.is_none());
}
}