use std::vec;
use serde::{Serialize, Deserialize};
use serde_json::{json, Value};
use crate::{session::SessionStore, request::{RequestType}, WechatCommonResponse, WechatMpClient, LabradorResult, LabraError, get_timestamp};
use crate::wechat::mp::constants::MEMBER_CARD;
use crate::wechat::mp::method::{MpMemeberCardMethod, WechatMpMethod};
#[derive(Debug, Clone)]
pub struct WechatMpMember<'a, T: SessionStore> {
client: &'a WechatMpClient<T>,
}
#[allow(unused)]
impl<'a, T: SessionStore> WechatMpMember<'a, T> {
#[inline]
pub fn new(client: &WechatMpClient<T>) -> WechatMpMember<T> {
WechatMpMember {
client,
}
}
pub async fn create_member_card_custom<D: Serialize>(&self, req: D) -> LabradorResult<WechatMpCardCreateResponse> {
let v = serde_json::to_value(req)?;
let req = serde_json::from_value::<WechatMpMemberCardCreateRequest>(v)?;
self.create_member_card(req).await
}
pub async fn create_member_card(&self, req: WechatMpMemberCardCreateRequest) -> LabradorResult<WechatMpCardCreateResponse> {
req.valid_check()?;
let v = self.client.post(WechatMpMethod::MemberCard(MpMemeberCardMethod::Create), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardCreateResponse>(v)
}
pub async fn activate_member_card(&self, req: WechatMpMemberCardActivateRequest) -> LabradorResult<WechatCommonResponse> {
self.client.post(WechatMpMethod::MemberCard(MpMemeberCardMethod::Activate), vec![], req, RequestType::Json).await?.json::<WechatCommonResponse>()
}
pub async fn get_user_info(&self, card_id: &str, code: &str) -> LabradorResult<WechatMpMemberCardUserInfoResponse> {
let req = json!({
"card_id": card_id,
"code": code
});
let v = self.client.post(WechatMpMethod::MemberCard(MpMemeberCardMethod::GetUserInfo), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpMemberCardUserInfoResponse>(v)
}
pub async fn update_user_member_card(&self, req: WechatMpMemberCardUpdateRequest) -> LabradorResult<WechatMpMemberCardUpdateResponse> {
let v = self.client.post(WechatMpMethod::MemberCard(MpMemeberCardMethod::UpdateUser), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpMemberCardUpdateResponse>(v)
}
pub async fn set_activate_user_form(&self, req: WechatMpMemberCardActivateUserFormRequest) -> LabradorResult<WechatCommonResponse> {
self.client.post(WechatMpMethod::MemberCard(MpMemeberCardMethod::ActivateSetUser), vec![], req, RequestType::Json).await?.json::<WechatCommonResponse>()
}
pub async fn get_activate_plugin_param(&self, card_id: &str, out_str: &str) -> LabradorResult<ActivatePluginParam> {
let url = self.get_activate_plugin_url(card_id, out_str).await?;
let decode_url = urlencoding::encode(&url);
let mut params = serde_urlencoded::from_str::<ActivatePluginParam>(decode_url.as_ref())?;
params.biz = params.biz + "==";
Ok(params)
}
pub async fn get_activate_plugin_url(&self, card_id: &str, out_str: &str) -> LabradorResult<String> {
let req = json!({
"card_id": card_id,
"outer_str": out_str
});
let v = self.client.post(WechatMpMethod::MemberCard(MpMemeberCardMethod::ActivateGetUrl), vec![], req, RequestType::Json).await?.json::<Value>()?;
let v = WechatCommonResponse::parse::<Value>(v)?;
let url = v["url"].as_str().unwrap_or_default();
Ok(url.to_string())
}
pub async fn update_card_info(&self, req: MemberCardUpdateRequest) -> LabradorResult<bool> {
let v = self.client.post(WechatMpMethod::MemberCard(MpMemeberCardMethod::Update), vec![], req, RequestType::Json).await?.json::<Value>()?;
let v = WechatCommonResponse::parse::<Value>(v)?;
let send_check = v["send_check"].as_bool().unwrap_or_default();
Ok(send_check)
}
pub async fn get_activate_tempinfo(&self, activate_ticket: &str) -> LabradorResult<WechatMpMemberCardActivateTempInfoResponse> {
let v = self.client.post(WechatMpMethod::MemberCard(MpMemeberCardMethod::Update), vec![], json!({ "activate_ticket": activate_ticket }), RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpMemberCardActivateTempInfoResponse>(v)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMemberCardCreateRequest {
pub card: MemberCardCreateRequest,
}
impl WechatMpMemberCardCreateRequest {
pub fn valid_check(&self) -> LabradorResult<()> {
let req = &self.card;
if req.card_type.ne(MEMBER_CARD) {
return Err(LabraError::RequestError("卡券类型必须等于MEMBER_CARD".to_string()));
}
let member_card = &req.member_card;
if member_card.prerogative.is_empty() {
return Err(LabraError::RequestError("会员卡特权说明不能为空:prerogative".to_string()));
}
if !member_card.auto_activate && member_card.wx_activate && member_card.activate_url.is_none() {
return Err(LabraError::RequestError("会员卡激活方式为接口激活,activate_url不能为空".to_string()));
}
let base_info = &member_card.base_info;
if base_info.logo_url.is_empty() {
return Err(LabraError::RequestError("会员卡基本信息的商户logo:logo_url不能为空".to_string()));
}
if base_info.code_type.is_empty() {
return Err(LabraError::RequestError("会员卡基本信息的条码类型:code_type不能为空".to_string()));
}
if base_info.brand_name.is_empty() {
return Err(LabraError::RequestError("会员卡基本信息的商户名字:brand_name不能为空".to_string()));
}
if base_info.brand_name.len() > 12 {
return Err(LabraError::RequestError("会员卡基本信息的商户名字:brand_name长度不能大于12个汉字".to_string()));
}
if base_info.title.is_empty() {
return Err(LabraError::RequestError("会员卡基本信息的卡券名称:title不能为空".to_string()));
}
if base_info.title.len() > 9 {
return Err(LabraError::RequestError("会员卡基本信息的卡券名称:title长度不能大于9个汉字".to_string()));
}
if base_info.color.is_empty() {
return Err(LabraError::RequestError("会员卡基本信息的卡颜色:color不能为空".to_string()));
}
if CardColor::from_str(&base_info.color) == CardColor::Unknow {
return Err(LabraError::RequestError(format!("会员卡基本信息的卡颜色:{} 不支持", base_info.color)));
}
if base_info.notice.is_empty() {
return Err(LabraError::RequestError("会员卡基本信息的使用提醒:notice不能为空".to_string()));
}
if base_info.description.is_empty() {
return Err(LabraError::RequestError("会员卡基本信息的使用说明:description不能为空".to_string()));
}
let date_info = &base_info.date_info;
let date_info_type = DateInfoType::from_str(&date_info.r#type);
if date_info_type == DateInfoType::Unknow {
return Err(LabraError::RequestError(format!("会员卡基本信息的使用日期类型:{} 不合法", date_info.r#type)));
}
if date_info_type == DateInfoType::DATE_TYPE_FIX_TERM && (date_info.fixed_term.is_none() || date_info.fixed_begin_term.is_none()) {
return Err(LabraError::RequestError(format!("会员卡基本信息的使用日期为:固定日期 fixedTerm和fixedBeginTerm不能为空")));
}
if date_info_type == DateInfoType::DATE_TYPE_FIX_TIME_RANGE && (date_info.begin_timestamp.is_none() || date_info.end_timestamp.is_none()) {
return Err(LabraError::RequestError(format!("会员卡基本信息的使用日期为:固定期限 fixedTerm和fixedBeginTerm不能为空")));
}
let current_tmp = get_timestamp();
if date_info_type == DateInfoType::DATE_TYPE_FIX_TIME_RANGE && (date_info.begin_timestamp.unwrap_or_default() * 1000 < current_tmp || date_info.end_timestamp.unwrap_or_default() * 1000 < current_tmp || date_info.begin_timestamp.unwrap_or_default() > date_info.end_timestamp.unwrap_or_default()) {
return Err(LabraError::RequestError(format!("会员卡基本信息的使用日期为:固定期限,beginTimestamp和endTimestamp的值不合法,请检查")));
}
if !base_info.use_all_locations.unwrap_or_default() && base_info.location_id_list.is_none() {
return Err(LabraError::RequestError("会员卡基本信息的门店使用范围选择指定门店,门店列表:locationIdList不能为空".to_string()));
}
if let Some(advanced_info) = &member_card.advanced_info {
if let Some(busi_serv_list) = &advanced_info.business_service {
for bs in busi_serv_list {
if BusinessServiceType::from_str(bs) == BusinessServiceType::Unknow {
return Err(LabraError::RequestError(format!("会员卡高级信息的商户服务:{} 不合法", bs)));
}
}
}
}
Ok(())
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemberCardCreateRequest {
pub card_type: String,
pub member_card: MemberCard,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemberCard {
pub background_pic_url: String,
pub base_info: BaseInfo,
pub prerogative: String,
pub auto_activate: bool,
pub supply_bonus: bool,
pub bonus_url: Option<String>,
pub supply_balance: bool,
pub balance_url: Option<String>,
pub custom_field1: Option<CustomField>,
pub custom_field2: Option<CustomField>,
pub custom_field3: Option<CustomField>,
pub bonus_cleared: Option<String>,
pub bonus_rules: Option<String>,
pub balance_rules: Option<String>,
pub activate_url: Option<String>,
pub activate_app_brand_user_name: Option<String>,
pub activate_app_brand_pass: Option<String>,
pub custom_cell1: Option<CustomCell1>,
pub custom_cell2: Option<CustomCell1>,
pub custom_cell3: Option<CustomCell1>,
pub bonus_rule: Option<BonusRule>,
pub discount: Option<i64>,
pub advanced_info: Option<AdvancedInfo>,
pub wx_activate: bool,
pub wx_activate_after_submit: bool,
pub wx_activate_after_submit_url: Option<String>,
pub bonus_app_brand_user_name: Option<String>,
pub bonus_app_brand_pass: Option<String>,
pub balance_app_brand_user_name: Option<String>,
pub balance_app_brand_pass: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BaseInfo {
pub logo_url: String,
pub code_type: String,
pub pay_info: Option<PayInfo>,
pub is_pay_and_qrcode: Option<bool>,
pub brand_name: String,
pub title: String,
pub color: String,
pub notice: String,
pub description: String,
pub sku: MemberCardSkuInfo,
pub date_info: DateInfo,
pub use_custom_code: Option<bool>,
pub bind_openid: Option<bool>,
pub service_phone: Option<String>,
pub location_id_list: Option<Vec<String>>,
pub use_all_locations: Option<bool>,
pub center_title: Option<String>,
pub center_sub_title: Option<String>,
pub center_url: Option<String>,
pub custom_url_name: Option<String>,
pub custom_url: Option<String>,
pub custom_url_sub_title: Option<String>,
pub promotion_url_name: Option<String>,
pub promotion_url: Option<String>,
pub promotion_url_sub_title: Option<String>,
pub get_limit: Option<i32>,
pub use_limit: Option<i32>,
pub can_share: Option<bool>,
pub can_give_friend: Option<bool>,
pub need_push_on_view: Option<bool>,
pub custom_app_brand_user_name: Option<String>,
pub custom_app_brand_pass: Option<String>,
pub center_app_brand_user_name: Option<String>,
pub center_app_brand_pass: Option<String>,
pub promotion_app_brand_user_name: Option<String>,
pub promotion_app_brand_pass: Option<String>,
pub activate_app_brand_user_name: Option<String>,
pub activate_app_brand_pass: Option<String>,
pub status: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdvancedInfo {
pub use_condition: Option<UseCondition>,
#[serde(rename="abstract")]
pub abstracts: Option<Abstracts>,
pub text_image_list: Option<Vec<TextImageList>>,
pub business_service: Option<Vec<String>>,
pub time_limit: Option<Vec<TimeLimit>>,
pub share_friends: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TimeLimit {
#[serde(rename="type")]
pub r#type: Option<Abstracts>,
pub begin_hour: Option<i64>,
pub begin_minute: Option<i64>,
pub end_hour: Option<i64>,
pub end_minute: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TextImageList {
pub image_url: Option<String>,
pub text: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Abstracts {
#[serde(rename="abstract")]
pub abstracts: Option<String>,
pub icon_url_list: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UseCondition {
pub accept_category: Option<String>,
pub reject_category: Option<String>,
pub least_cost: Option<i64>,
pub object_use_for: Option<String>,
pub can_use_with_other_discount: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BonusRule {
pub cost_money_unit: i64,
pub increase_bonus: i64,
pub max_increase_bonus: i64,
pub init_increase_bonus: i64,
pub cost_bonus_unit: i64,
pub reduce_money: i64,
pub least_money_to_use_bonus: i64,
pub max_reduce_bonus: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CustomCell1 {
pub name: String,
pub tips: String,
pub url: String,
pub app_brand_user_name: Option<String>,
pub app_brand_pass: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CustomField {
pub name_type: String,
pub name: String,
pub url: String,
pub app_brand_user_name: Option<String>,
pub app_brand_pass: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PayInfo {
pub swipe_card: SwipeCard,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SwipeCard {
pub is_swipe_card: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemberCardSkuInfo {
pub quantity: i32,
pub total_quantity: i32,
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, PartialEq,Serialize, Deserialize)]
pub enum CardColor {
Color010,
Color020,
Color030,
Color040,
Color050,
Color060,
Color070,
Color080,
Color081,
Color082,
Color090,
Color100,
Color101,
Color102,
Unknow,
}
impl CardColor {
fn from_str(color: &str) -> Self {
match color {
"#63b359" => Self::Color010,
"#2c9f67" => Self::Color020,
"#509fc9" => Self::Color030,
"#5885cf" => Self::Color040,
"#9062c0" => Self::Color050,
"#d09a45" => Self::Color060,
"#e4b138" => Self::Color070,
"#ee903c" => Self::Color080,
"#f08500" => Self::Color081,
"#a9d92d" => Self::Color082,
"#dd6549" => Self::Color090,
"#cc463d" => Self::Color100,
"#cf3e36" => Self::Color101,
"#5E6671" => Self::Color102,
_ => {
Self::Unknow
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, PartialEq,Serialize, Deserialize)]
pub enum DateInfoType {
DATE_TYPE_PERMANENT,
DATE_TYPE_FIX_TIME_RANGE,
DATE_TYPE_FIX_TERM,
Unknow,
}
impl DateInfoType {
fn from_str(v: &str) -> Self {
match v {
"DATE_TYPE_PERMANENT" => Self::DATE_TYPE_PERMANENT,
"DATE_TYPE_FIX_TIME_RANGE" => Self::DATE_TYPE_FIX_TIME_RANGE,
"DATE_TYPE_FIX_TERM" => Self::DATE_TYPE_FIX_TERM,
_ => {
Self::Unknow
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, PartialEq,Serialize, Deserialize)]
pub enum BusinessServiceType {
BIZ_SERVICE_DELIVER,
BIZ_SERVICE_FREE_PARK,
BIZ_SERVICE_WITH_PET,
BIZ_SERVICE_FREE_WIFI,
Unknow,
}
impl BusinessServiceType {
fn from_str(v: &str) -> Self {
match v {
"BIZ_SERVICE_DELIVER" => Self::BIZ_SERVICE_DELIVER,
"BIZ_SERVICE_FREE_PARK" => Self::BIZ_SERVICE_FREE_PARK,
"BIZ_SERVICE_WITH_PET" => Self::BIZ_SERVICE_WITH_PET,
"BIZ_SERVICE_FREE_WIFI" => Self::BIZ_SERVICE_FREE_WIFI,
_ => {
Self::Unknow
}
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, PartialEq,Serialize, Deserialize)]
pub enum CardRichFieldType {
FORM_FIELD_RADIO,
FORM_FIELD_SELECT,
FORM_FIELD_CHECK_BOX,
Unknow,
}
#[allow(unused)]
impl CardRichFieldType {
fn from_str(v: &str) -> Self {
match v {
"FORM_FIELD_RADIO" => Self::FORM_FIELD_RADIO,
"FORM_FIELD_SELECT" => Self::FORM_FIELD_SELECT,
"FORM_FIELD_CHECK_BOX" => Self::FORM_FIELD_CHECK_BOX,
_ => {
Self::Unknow
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DateInfo {
#[serde(rename="type")]
pub r#type: String,
pub begin_timestamp: Option<i64>,
pub end_timestamp: Option<i64>,
pub fixed_term: Option<i64>,
pub fixed_begin_term: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpCardCreateResponse {
pub card_id: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMemberCardActivateRequest {
pub membership_number: String,
pub code: String,
pub card_id: Option<String>,
pub background_pic_url: Option<String>,
pub activate_begin_time: Option<i64>,
pub activate_end_time: Option<i64>,
pub init_bonus: Option<i64>,
pub init_bonus_record: Option<String>,
pub init_balance: Option<f64>,
pub init_custom_field_value1: Option<String>,
pub init_custom_field_value2: Option<String>,
pub init_custom_field_value3: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMemberCardUserInfoResponse {
pub openid: String,
pub nickname: Option<String>,
pub bonus: Option<i64>,
pub balance: Option<f64>,
pub sex: Option<String>,
pub user_info: Option<MemberCardUserInfo>,
pub user_card_status: Option<String>,
pub has_active: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemberCardUserInfo {
pub custom_field_list: Vec<NameValues>,
pub common_field_list: Vec<NameValues>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NameValues {
pub name: Option<String>,
pub value: Option<String>,
pub value_list: Option<Vec<String>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMemberCardUpdateRequest {
pub code: String,
pub card_id: Option<String>,
pub background_pic_url: Option<String>,
pub bonus: Option<i64>,
pub add_bonus: Option<i64>,
pub record_bonus: Option<String>,
pub balance: Option<f64>,
pub add_balance: Option<f64>,
pub record_balance: Option<String>,
pub notify_optional: Option<NotifyOptional>,
pub custom_field_value1: Option<String>,
pub custom_field_value2: Option<String>,
pub custom_field_value3: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NotifyOptional {
pub is_notify_bonus: Option<bool>,
pub is_notify_balance: Option<bool>,
pub is_notify_custom_field1: Option<bool>,
pub is_notify_custom_field2: Option<bool>,
pub is_notify_custom_field3: Option<bool>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMemberCardUpdateResponse {
pub openid: String,
pub result_bonus: Option<i64>,
pub result_balance: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMemberCardActivateUserFormRequest {
pub card_id: String,
pub service_statement: Value,
pub bind_old_card: Value,
pub required_form: MemberCardUserForm,
pub optional_form: MemberCardUserForm,
}
impl WechatMpMemberCardActivateUserFormRequest {
pub fn set_bind_old_card(&mut self, name: &str, url: &str) {
if name.is_empty() || url.is_empty() {
return;
}
self.bind_old_card["name"] = name.into();
self.bind_old_card["url"] = url.into();
}
pub fn set_service_statement(&mut self, name: &str, url: &str) {
if name.is_empty() || url.is_empty() {
return;
}
self.service_statement["name"] = name.into();
self.service_statement["url"] = url.into();
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemberCardUserForm {
pub rich_field_list: Vec<MemberCardUserFormRichField>,
pub custom_field_list: Vec<String>,
pub common_field_id_list: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemberCardUserFormRichField {
#[serde(rename="type")]
pub r#type: String,
pub name: String,
pub values: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActivatePluginParam {
pub encrypt_card_id: String,
pub outer_str: String,
pub biz: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemberCardUpdateRequest {
pub card_id: String,
pub member_card: MemberCardUpdate,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemberCardUpdate {
pub base_info: BaseInfoUpdate,
pub background_pic_url: String,
pub supply_bonus: bool,
pub bonus_cleared: Option<String>,
pub bonus_rules: Option<String>,
pub bonus_url: Option<String>,
pub balance_url: Option<String>,
pub supply_balance: bool,
pub balance_rules: Option<String>,
pub prerogative: String,
pub auto_activate: bool,
pub wx_activate: bool,
pub activate_url: Option<String>,
pub custom_field1: Option<CustomField>,
pub custom_field2: Option<CustomField>,
pub custom_field3: Option<CustomField>,
pub custom_cell1: Option<CustomCell1>,
pub custom_cell2: Option<CustomCell1>,
pub custom_cell3: Option<CustomCell1>,
pub bonus_rule: Option<BonusRule>,
pub discount: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BaseInfoUpdate {
pub title: String,
pub logo_url: String,
pub notice: String,
pub description: String,
pub service_phone: Option<String>,
pub color: String,
pub location_id_list: Option<Vec<String>>,
pub use_all_locations: Option<bool>,
pub center_title: Option<String>,
pub center_sub_title: Option<String>,
pub center_url: Option<String>,
pub custom_url_name: Option<String>,
pub custom_url: Option<String>,
pub custom_url_sub_title: Option<String>,
pub promotion_url_name: Option<String>,
pub promotion_url: Option<String>,
pub promotion_url_sub_title: Option<String>,
pub code_type: String,
pub pay_info: Option<PayInfo>,
pub is_pay_and_qrcode: Option<bool>,
pub get_limit: Option<i32>,
pub can_share: Option<bool>,
pub can_give_friend: Option<bool>,
pub date_info: DateInfo,
pub custom_app_brand_user_name: Option<String>,
pub custom_app_brand_pass: Option<String>,
pub center_app_brand_user_name: Option<String>,
pub center_app_brand_pass: Option<String>,
pub promotion_app_brand_user_name: Option<String>,
pub promotion_app_brand_pass: Option<String>,
pub activate_app_brand_user_name: Option<String>,
pub activate_app_brand_pass: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WechatMpMemberCardActivateTempInfoResponse {
pub user_info: MemberCardUserInfo,
}