use std::vec;
use serde::{Serialize, Deserialize, Serializer};
use serde_json::{json, Value};
use crate::{session::SessionStore, request::{RequestType}, WechatCommonResponse, WechatMpClient, LabradorResult, LabraError, get_timestamp, TicketType, get_nonce_str, WechatCrypto, BaseInfo, AdvancedInfo};
use crate::wechat::mp::constants::{QR_CODE};
use crate::wechat::mp::method::{MpCardMethod, WechatMpMethod};
#[derive(Debug, Clone)]
pub struct WechatMpCard<'a, T: SessionStore> {
client: &'a WechatMpClient<T>,
}
#[allow(unused)]
impl<'a, T: SessionStore> WechatMpCard<'a, T> {
#[inline]
pub fn new(client: &WechatMpClient<T>) -> WechatMpCard<T> {
WechatMpCard {
client,
}
}
pub async fn get_card_api_ticket(&self) -> LabradorResult<String> {
self.get_card_api_ticket_force(false).await
}
pub async fn get_card_api_ticket_force(&self, force_refresh: bool) -> LabradorResult<String> {
self.client.get_ticket_force(TicketType::WxCard, force_refresh).await
}
pub async fn create_card_api_signature(&self, mut params: Vec<String>) -> LabradorResult<WechatMpCardApiSignature> {
let timestamp = get_timestamp() / 1000;
let noncestr = get_nonce_str();
let api_ticket = self.get_card_api_ticket_force(false).await?;
params.push(timestamp.to_string());
params.push(noncestr.to_string());
params.push(api_ticket);
params.sort();
let signature = WechatCrypto::get_sha1_sign(¶ms.join(""));
Ok(WechatMpCardApiSignature{
app_id: self.client.appid.to_string(),
card_id: "".to_string(),
card_type: "".to_string(),
location_id: "".to_string(),
code: "".to_string(),
openid: "".to_string(),
nonce_str: noncestr,
signature,
timestamp,
})
}
pub async fn decrypt_card_code(&self, encrypt_code: &str) -> LabradorResult<String> {
let req = json!({
"encrypt_code": encrypt_code
});
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::CodeDecrypt), vec![], req, RequestType::Json).await?.json::<Value>()?;
let v= WechatCommonResponse::parse::<Value>(v)?;
let code = v["code"].as_str().unwrap_or_default();
Ok(code.to_string())
}
pub async fn query_card_code(&self, card_id: &str, code: &str, check_consume: bool) -> LabradorResult<WechatMpCardResponse> {
let req = json!({
"card_id": card_id,
"code": code,
"check_consume": check_consume,
});
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::CodeGet), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardResponse>(v)
}
pub async fn consume_card_code(&self, code: &str) -> LabradorResult<WechatMpCardCodeConsumeResponse> {
self.consume_card_code_with_cardid(None, code).await
}
pub async fn consume_card_code_with_cardid(&self, card_id: Option<&str>, code: &str) -> LabradorResult<WechatMpCardCodeConsumeResponse> {
let req = json!({
"card_id": card_id,
"code": code,
});
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::CodeConsume), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardCodeConsumeResponse>(v)
}
pub async fn mark_card_code(&self, code: &str, card_id: &str, openid: &str, is_mark: bool) -> LabradorResult<WechatCommonResponse> {
let req = json!({
"card_id": card_id,
"code": code,
"openid": openid,
"is_mark": is_mark,
});
self.client.post(WechatMpMethod::Card(MpCardMethod::CodeMark), vec![], req, RequestType::Json).await?.json::<WechatCommonResponse>()
}
pub async fn get_card_detail(&self, card_id: &str) -> LabradorResult<Value> {
let req = json!({
"card_id": card_id,
});
let v= self.client.post(WechatMpMethod::Card(MpCardMethod::Get), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<Value>(v)
}
pub async fn add_test_white_list(&self, openid: &str) -> LabradorResult<WechatCommonResponse> {
let req = json!({
"openid": vec![openid],
});
self.client.post(WechatMpMethod::Card(MpCardMethod::SetWhiteList), vec![], req, RequestType::Json).await?.json::<WechatCommonResponse>()
}
pub async fn create_card(&self, req: WechatMpCardCreateRequest) -> LabradorResult<WechatMpCardCreateResponse> {
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::Create), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardCreateResponse>(v)
}
pub async fn create_qrcode_card(&self, card_id: &str, outer_str: &str) -> LabradorResult<WechatMpCardQrcodeCreateResponse> {
self.create_qrcode_card_expire(card_id, outer_str, 0).await
}
pub async fn create_qrcode_card_expire(&self, card_id: &str, outer_str: &str, expires_in: i64) -> LabradorResult<WechatMpCardQrcodeCreateResponse> {
self.create_qrcode_card_complex(card_id, outer_str, expires_in, None, None, false).await
}
pub async fn create_qrcode_card_complex(&self, card_id: &str, outer_str: &str, expires_in: i64, openid: Option<&str>, code: Option<&str>, is_unique_code: bool) -> LabradorResult<WechatMpCardQrcodeCreateResponse> {
let mut req = json!({
"action_name" : QR_CODE,
});
if expires_in > 0 {
req["expire_seconds"] = expires_in.into();
}
let action_info = json!({
"card": {
"openid": openid,
"code": code,
"is_unique_code": is_unique_code,
"card_id": card_id,
"outer_str": outer_str,
}
});
req["action_info"] = action_info;
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::CreateQrcode), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardQrcodeCreateResponse>(v)
}
pub async fn create_landing_page(&self, req: WechatMpCardLandingPageCreateRequest) -> LabradorResult<WechatMpCardLandingPageCreateResponse> {
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::CreateLandingpage), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardLandingPageCreateResponse>(v)
}
pub async fn unavailable_card_code(&self, card_id: &str, code: &str, reason: &str) -> LabradorResult<WechatCommonResponse> {
let req = json!({
"card_id": card_id,
"code": code,
"reason": reason
});
self.client.post(WechatMpMethod::Card(MpCardMethod::UnavailabeCode), vec![], req, RequestType::Json).await?.json::<WechatCommonResponse>()
}
pub async fn delete_card(&self, card_id: &str) -> LabradorResult<WechatCommonResponse> {
let req = json!({
"card_id": card_id,
});
self.client.post(WechatMpMethod::Card(MpCardMethod::Delete), vec![], req, RequestType::Json).await?.json::<WechatCommonResponse>()
}
pub async fn card_code_deposit(&self, card_id: &str, code_list: Vec<&str>) -> LabradorResult<WechatMpCardCodeDepositResponse> {
if code_list.len() == 0 || code_list.len() > 100 {
return Err(LabraError::RequestError("code数量为0或者code数量超过100个".to_string()))
}
let req = json!({
"card_id": card_id,
"code": code_list,
});
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::CodeDeposit), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardCodeDepositResponse>(v)
}
pub async fn card_code_deposit_count(&self, card_id: &str) -> LabradorResult<WechatMpCardCodeDepositCountResponse> {
let req = json!({
"card_id": card_id,
});
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::GetDepositCount), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardCodeDepositCountResponse>(v)
}
pub async fn card_code_check_code(&self, card_id: &str, code_list: Vec<&str>) -> LabradorResult<WechatMpCardCheckCodeResponse> {
if code_list.len() == 0 || code_list.len() > 100 {
return Err(LabraError::RequestError("code数量为0或者code数量超过100个".to_string()))
}
let req = json!({
"card_id": card_id,
"code": code_list,
});
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::CheckCode), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardCheckCodeResponse>(v)
}
pub async fn card_mpnews_get_html(&self, card_id: &str) -> LabradorResult<WechatMpCardMpnewsGethtmlResponse> {
let req = json!({
"card_id": card_id,
});
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::GetHtml), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardMpnewsGethtmlResponse>(v)
}
pub async fn card_modify_stock(&self, card_id: &str, change_value: i64) -> LabradorResult<WechatCommonResponse> {
let mut req = json!({
"card_id": card_id,
});
if change_value > 0 {
req["increase_stock_value"] = change_value.into();
} else {
req["reduce_stock_value"] = change_value.abs().into();
}
self.client.post(WechatMpMethod::Card(MpCardMethod::ModifyStock), vec![], req, RequestType::Json).await?.json::<WechatCommonResponse>()
}
pub async fn card_code_update(&self, card_id: &str, old_code: &str, new_code: &str) -> LabradorResult<WechatCommonResponse> {
let mut req = json!({
"card_id": card_id,
"code": old_code,
"new_code": new_code,
});
self.client.post(WechatMpMethod::Card(MpCardMethod::UpdateCode), vec![], req, RequestType::Json).await?.json::<WechatCommonResponse>()
}
pub async fn card_paycell_set(&self, card_id: &str, is_open: bool) -> LabradorResult<WechatCommonResponse> {
let mut req = json!({
"card_id": card_id,
"is_open": is_open,
});
self.client.post(WechatMpMethod::Card(MpCardMethod::SetPayCell), vec![], req, RequestType::Json).await?.json::<WechatCommonResponse>()
}
pub async fn card_self_consume_cell_set(&self, card_id: &str, is_open: bool, need_verify_cod: bool, need_remark_amount: bool) -> LabradorResult<WechatCommonResponse> {
let mut req = json!({
"card_id": card_id,
"is_open": is_open,
"need_verify_cod": need_verify_cod,
"need_remark_amount": need_remark_amount,
});
self.client.post(WechatMpMethod::Card(MpCardMethod::SetSelfConsumerCell), vec![], req, RequestType::Json).await?.json::<WechatCommonResponse>()
}
pub async fn get_user_card_list(&self, card_id: &str, openid: &str) -> LabradorResult<WechatUserCardListResponse> {
let mut req = json!({
"card_id": card_id,
"openid": openid,
});
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::GetUserCardList), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatUserCardListResponse>(v)
}
pub async fn create_submerchant(&self, req: WechatMpCardCreateSubmerchantRequest) -> LabradorResult<WechatMpCardSubmerchantResponse> {
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::SubmitSubmerchant), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardSubmerchantResponse>(v)
}
pub async fn get_cateogry(&self) -> LabradorResult<WechatMpCardCategoryResponse> {
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::GetApplyProtocol), vec![], Value::Null, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardCategoryResponse>(v)
}
pub async fn update_submerchant(&self, req: WechatMpCardCreateSubmerchantRequest) -> LabradorResult<WechatMpCardSubmerchantResponse> {
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::UpdateSubmerchant), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardSubmerchantResponse>(v)
}
pub async fn get_submerchant(&self, merchant_id: i32) -> LabradorResult<WechatMpCardSubmerchantResponse> {
let req = json!({
"merchant_id": merchant_id
});
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::GetSubmerchant), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardSubmerchantResponse>(v)
}
pub async fn get_submerchant_batch(&self, begin_id: i64, limit: i64, status: &str) -> LabradorResult<WechatMpCardSubmerchantBatchResponse> {
let req = json!({
"begin_id": begin_id,
"limit": limit,
"status": status
});
let v = self.client.post(WechatMpMethod::Card(MpCardMethod::BatchGetSubmerchant), vec![], req, RequestType::Json).await?.json::<Value>()?;
WechatCommonResponse::parse::<WechatMpCardSubmerchantBatchResponse>(v)
}
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardApiSignature {
pub app_id: String,
pub card_id: String,
pub card_type: String,
pub location_id: String,
pub code: String,
pub openid: String,
#[serde(rename="nonceStr")]
pub nonce_str: String,
pub signature: String,
pub timestamp: i64,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardResponse {
pub card: WechatMpCardInfo,
pub user_card_status: Option<String>,
pub can_consume: bool,
pub out_str: Option<String>,
pub background_pic_url: Option<String>,
pub openid: String,
pub unionid: Option<String>,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardInfo {
pub card_id: String,
pub begin_time: i64,
pub end_time: i64,
pub user_card_status: Option<String>,
pub membership_number: Option<String>,
pub code: Option<String>,
pub bonus: Option<i64>,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardCodeConsumeResponse {
pub card: CodeConsumeCard,
pub openid: String,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct CodeConsumeCard {
pub card_id: String,
}
#[allow(unused)]
pub struct WechatMpCardCreateRequest {
pub card: AbstractCardCreateRequest,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct GrouponCardCreateRequest {
pub card_type: String,
pub groupon: GrouponCard,
}
#[derive(Serialize, Deserialize)]
pub struct GrouponCard {
pub deal_detail: String,
pub base_info: BaseInfo,
pub advanced_info: AdvancedInfo,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct GiftCardCreateRequest {
pub card_type: String,
pub gift: GiftCard,
}
#[derive(Serialize, Deserialize)]
pub struct GiftCard {
pub gift: String,
pub base_info: BaseInfo,
pub advanced_info: AdvancedInfo,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct GeneralCouponCreateRequest {
pub card_type: String,
pub general_coupon: GeneralCoupon,
}
#[derive(Serialize, Deserialize)]
pub struct GeneralCoupon {
pub default_detail: String,
pub base_info: BaseInfo,
pub advanced_info: AdvancedInfo,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct DiscountCardCreateRequest {
pub card_type: String,
pub discount: DiscountCard,
}
#[derive(Serialize, Deserialize)]
pub struct DiscountCard {
pub discount: i32,
pub base_info: BaseInfo,
pub advanced_info: AdvancedInfo,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct CashCardCreateRequest {
pub card_type: String,
pub cash: CashCard,
}
#[derive(Serialize, Deserialize)]
pub struct CashCard {
pub least_cost: i32,
pub reduce_cost: i32,
pub base_info: BaseInfo,
pub advanced_info: AdvancedInfo,
}
pub enum AbstractCardCreateRequest {
Cash(CashCardCreateRequest),
Discount(DiscountCardCreateRequest),
GeneralCoupon(GeneralCouponCreateRequest),
Gift(GiftCardCreateRequest),
Groupon(GrouponCardCreateRequest),
}
impl Serialize for WechatMpCardCreateRequest {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
match &self.card {
AbstractCardCreateRequest::Cash(v) => v.serialize(serializer),
AbstractCardCreateRequest::Discount(v) => v.serialize(serializer),
AbstractCardCreateRequest::GeneralCoupon(v) => v.serialize(serializer),
AbstractCardCreateRequest::Gift(v) => v.serialize(serializer),
AbstractCardCreateRequest::Groupon(v) => v.serialize(serializer),
}
}
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardCreateResponse {
pub card_id: String,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardQrcodeCreateResponse {
pub ticket: String,
pub url: Option<String>,
pub show_qrcode_url: Option<String>,
pub expire_seconds: i64,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardLandingPageCreateRequest {
pub banner: String,
pub page_title: String,
pub scene: String,
pub can_share: bool,
pub card_list: Vec<CardLandingPage>,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct CardLandingPage {
pub card_id: String,
pub thumb_url: String,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardLandingPageCreateResponse {
pub url: String,
pub page_id: i32,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardCodeDepositResponse {
pub succ_code: Vec<String>,
pub duplicate_code: Vec<String>,
pub fail_code: Vec<String>,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardCheckCodeResponse {
pub exist_code: Vec<String>,
pub not_exist_code: Vec<String>,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardCodeDepositCountResponse {
pub count: i32,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardMpnewsGethtmlResponse {
pub content: String,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatUserCardListResponse {
pub card_list: Vec<UserCard>,
pub has_share_card: bool,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct UserCard {
pub code: String,
pub card_id: String,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardCreateSubmerchantRequest {
pub info: CreateSubmerchantRequest,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct CreateSubmerchantRequest {
pub merchant_id: Option<i32>,
pub app_id: Option<String>,
pub brand_name: String,
pub logo_url: String,
pub protocol: String,
pub end_time: i64,
pub primary_category_id: u8,
pub secondary_category_id: u8,
pub agreement_media_id: Option<String>,
pub operator_media_id: Option<String>,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardSubmerchantResponse {
pub info: SubmerchantResponse,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardSubmerchantBatchResponse {
pub info_list: Vec<SubmerchantResponse>,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct SubmerchantResponse {
pub merchant_id: Option<i32>,
pub app_id: Option<String>,
pub create_time: Option<i64>,
pub update_time: Option<i64>,
pub brand_name: String,
pub logo_url: String,
pub status: String,
pub bengin_time: Option<i64>,
pub end_time: Option<i64>,
pub primary_category_id: Option<u8>,
pub secondary_category_id: Option<u8>,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct WechatMpCardCategoryResponse {
pub category: Vec<CardCategory>,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct CardCategory {
pub primary_category_id: Option<u8>,
pub category_name: Option<String>,
pub secondary_category: Vec<SecondaryCategory>,
}
#[allow(unused)]
#[derive(Serialize, Deserialize)]
pub struct SecondaryCategory {
pub category_name: Option<String>,
pub secondary_category_id: Option<u8>,
pub can_choose_prepaid_card: Option<u8>,
pub can_choose_payment_card: Option<u8>,
pub need_qualification_stuffs: Option<Vec<String>>,
}